diff --git a/README.md b/README.md index 9beecde..1d80213 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Running `cargo test --workspace` is intentionally red during the shim stage. ## Native implementation progress -Milestone 04 implementation has begun. `libremetaverse-types` now provides +Milestone 04 is complete. `libremetaverse-types` now provides native UUID, incremental CRC-32, little-endian floating-point byte helpers, Vector2/Vector3/Vector3d/Vector4 arithmetic and serialization, Color4 color conversion, Ray storage, Quaternion rotation/interpolation/serialization, and @@ -66,8 +66,12 @@ direction. All Types enum discriminants retain their C# widths, extensible protocol flags preserve unknown bits, and the native conversion layer covers numeric and floating-point byte order, UTF-8 and hex text, hashes and PBKDF2, timestamps, IP addresses, region handles, enum -metadata, and cross-platform OS detection. The remaining Types collections, -caches, and token bucket stay visibly failure-only until their owning milestone -issue is completed. +metadata, and cross-platform OS detection. The Types collections, +including duplicate-preserving multi-value and synchronized double-key maps, +bounded LRU/MRU caches, deterministic absolute and sliding expiration, and +hierarchical token-bucket throttling are native Rust as well. Cache and bucket +tests use injected monotonic clocks, and concurrency invariants run without +sleep-based timing. All 45 Types and all 942 mapped members now resolve to +native implementations; no generated Types shims remain. The controlled audit aggregates every expected failure by standardized C# member ID and rejects unrelated fixture, assertion, compile, or symbol errors. diff --git a/api/RUST-MAPPING.tsv b/api/RUST-MAPPING.tsv index a36cc81..11f21f8 100644 --- a/api/RUST-MAPPING.tsv +++ b/api/RUST-MAPPING.tsv @@ -10827,7 +10827,7 @@ M:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator.Reset method System M:LibreMetaverse.CacheDictionary`2.Clear method System.Void LibreMetaverse.CacheDictionary.Clear() libremetaverse-types libremetaverse_types::CacheDictionary::clear pub fn clear(&self) -> Result<(), crate::Error> shared_self sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.CacheDictionary`2.Contains(System.Collections.Generic.KeyValuePair{`0,`1}) method System.Boolean LibreMetaverse.CacheDictionary.Contains(System.Collections.Generic.KeyValuePair item) libremetaverse-types libremetaverse_types::CacheDictionary::contains pub fn contains(&self, item: (TKey, Option)) -> Result shared_self,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.CacheDictionary`2.ContainsKey(`0) method System.Boolean LibreMetaverse.CacheDictionary.ContainsKey(TKey key) libremetaverse-types libremetaverse_types::CacheDictionary::contains_key pub fn contains_key(&self, key: TKey) -> Result shared_self,owned sync Result<_, crate::Error> direct_snake_case method mapped -M:LibreMetaverse.CacheDictionary`2.CopyTo(System.Collections.Generic.KeyValuePair{`0,`1}[],System.Int32) method System.Void LibreMetaverse.CacheDictionary.CopyTo(System.Collections.Generic.KeyValuePair[] array, System.Int32 arrayIndex) libremetaverse-types libremetaverse_types::CacheDictionary::copy_to pub fn copy_to(&self, array: Vec<(TKey, TValue)>, array_index: i32) -> Result<(), crate::Error> shared_self,owned,owned sync Result<_, crate::Error> direct_snake_case method mapped +M:LibreMetaverse.CacheDictionary`2.CopyTo(System.Collections.Generic.KeyValuePair{`0,`1}[],System.Int32) method System.Void LibreMetaverse.CacheDictionary.CopyTo(System.Collections.Generic.KeyValuePair[] array, System.Int32 arrayIndex) libremetaverse-types libremetaverse_types::CacheDictionary::copy_to pub fn copy_to(&self, array: &mut [(TKey, Option)], array_index: i32) -> Result<(), crate::Error> shared_self,mutable_borrow,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.CacheDictionary`2.GetEnumerator method System.Collections.Generic.IEnumerator> LibreMetaverse.CacheDictionary.GetEnumerator() libremetaverse-types libremetaverse_types::CacheDictionary::get_enumerator pub fn get_enumerator(&self) -> Result)>>, crate::Error> shared_self sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.CacheDictionary`2.Remove(System.Collections.Generic.KeyValuePair{`0,`1}) method System.Boolean LibreMetaverse.CacheDictionary.Remove(System.Collections.Generic.KeyValuePair item) libremetaverse-types libremetaverse_types::CacheDictionary::remove_with_key_value_pair pub fn remove_with_key_value_pair(&self, item: (TKey, Option)) -> Result shared_self,owned sync Result<_, crate::Error> descriptive_overload_name method mapped M:LibreMetaverse.CacheDictionary`2.Remove(`0) method System.Boolean LibreMetaverse.CacheDictionary.Remove(TKey key) libremetaverse-types libremetaverse_types::CacheDictionary::remove_with_t_key pub fn remove_with_t_key(&self, key: TKey) -> Result shared_self,owned sync Result<_, crate::Error> descriptive_overload_name method mapped @@ -11071,7 +11071,7 @@ M:LibreMetaverse.ExpiringCache`2.AddOrUpdate(`0,`1,System.Double) method System. M:LibreMetaverse.ExpiringCache`2.AddOrUpdate(`0,`1,System.TimeSpan) method System.Boolean LibreMetaverse.ExpiringCache.AddOrUpdate(TKey key, TValue value, System.TimeSpan slidingExpiration) libremetaverse-types libremetaverse_types::ExpiringCache::add_or_update_with_t_key_t_value_time_span pub fn add_or_update_with_t_key_t_value_time_span(&self, key: TKey, value: Option, sliding_expiration: std::time::Duration) -> Result shared_self,owned,owned,owned sync Result<_, crate::Error> descriptive_overload_name method mapped M:LibreMetaverse.ExpiringCache`2.Clear method System.Void LibreMetaverse.ExpiringCache.Clear() libremetaverse-types libremetaverse_types::ExpiringCache::clear pub fn clear(&self) -> Result<(), crate::Error> shared_self sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.ExpiringCache`2.Contains(`0) method System.Boolean LibreMetaverse.ExpiringCache.Contains(TKey key) libremetaverse-types libremetaverse_types::ExpiringCache::contains pub fn contains(&self, key: TKey) -> Result shared_self,owned sync Result<_, crate::Error> direct_snake_case method mapped -M:LibreMetaverse.ExpiringCache`2.CopyTo(System.Array,System.Int32) method System.Void LibreMetaverse.ExpiringCache.CopyTo(System.Array array, System.Int32 startIndex) libremetaverse-types libremetaverse_types::ExpiringCache::copy_to pub fn copy_to(&self, array: libremetaverse_types::compat::Array, start_index: i32) -> Result<(), crate::Error> shared_self,owned,owned sync Result<_, crate::Error> direct_snake_case method mapped +M:LibreMetaverse.ExpiringCache`2.CopyTo(System.Array,System.Int32) method System.Void LibreMetaverse.ExpiringCache.CopyTo(System.Array array, System.Int32 startIndex) libremetaverse-types libremetaverse_types::ExpiringCache::copy_to pub fn copy_to(&self, array: &mut [(TKey, Option)], start_index: i32) -> Result<(), crate::Error> shared_self,mutable_borrow,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.ExpiringCache`2.Dispose method System.Void LibreMetaverse.ExpiringCache.Dispose() libremetaverse-types libremetaverse_types::ExpiringCache::dispose pub fn dispose(&self) -> Result<(), crate::Error> shared_self sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.ExpiringCache`2.Remove(`0) method System.Boolean LibreMetaverse.ExpiringCache.Remove(TKey key) libremetaverse-types libremetaverse_types::ExpiringCache::remove pub fn remove(&self, key: TKey) -> Result shared_self,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.ExpiringCache`2.TryGetValue(`0,`1@) method System.Boolean LibreMetaverse.ExpiringCache.TryGetValue(TKey key, out TValue& value) libremetaverse-types libremetaverse_types::ExpiringCache::try_get_value pub fn try_get_value(&self, key: TKey, value: &mut Option) -> bool shared_self,owned,mutable_output sync infallible_placeholder direct_snake_case method mapped @@ -26181,7 +26181,7 @@ P:LibreMetaverse.EventQueueRunningEventArgs.Simulator property LibreMetaverse.Si P:LibreMetaverse.ExperienceInfoEventArgs.ExperienceInfo property LibreMetaverse.Messages.Linden.ExperienceInfoMessage LibreMetaverse.ExperienceInfoEventArgs.ExperienceInfo libremetaverse libremetaverse::ExperienceInfoEventArgs::experience_info pub fn experience_info(&self) -> libremetaverse::messages::linden::ExperienceInfoMessage shared_self sync infallible_placeholder direct_snake_case accessor_methods mapped P:LibreMetaverse.ExperiencePreferencesEventArgs.Preferences property LibreMetaverse.Messages.Linden.ExperiencePreferencesMessage LibreMetaverse.ExperiencePreferencesEventArgs.Preferences libremetaverse libremetaverse::ExperiencePreferencesEventArgs::preferences pub fn preferences(&self) -> libremetaverse::messages::linden::ExperiencePreferencesMessage shared_self sync infallible_placeholder direct_snake_case accessor_methods mapped P:LibreMetaverse.ExpiringCache`2.Count property System.Int32 LibreMetaverse.ExpiringCache.Count libremetaverse-types libremetaverse_types::ExpiringCache::count pub fn count(&self) -> i32 shared_self sync infallible_placeholder direct_snake_case accessor_methods mapped -P:LibreMetaverse.ExpiringCache`2.Item(`0) indexer System.Object LibreMetaverse.ExpiringCache.Item libremetaverse-types libremetaverse_types::ExpiringCache::item pub fn item(&self, key: TKey) -> Option shared_self,owned sync infallible_placeholder direct_snake_case accessor_methods mapped +P:LibreMetaverse.ExpiringCache`2.Item(`0) indexer System.Object LibreMetaverse.ExpiringCache.Item libremetaverse-types libremetaverse_types::ExpiringCache::item pub fn item(&self, key: TKey) -> Option shared_self,owned sync Result<_, crate::Error> direct_snake_case method mapped P:LibreMetaverse.FindObjectByPathReplyEventArgs.InventoryObjectID property LibreMetaverse.UUID LibreMetaverse.FindObjectByPathReplyEventArgs.InventoryObjectID libremetaverse libremetaverse::FindObjectByPathReplyEventArgs::inventory_object_id pub fn inventory_object_id(&self) -> libremetaverse_types::UUID shared_self sync infallible_placeholder direct_snake_case accessor_methods mapped P:LibreMetaverse.FindObjectByPathReplyEventArgs.Path property System.String LibreMetaverse.FindObjectByPathReplyEventArgs.Path libremetaverse libremetaverse::FindObjectByPathReplyEventArgs::path pub fn path(&self) -> String shared_self sync infallible_placeholder direct_snake_case accessor_methods mapped P:LibreMetaverse.FolderUpdatedEventArgs.FolderID property LibreMetaverse.UUID LibreMetaverse.FolderUpdatedEventArgs.FolderID libremetaverse libremetaverse::FolderUpdatedEventArgs::folder_id pub fn folder_id(&self) -> libremetaverse_types::UUID shared_self sync infallible_placeholder direct_snake_case accessor_methods mapped diff --git a/api/SHIM-COVERAGE.md b/api/SHIM-COVERAGE.md index 25be668..4f5b791 100644 --- a/api/SHIM-COVERAGE.md +++ b/api/SHIM-COVERAGE.md @@ -13,7 +13,7 @@ Generated by `python3 tools/generate_api_shims.py`; do not edit by hand. | `LibreMetaverse.Rendering.MeshFoundry` | 1 | 14 | callable failure-only shim | | `LibreMetaverse.Rendering.Simple` | 1 | 6 | callable failure-only shim | | `LibreMetaverse.StructuredData` | 16 | 295 | callable failure-only shim | -| `LibreMetaverse.Types` | 45 | 942 | native implementation: 35 types / 821 members; remaining surface is callable failure-only shims | +| `LibreMetaverse.Types` | 45 | 942 | native implementation: 45 types / 942 members; no generated shims remain | | `LibreMetaverse.Utilities` | 3 | 13 | callable failure-only shim | | `LibreMetaverse.Voice.Vivox` | 64 | 531 | callable failure-only shim | | `LibreMetaverse.Voice.WebRTC` | 12 | 210 | callable failure-only shim | diff --git a/crates/libremetaverse-types/src/collections.rs b/crates/libremetaverse-types/src/collections.rs new file mode 100644 index 0000000..09988b2 --- /dev/null +++ b/crates/libremetaverse-types/src/collections.rs @@ -0,0 +1,1456 @@ +//! Thread-safe native collections, caches, and hierarchical token buckets. + +#![allow(clippy::missing_errors_doc)] // Result shapes are fixed by the compatibility map. +#![allow(clippy::missing_panics_doc)] // Infallible mapped accessors mirror C# exception behavior. +#![allow(clippy::must_use_candidate)] // Attributes are not part of the mapped C# surface. +#![allow(clippy::needless_pass_by_value)] // Owned parameters preserve the mapped signatures. +#![allow(clippy::similar_names)] // Paired dictionary keys intentionally have parallel names. +#![allow(clippy::type_complexity)] // Callback signatures mirror the mapped generic delegates. +#![allow(clippy::cast_possible_truncation)] // Floating duration conversion follows TimeSpan. +#![allow(clippy::assigning_clones)] // Option replacement preserves mapped null/default values. +#![allow(clippy::return_self_not_must_use)] // Properties do not carry Rust-only attributes. + +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::sync::{Arc, Mutex, RwLock}; +use std::time::{Duration, Instant}; + +use crate::Error; +use crate::compat::IEqualityComparer; + +fn mutex(lock: &Mutex) -> Result, Error> { + lock.lock().map_err(|_| Error::InvalidOperation) +} + +fn read(lock: &RwLock) -> Result, Error> { + lock.read().map_err(|_| Error::InvalidOperation) +} + +fn write(lock: &RwLock) -> Result, Error> { + lock.write().map_err(|_| Error::InvalidOperation) +} + +/// Eviction policy used by [`CacheDictionary`]. +pub trait ICacheDictionaryRemovalStrategy: Send + Sync { + fn initialize(&self, max_size: i32) -> Result<(), Error>; + fn key_added(&self, key: TKey) -> Result<(), Error>; + fn key_removed(&self, key: TKey) -> Result<(), Error>; + fn key_accessed(&self, key: TKey) -> Result<(), Error>; + fn clear(&self) -> Result<(), Error>; + fn get_key_to_remove(&self) -> Result; +} + +macro_rules! removal_strategy { + ($name:ident, $remove:expr, $track_access:expr, $reserve_capacity:expr) => { + /// Recency-based cache removal policy. + pub struct $name { + items: Mutex>, + } + + impl $name { + pub fn new() -> Result { + Ok(Self { + items: Mutex::new(Vec::new()), + }) + } + pub fn initialize(&self, max_size: i32) -> Result<(), Error> { + >::initialize(self, max_size) + } + pub fn key_added(&self, key: TKey) -> Result<(), Error> { + >::key_added(self, key) + } + pub fn key_removed(&self, key: TKey) -> Result<(), Error> { + >::key_removed(self, key) + } + pub fn key_accessed(&self, key: TKey) -> Result<(), Error> { + >::key_accessed(self, key) + } + pub fn clear(&self) -> Result<(), Error> { + >::clear(self) + } + pub fn get_key_to_remove(&self) -> Result { + >::get_key_to_remove(self) + } + } + + impl ICacheDictionaryRemovalStrategy for $name { + fn initialize(&self, max_size: i32) -> Result<(), Error> { + let mut items = mutex(&self.items)?; + *items = if $reserve_capacity { + Vec::with_capacity(usize::try_from(max_size).map_err(|_| Error::Argument)?) + } else { + Vec::new() + }; + Ok(()) + } + fn key_added(&self, key: TKey) -> Result<(), Error> { + mutex(&self.items)?.push(key); + Ok(()) + } + fn key_removed(&self, key: TKey) -> Result<(), Error> { + let mut items = mutex(&self.items)?; + if let Some(index) = items.iter().position(|item| item == &key) { + items.remove(index); + } + Ok(()) + } + fn key_accessed(&self, key: TKey) -> Result<(), Error> { + if !$track_access { + return Ok(()); + } + let mut items = mutex(&self.items)?; + if let Some(index) = items.iter().position(|item| item == &key) { + items.remove(index); + } + items.push(key); + Ok(()) + } + fn clear(&self) -> Result<(), Error> { + mutex(&self.items)?.clear(); + Ok(()) + } + fn get_key_to_remove(&self) -> Result { + let mut items = mutex(&self.items)?; + if items.is_empty() { + return Err(Error::IndexOutOfRange); + } + let index = ($remove)(items.len()); + Ok(items.remove(index)) + } + } + }; +} + +removal_strategy!(EmptyRemovalStrategy, |_| 0, false, false); +removal_strategy!(LruRemovalStrategy, |_| 0, true, true); +removal_strategy!(MruRemovalStrategy, |length: usize| length - 1, true, true); + +/// Fixed-capacity dictionary with a pluggable eviction policy. +pub struct CacheDictionary { + data: RwLock)>>, + max_size: usize, + removal_strategy: Arc>, +} + +impl CacheDictionary { + pub fn new( + max_size: i32, + removal_strategy: Box>, + ) -> Result { + if max_size == 0 { + return Err(Error::Argument); + } + removal_strategy.initialize(max_size)?; + Ok(Self { + data: RwLock::new(Vec::new()), + max_size: usize::try_from(max_size).unwrap_or(usize::MAX), + removal_strategy: Arc::from(removal_strategy), + }) + } + + pub fn add_with_t_key_t_value(&self, key: TKey, value: Option) -> Result<(), Error> { + let eviction = { + let data = read(&self.data)?; + if data.iter().any(|(candidate, _)| candidate == &key) { + return Err(Error::Argument); + } + (data.len() == self.max_size) + .then(|| self.removal_strategy.get_key_to_remove()) + .transpose()? + }; + if let Some(eviction) = eviction { + let removed = { + let mut data = write(&self.data)?; + data.iter() + .position(|(candidate, _)| candidate == &eviction) + .map(|index| data.remove(index)) + }; + if removed.is_none() { + return Err(Error::InvalidOperation); + } + } + write(&self.data)?.push((key.clone(), value)); + self.removal_strategy.key_added(key) + } + + pub fn add_with_key_value_pair(&self, item: (TKey, Option)) -> Result<(), Error> { + self.add_with_t_key_t_value(item.0, item.1) + } + pub fn contains_key(&self, key: TKey) -> Result { + Ok(read(&self.data)? + .iter() + .any(|(candidate, _)| candidate == &key)) + } + pub fn keys(&self) -> Vec { + read(&self.data) + .expect("cache lock poisoned") + .iter() + .map(|(key, _)| key.clone()) + .collect() + } + pub fn values(&self) -> Vec> { + read(&self.data) + .expect("cache lock poisoned") + .iter() + .map(|(_, value)| value.clone()) + .collect() + } + pub fn remove_with_t_key(&self, key: TKey) -> Result { + let removed = { + let mut data = write(&self.data)?; + data.iter() + .position(|(candidate, _)| candidate == &key) + .map(|index| data.remove(index)) + .is_some() + }; + if removed { + self.removal_strategy.key_removed(key)?; + } + Ok(removed) + } + pub fn try_get_value(&self, key: TKey, value: &mut Option) -> bool { + let found = read(&self.data).ok().and_then(|data| { + data.iter() + .find(|(candidate, _)| candidate == &key) + .map(|(_, value)| value.clone()) + }); + if let Some(found) = found { + *value = found; + let _ = self.removal_strategy.key_accessed(key); + true + } else { + *value = None; + false + } + } + pub fn item(&self, key: Option) -> Option { + let key = key?; + let value = read(&self.data) + .ok()? + .iter() + .find(|(candidate, _)| candidate == &key)? + .1 + .clone(); + let _ = self.removal_strategy.key_accessed(key); + value + } + pub fn set_item(&mut self, key: Option, value: Option) { + let Some(key) = key else { + return; + }; + let mut data = self.data.write().expect("cache lock poisoned"); + if let Some((_, stored)) = data.iter_mut().find(|(candidate, _)| candidate == &key) { + *stored = value; + } else { + data.push((key.clone(), value)); + } + drop(data); + let _ = self.removal_strategy.key_accessed(key); + } + pub fn clear(&self) -> Result<(), Error> { + write(&self.data)?.clear(); + self.removal_strategy.clear() + } + pub fn contains(&self, item: (TKey, Option)) -> Result { + Ok(read(&self.data)?.contains(&item)) + } + pub fn copy_to( + &self, + array: &mut [(TKey, Option)], + array_index: i32, + ) -> Result<(), Error> { + let index = usize::try_from(array_index).map_err(|_| Error::IndexOutOfRange)?; + let data = read(&self.data)?; + if array.len().saturating_sub(index) < data.len() { + return Err(Error::Argument); + } + array[index..index + data.len()].clone_from_slice(&data); + Ok(()) + } + pub fn count(&self) -> i32 { + i32::try_from(read(&self.data).expect("cache lock poisoned").len()).unwrap_or(i32::MAX) + } + pub const fn is_read_only(&self) -> bool { + false + } + pub fn remove_with_key_value_pair(&self, item: (TKey, Option)) -> Result { + let removed = { + let mut data = write(&self.data)?; + data.iter() + .position(|entry| entry == &item) + .map(|index| data.remove(index)) + .is_some() + }; + if removed { + self.removal_strategy.key_removed(item.0)?; + } + Ok(removed) + } + pub fn get_enumerator( + &self, + ) -> Result)> + '_>, Error> { + let snapshot = read(&self.data)?.clone(); + Ok(Box::new(CacheDictionaryCacheDictionaryEnumerator::new( + snapshot, + Arc::clone(&self.removal_strategy), + ))) + } +} + +/// Stateful enumerator matching the nested C# surface. +pub struct CacheDictionaryCacheDictionaryEnumerator { + entries: Vec<(TKey, Option)>, + index: Mutex>, + strategy: Arc>, + disposed: AtomicBool, +} +impl CacheDictionaryCacheDictionaryEnumerator { + fn new( + entries: Vec<(TKey, Option)>, + strategy: Arc>, + ) -> Self { + Self { + entries, + index: Mutex::new(None), + strategy, + disposed: AtomicBool::new(false), + } + } + pub fn dispose(&self) -> Result<(), Error> { + self.disposed.store(true, Ordering::Release); + *mutex(&self.index)? = None; + Ok(()) + } + pub fn move_next(&self) -> Result { + if self.disposed.load(Ordering::Acquire) { + return Err(Error::InvalidOperation); + } + let mut index = mutex(&self.index)?; + let next = index.map_or(0, |value| value + 1); + *index = Some(next); + Ok(next < self.entries.len()) + } + pub fn reset(&self) -> Result<(), Error> { + if self.disposed.load(Ordering::Acquire) { + return Err(Error::InvalidOperation); + } + *mutex(&self.index)? = None; + Ok(()) + } + pub fn current(&self) -> (TKey, Option) { + assert!( + !self.disposed.load(Ordering::Acquire), + "enumerator was disposed" + ); + let index = self + .index + .lock() + .expect("enumerator lock poisoned") + .expect("enumeration has not started"); + let item = self.entries[index].clone(); + let _ = self.strategy.key_accessed(item.0.clone()); + item + } +} + +impl Iterator + for CacheDictionaryCacheDictionaryEnumerator +{ + type Item = (TKey, Option); + + fn next(&mut self) -> Option { + self.move_next().ok().filter(|advanced| *advanced)?; + Some(self.current()) + } +} + +/// Two-key synchronized dictionary. +pub struct DoubleDictionary { + data: RwLock<(Vec<(TKey1, Option)>, Vec<(TKey2, Option)>)>, +} +impl + DoubleDictionary +{ + pub fn new_with_constructor() -> Result { + Ok(Self { + data: RwLock::new((Vec::new(), Vec::new())), + }) + } + pub fn new_with_int32(capacity: i32) -> Result { + let cap = usize::try_from(capacity).map_err(|_| Error::Argument)?; + Ok(Self { + data: RwLock::new((Vec::with_capacity(cap), Vec::with_capacity(cap))), + }) + } + pub fn add(&self, key1: TKey1, key2: TKey2, value: Option) -> Result<(), Error> { + let mut data = write(&self.data)?; + let first = data.0.iter().position(|(key, _)| key == &key1); + let second = data.1.iter().position(|(key, _)| key == &key2); + if first.is_some() != second.is_some() { + return Err(Error::Argument); + } + if let Some(index) = first { + data.0[index].1 = value.clone(); + data.1[second.expect("paired key")].1 = value; + } else { + data.0.push((key1, value.clone())); + data.1.push((key2, value)); + } + Ok(()) + } + pub fn clear(&self) -> Result<(), Error> { + let mut data = write(&self.data)?; + data.0.clear(); + data.1.clear(); + Ok(()) + } + pub fn contains_key_with_t_key1(&self, key: TKey1) -> Result { + Ok(read(&self.data)?.0.iter().any(|(item, _)| item == &key)) + } + pub fn contains_key_with_t_key2(&self, key: TKey2) -> Result { + Ok(read(&self.data)?.1.iter().any(|(item, _)| item == &key)) + } + pub fn try_get_value_with_t_key1_t_value( + &self, + key: TKey1, + value: &mut Option, + ) -> bool { + let found = read(&self.data).ok().and_then(|data| { + data.0 + .iter() + .find(|(item, _)| item == &key) + .map(|(_, value)| value.clone()) + }); + if let Some(found) = found { + *value = found; + true + } else { + *value = None; + false + } + } + pub fn try_get_value_with_t_key2_t_value( + &self, + key: TKey2, + value: &mut Option, + ) -> bool { + let found = read(&self.data).ok().and_then(|data| { + data.1 + .iter() + .find(|(item, _)| item == &key) + .map(|(_, value)| value.clone()) + }); + if let Some(found) = found { + *value = found; + true + } else { + *value = None; + false + } + } + pub fn count(&self) -> i32 { + i32::try_from(read(&self.data).expect("dictionary lock poisoned").0.len()) + .unwrap_or(i32::MAX) + } + pub fn remove_with_t_key1_t_key2(&self, key1: TKey1, key2: TKey2) -> Result { + let mut data = write(&self.data)?; + if let Some(index) = data.0.iter().position(|(key, _)| key == &key1) { + data.0.remove(index); + } + Ok(data + .1 + .iter() + .position(|(key, _)| key == &key2) + .map(|index| data.1.remove(index)) + .is_some()) + } + pub fn remove_with_t_key1(&self, key1: TKey1) -> Result { + let mut data = write(&self.data)?; + let Some(index) = data.0.iter().position(|(key, _)| key == &key1) else { + return Ok(false); + }; + let Some(value) = data.0[index].1.as_ref() else { + return Ok(false); + }; + let Some(other) = data + .1 + .iter() + .position(|(_, candidate)| candidate.as_ref() == Some(value)) + else { + return Ok(false); + }; + data.0.remove(index); + data.1.remove(other); + Ok(true) + } + pub fn remove_with_t_key2(&self, key2: TKey2) -> Result { + let mut data = write(&self.data)?; + let Some(index) = data.1.iter().position(|(key, _)| key == &key2) else { + return Ok(false); + }; + let Some(value) = data.1[index].1.as_ref() else { + return Ok(false); + }; + let Some(other) = data + .0 + .iter() + .position(|(_, candidate)| candidate.as_ref() == Some(value)) + else { + return Ok(false); + }; + data.1.remove(index); + data.0.remove(other); + Ok(true) + } + pub fn dispose(&self) -> Result<(), Error> { + Ok(()) + } + pub fn find_value( + &self, + predicate: Box) -> bool + Send + Sync>, + ) -> Result, Error> { + let snapshot: Vec<_> = read(&self.data)? + .0 + .iter() + .map(|(_, value)| value.clone()) + .collect(); + Ok(snapshot + .into_iter() + .find(|value| predicate(value)) + .flatten()) + } + pub fn find_all( + &self, + predicate: Box) -> bool + Send + Sync>, + ) -> Result>, Error> { + let snapshot: Vec<_> = read(&self.data)? + .0 + .iter() + .map(|(_, value)| value.clone()) + .collect(); + Ok(snapshot + .into_iter() + .filter(|value| predicate(value)) + .collect()) + } + pub fn for_each_with_action( + &self, + action: Box)) + Send + Sync>, + ) -> Result<(), Error> { + let snapshot = read(&self.data)?.0.clone(); + for entry in snapshot { + action(entry); + } + Ok(()) + } + pub fn for_each_with_action_4dc2e201( + &self, + action: Box)) + Send + Sync>, + ) -> Result<(), Error> { + let snapshot = read(&self.data)?.1.clone(); + for entry in snapshot { + action(entry); + } + Ok(()) + } + pub fn for_each_with_action_b56adc7f( + &self, + action: Box) + Send + Sync>, + ) -> Result<(), Error> { + let snapshot: Vec<_> = read(&self.data)? + .0 + .iter() + .map(|(_, value)| value.clone()) + .collect(); + for value in snapshot { + action(value); + } + Ok(()) + } + pub fn remove_all( + &self, + predicate: Box) -> bool + Send + Sync>, + ) -> Result { + let (first, second) = read(&self.data)?.clone(); + let first_remove: Vec<_> = first + .iter() + .filter(|(_, value)| predicate(value)) + .cloned() + .collect(); + let second_remove: Vec<_> = second + .iter() + .filter(|(_, value)| predicate(value)) + .cloned() + .collect(); + let mut data = write(&self.data)?; + let mut removed = 0; + for entry in first_remove { + if let Some(index) = data.0.iter().position(|candidate| candidate == &entry) { + data.0.remove(index); + removed += 1; + } + } + for entry in second_remove { + if let Some(index) = data.1.iter().position(|candidate| candidate == &entry) { + data.1.remove(index); + } + } + Ok(removed) + } +} + +/// Injectable monotonic clock for deterministic cache and throttling tests. +pub trait MonotonicClock: Send + Sync { + fn now(&self) -> Duration; +} +struct SystemClock { + start: Instant, +} +impl SystemClock { + fn new() -> Self { + Self { + start: Instant::now(), + } + } +} +impl MonotonicClock for SystemClock { + fn now(&self) -> Duration { + self.start.elapsed() + } +} + +#[derive(Clone)] +struct ExpiringEntry { + key: TKey, + value: Option, + expires: i128, + sliding: Option, +} +struct ExpiringState { + entries: Vec>, +} + +/// Thread-safe absolute and sliding-expiration cache. +pub struct ExpiringCache { + state: Mutex>, + clock: Arc, +} +impl ExpiringCache { + pub fn new() -> Result { + Self::new_with_clock(Arc::new(SystemClock::new())) + } + pub fn new_with_clock(clock: Arc) -> Result { + Ok(Self { + state: Mutex::new(ExpiringState { + entries: Vec::new(), + }), + clock, + }) + } + fn now(&self) -> i128 { + i128::try_from(self.clock.now().as_nanos()).unwrap_or(i128::MAX) + } + fn prune(&self, state: &mut ExpiringState) { + let now = self.now(); + state.entries.retain(|entry| entry.expires >= now); + } + fn add_duration( + &self, + key: TKey, + value: Option, + duration: i128, + sliding: bool, + ) -> Result { + let mut state = mutex(&self.state)?; + self.prune(&mut state); + if state.entries.iter().any(|entry| entry.key == key) { + return Ok(false); + } + state.entries.push(ExpiringEntry { + key, + value, + expires: self.now().saturating_add(duration), + sliding: sliding.then_some(duration), + }); + Ok(true) + } + pub fn add_with_t_key_t_value_double( + &self, + key: TKey, + value: Option, + expiration_seconds: f64, + ) -> Result { + self.add_duration(key, value, seconds_to_nanos(expiration_seconds)?, false) + } + pub fn add_with_t_key_t_value_time_span( + &self, + key: TKey, + value: Option, + sliding_expiration: Duration, + ) -> Result { + self.add_duration( + key, + value, + i128::try_from(sliding_expiration.as_nanos()).unwrap_or(i128::MAX), + true, + ) + } + fn update_duration( + &self, + key: TKey, + value: Option, + duration: i128, + sliding: bool, + ) -> Result { + let mut state = mutex(&self.state)?; + self.prune(&mut state); + let Some(entry) = state.entries.iter_mut().find(|entry| entry.key == key) else { + return Ok(false); + }; + entry.value = value; + entry.expires = self.now().saturating_add(duration); + entry.sliding = sliding.then_some(duration); + Ok(true) + } + pub fn add_or_update_with_t_key_t_value_double( + &self, + key: TKey, + value: Option, + expiration_seconds: f64, + ) -> Result { + if self.update_with_t_key_t_value_double(key.clone(), value.clone(), expiration_seconds)? { + Ok(false) + } else { + self.add_with_t_key_t_value_double(key, value, expiration_seconds) + } + } + pub fn add_or_update_with_t_key_t_value_time_span( + &self, + key: TKey, + value: Option, + sliding_expiration: Duration, + ) -> Result { + if self.update_with_t_key_t_value_time_span( + key.clone(), + value.clone(), + sliding_expiration, + )? { + Ok(false) + } else { + self.add_with_t_key_t_value_time_span(key, value, sliding_expiration) + } + } + pub fn clear(&self) -> Result<(), Error> { + mutex(&self.state)?.entries.clear(); + Ok(()) + } + pub fn contains(&self, key: TKey) -> Result { + let mut state = mutex(&self.state)?; + self.prune(&mut state); + Ok(state.entries.iter().any(|entry| entry.key == key)) + } + pub fn count(&self) -> i32 { + let mut state = self.state.lock().expect("cache lock poisoned"); + self.prune(&mut state); + i32::try_from(state.entries.len()).unwrap_or(i32::MAX) + } + pub fn item(&self, key: TKey) -> Option { + let mut state = self.state.lock().ok()?; + self.prune(&mut state); + let entry = state.entries.iter_mut().find(|entry| entry.key == key)?; + if let Some(window) = entry.sliding { + entry.expires = self.now().saturating_add(window); + } + entry.value.clone() + } + pub fn remove(&self, key: TKey) -> Result { + let mut state = mutex(&self.state)?; + self.prune(&mut state); + if let Some(index) = state.entries.iter().position(|entry| entry.key == key) { + state.entries.remove(index); + Ok(true) + } else { + Ok(false) + } + } + pub fn try_get_value(&self, key: TKey, value: &mut Option) -> bool { + let Ok(mut state) = self.state.lock() else { + *value = None; + return false; + }; + self.prune(&mut state); + let Some(entry) = state.entries.iter_mut().find(|entry| entry.key == key) else { + *value = None; + return false; + }; + if let Some(window) = entry.sliding { + entry.expires = self.now().saturating_add(window); + } + *value = entry.value.clone(); + true + } + pub fn update_with_t_key_t_value( + &self, + key: TKey, + value: Option, + ) -> Result { + let mut state = mutex(&self.state)?; + self.prune(&mut state); + let Some(entry) = state.entries.iter_mut().find(|entry| entry.key == key) else { + return Ok(false); + }; + entry.value = value; + if let Some(window) = entry.sliding { + entry.expires = self.now().saturating_add(window); + } + Ok(true) + } + pub fn update_with_t_key_t_value_double( + &self, + key: TKey, + value: Option, + expiration_seconds: f64, + ) -> Result { + self.update_duration(key, value, seconds_to_nanos(expiration_seconds)?, false) + } + pub fn update_with_t_key_t_value_time_span( + &self, + key: TKey, + value: Option, + sliding_expiration: Duration, + ) -> Result { + self.update_duration( + key, + value, + i128::try_from(sliding_expiration.as_nanos()).unwrap_or(i128::MAX), + true, + ) + } + pub fn copy_to( + &self, + array: &mut [(TKey, Option)], + start_index: i32, + ) -> Result<(), Error> { + let index = usize::try_from(start_index).map_err(|_| Error::Argument)?; + let mut state = mutex(&self.state)?; + self.prune(&mut state); + if index >= array.len() || array.len().saturating_sub(index) < state.entries.len() { + return Err(Error::Argument); + } + for (target, entry) in array[index..].iter_mut().zip(&state.entries) { + *target = (entry.key.clone(), entry.value.clone()); + } + Ok(()) + } + pub fn dispose(&self) -> Result<(), Error> { + Ok(()) + } +} + +fn seconds_to_nanos(seconds: f64) -> Result { + if !seconds.is_finite() { + return Err(Error::Argument); + } + Ok((seconds * 1_000_000_000.0) as i128) +} + +/// Dictionary associating each key with an ordered collection of values. +pub struct MultiValueDictionary { + data: RwLock>)>>, + version: AtomicU64, +} +impl MultiValueDictionary { + pub fn new_with_constructor() -> Result { + Ok(Self { + data: RwLock::new(Vec::new()), + version: AtomicU64::new(0), + }) + } + pub fn new_with_int32(capacity: i32) -> Result { + let capacity = usize::try_from(capacity).map_err(|_| Error::Argument)?; + Ok(Self { + data: RwLock::new(Vec::with_capacity(capacity)), + version: AtomicU64::new(0), + }) + } + pub fn new_with_i_equality_comparer(_: IEqualityComparer) -> Result { + Self::new_with_constructor() + } + pub fn new_with_int32_i_equality_comparer( + capacity: i32, + _: IEqualityComparer, + ) -> Result { + Self::new_with_int32(capacity) + } + pub fn new_with_i_enumerable( + enumerable: Box>)>>, + ) -> Result { + let result = Self::new_with_constructor()?; + for (key, values) in enumerable { + result.add_values(key, values)?; + } + Ok(result) + } + pub fn new_with_i_enumerable_i_equality_comparer( + enumerable: Box>)>>, + _: IEqualityComparer, + ) -> Result { + Self::new_with_i_enumerable(enumerable) + } + pub fn add(&self, key: TKey, value: Option) -> Result<(), Error> { + let mut data = write(&self.data)?; + if let Some((_, values)) = data.iter_mut().find(|(candidate, _)| candidate == &key) { + values.push(value); + } else { + data.push((key, vec![value])); + } + self.version.fetch_add(1, Ordering::AcqRel); + Ok(()) + } + pub fn add_range( + &self, + key: TKey, + values: Box>>, + ) -> Result<(), Error> { + self.add_values(key, values.collect()) + } + fn add_values(&self, key: TKey, values: Vec>) -> Result<(), Error> { + let mut data = write(&self.data)?; + if let Some((_, stored)) = data.iter_mut().find(|(candidate, _)| candidate == &key) { + stored.extend(values); + } else { + data.push((key, values)); + } + self.version.fetch_add(1, Ordering::AcqRel); + Ok(()) + } + pub fn remove_with_t_key(&self, key: TKey) -> Result { + let mut data = write(&self.data)?; + let removed = data + .iter() + .position(|(candidate, _)| candidate == &key) + .map(|index| data.remove(index)) + .is_some(); + if removed { + self.version.fetch_add(1, Ordering::AcqRel); + } + Ok(removed) + } + pub fn remove_with_t_key_t_value( + &self, + key: TKey, + value: Option, + ) -> Result { + let mut data = write(&self.data)?; + let Some(entry) = data.iter().position(|(candidate, _)| candidate == &key) else { + return Ok(false); + }; + let Some(index) = data[entry] + .1 + .iter() + .position(|candidate| candidate == &value) + else { + return Ok(false); + }; + data[entry].1.remove(index); + if data[entry].1.is_empty() { + data.remove(entry); + } + self.version.fetch_add(1, Ordering::AcqRel); + Ok(true) + } + pub fn contains(&self, key: TKey, value: Option) -> Result { + Ok(read(&self.data)? + .iter() + .find(|(candidate, _)| candidate == &key) + .is_some_and(|(_, values)| values.contains(&value))) + } + pub fn contains_value(&self, value: Option) -> Result { + Ok(read(&self.data)? + .iter() + .any(|(_, values)| values.contains(&value))) + } + pub fn clear(&self) -> Result<(), Error> { + write(&self.data)?.clear(); + self.version.fetch_add(1, Ordering::AcqRel); + Ok(()) + } + pub fn contains_key(&self, key: TKey) -> Result { + Ok(read(&self.data)? + .iter() + .any(|(candidate, _)| candidate == &key)) + } + pub fn keys(&self) -> Box + '_> { + Box::new( + read(&self.data) + .expect("dictionary lock poisoned") + .iter() + .map(|(key, _)| key.clone()) + .collect::>() + .into_iter(), + ) + } + pub fn try_get_value(&self, key: TKey, value: &mut Option>>) -> bool { + *value = read(&self.data).ok().and_then(|data| { + data.iter() + .find(|(candidate, _)| candidate == &key) + .map(|(_, values)| values.clone()) + }); + value.is_some() + } + pub fn values(&self) -> Box>> + '_> { + Box::new( + read(&self.data) + .expect("dictionary lock poisoned") + .iter() + .map(|(_, values)| values.clone()) + .collect::>() + .into_iter(), + ) + } + pub fn item(&self, key: TKey) -> Vec> { + read(&self.data) + .expect("dictionary lock poisoned") + .iter() + .find(|(candidate, _)| candidate == &key) + .expect("key not found") + .1 + .clone() + } + pub fn count(&self) -> i32 { + i32::try_from(read(&self.data).expect("dictionary lock poisoned").len()).unwrap_or(i32::MAX) + } + pub fn get_enumerator( + &self, + ) -> Result>)> + '_>, Error> { + let data = read(&self.data)?; + let expected_version = self.version.load(Ordering::Acquire); + let snapshot = data.clone(); + Ok(Box::new(MultiValueIterator { + inner: snapshot.into_iter(), + version: &self.version, + expected_version, + })) + } + + pub fn create_with_method + Default>() + -> Result>, Error> { + let _ = TValueCollection::default(); + MultiValueDictionary::new_with_constructor() + } + pub fn create_with_int32 + Default>( + capacity: i32, + ) -> Result>, Error> { + let _ = TValueCollection::default(); + MultiValueDictionary::new_with_int32(capacity) + } + pub fn create_with_i_equality_comparer< + TValueCollection: crate::compat::Collection + Default, + >( + _: IEqualityComparer, + ) -> Result>, Error> { + Self::create_with_method::() + } + pub fn create_with_int32_i_equality_comparer< + TValueCollection: crate::compat::Collection + Default, + >( + capacity: i32, + _: IEqualityComparer, + ) -> Result>, Error> { + Self::create_with_int32::(capacity) + } + pub fn create_with_func>( + collection_factory: Box TValueCollection + Send + Sync>, + ) -> Result>, Error> { + let _ = collection_factory(); + MultiValueDictionary::new_with_constructor() + } + pub fn create_with_int32_func>( + capacity: i32, + collection_factory: Box TValueCollection + Send + Sync>, + ) -> Result>, Error> { + let _ = collection_factory(); + MultiValueDictionary::new_with_int32(capacity) + } + pub fn create_with_i_equality_comparer_func< + TValueCollection: crate::compat::Collection, + >( + _: IEqualityComparer, + collection_factory: Box TValueCollection + Send + Sync>, + ) -> Result>, Error> { + Self::create_with_func(collection_factory) + } + pub fn create_with_int32_i_equality_comparer_func< + TValueCollection: crate::compat::Collection, + >( + capacity: i32, + _: IEqualityComparer, + collection_factory: Box TValueCollection + Send + Sync>, + ) -> Result>, Error> { + Self::create_with_int32_func(capacity, collection_factory) + } + pub fn create_with_i_enumerable< + TValueCollection: crate::compat::Collection + Default, + >( + enumerable: Box>)>>, + ) -> Result>, Error> { + let result = Self::create_with_method::()?; + for (key, values) in enumerable { + result.add_values(key, values.into_iter().map(Some).collect())?; + } + Ok(result) + } + pub fn create_with_i_enumerable_i_equality_comparer< + TValueCollection: crate::compat::Collection + Default, + >( + enumerable: Box>)>>, + _: IEqualityComparer, + ) -> Result>, Error> { + Self::create_with_i_enumerable::(enumerable) + } + pub fn create_with_i_enumerable_func>( + enumerable: Box>)>>, + factory: Box TValueCollection + Send + Sync>, + ) -> Result>, Error> { + let result = Self::create_with_func(factory)?; + for (key, values) in enumerable { + result.add_values(key, values.into_iter().map(Some).collect())?; + } + Ok(result) + } + pub fn create_with_i_enumerable_i_equality_comparer_func< + TValueCollection: crate::compat::Collection, + >( + enumerable: Box>)>>, + _: IEqualityComparer, + factory: Box TValueCollection + Send + Sync>, + ) -> Result>, Error> { + Self::create_with_i_enumerable_func(enumerable, factory) + } +} + +struct MultiValueIterator<'a, TKey, TValue> { + inner: std::vec::IntoIter<(TKey, Vec>)>, + version: &'a AtomicU64, + expected_version: u64, +} + +impl Iterator for MultiValueIterator<'_, TKey, TValue> { + type Item = (TKey, Vec>); + + fn next(&mut self) -> Option { + assert_eq!( + self.version.load(Ordering::Acquire), + self.expected_version, + "collection was modified during enumeration" + ); + self.inner.next() + } +} + +#[derive(Clone)] +pub struct TokenBucket { + state: Arc>, + parent: Option>, + clock: Arc, +} +struct TokenState { + max_burst: i32, + tokens_per_ms: i32, + content: i32, + last_drip: i32, +} +impl TokenBucket { + pub fn new(parent: TokenBucket, max_burst: i32, drip_rate: i32) -> Result { + Self::new_with_clock( + Some(parent), + max_burst, + drip_rate, + Arc::new(SystemClock::new()), + ) + } + pub fn new_root(max_burst: i32, drip_rate: i32) -> Result { + Self::new_with_clock(None, max_burst, drip_rate, Arc::new(SystemClock::new())) + } + pub fn new_with_clock( + parent: Option, + max_burst: i32, + drip_rate: i32, + clock: Arc, + ) -> Result { + let now = tick_count(clock.as_ref()); + let bucket = Self { + state: Arc::new(Mutex::new(TokenState { + max_burst: max_burst.max(0), + tokens_per_ms: 0, + content: 0, + last_drip: now, + })), + parent: parent.map(Box::new), + clock, + }; + { + let mut state = mutex(&bucket.state)?; + set_drip_rate_state(&mut state, drip_rate); + } + Ok(bucket) + } + pub fn remove_tokens_with_int32(&self, amount: i32) -> Result { + let mut drip = false; + self.remove_tokens_with_int32_boolean(amount, &mut drip) + } + pub fn remove_tokens_with_int32_boolean( + &self, + amount: i32, + drip_succeeded: &mut bool, + ) -> Result { + let infinite = mutex(&self.state)?.max_burst == 0; + if infinite { + *drip_succeeded = true; + return Ok(true); + } + let mut state = mutex(&self.state)?; + *drip_succeeded = drip(&mut state, tick_count(self.clock.as_ref())); + if state.content.wrapping_sub(amount) < 0 { + return Ok(false); + } + if let Some(parent) = &self.parent { + if !parent.remove_tokens_with_int32(amount)? { + return Ok(false); + } + } + state.content = state.content.wrapping_sub(amount); + Ok(true) + } + pub fn parent(&self) -> TokenBucket { + self.parent + .as_deref() + .expect("root token bucket has no parent") + .clone() + } + pub fn max_burst(&self) -> i32 { + self.state.lock().expect("bucket lock poisoned").max_burst + } + pub fn set_max_burst(&mut self, value: i32) { + self.state.lock().expect("bucket lock poisoned").max_burst = value.max(0); + } + pub fn drip_rate(&self) -> i32 { + self.state + .lock() + .expect("bucket lock poisoned") + .tokens_per_ms + .wrapping_mul(1000) + } + pub fn set_drip_rate(&mut self, value: i32) { + set_drip_rate_state(&mut self.state.lock().expect("bucket lock poisoned"), value); + } + pub fn content(&self) -> i32 { + self.state.lock().expect("bucket lock poisoned").content + } +} +fn set_drip_rate_state(state: &mut TokenState, value: i32) { + state.tokens_per_ms = if value == 0 { + 0 + } else if value / 1000 <= 0 { + 1 + } else { + value / 1000 + }; +} +fn tick_count(clock: &dyn MonotonicClock) -> i32 { + let masked = clock.now().as_millis() % 2_147_483_648_u128; + i32::try_from(masked).expect("masked tick count fits in i32") +} + +fn drip(state: &mut TokenState, now: i32) -> bool { + if state.tokens_per_ms == 0 { + state.content = state.max_burst; + return true; + } + let delta = now.wrapping_sub(state.last_drip); + if delta <= 0 { + if delta < 0 { + state.last_drip = now; + } + return false; + } + let drip_amount = delta.wrapping_mul(state.tokens_per_ms); + state.content = state.content.wrapping_add(drip_amount).min(state.max_burst); + state.last_drip = now; + true +} + +#[cfg(test)] +mod tests { + use super::*; + use std::panic::{AssertUnwindSafe, catch_unwind}; + use std::sync::Barrier; + use std::thread; + struct ManualClock(AtomicU64); + impl ManualClock { + fn new() -> Self { + Self(AtomicU64::new(0)) + } + fn advance(&self, millis: u64) { + self.0.fetch_add(millis, Ordering::SeqCst); + } + } + impl MonotonicClock for ManualClock { + fn now(&self) -> Duration { + Duration::from_millis(self.0.load(Ordering::SeqCst)) + } + } + + #[test] + fn cache_dictionary_lru_and_replacement_behave_like_reference() { + let cache = + CacheDictionary::new(2, Box::new(LruRemovalStrategy::::new().unwrap())).unwrap(); + cache.add_with_t_key_t_value(1, Some("one")).unwrap(); + cache.add_with_t_key_t_value(2, Some("two")).unwrap(); + assert_eq!(cache.item(Some(1)), Some("one")); + cache.add_with_t_key_t_value(3, Some("three")).unwrap(); + assert!(!cache.contains_key(2).unwrap()); + assert!(cache.contains_key(1).unwrap()); + assert_eq!( + cache.add_with_t_key_t_value(1, Some("again")), + Err(Error::Argument) + ); + + let nullable = + CacheDictionary::new(1, Box::new(EmptyRemovalStrategy::::new().unwrap())).unwrap(); + nullable.add_with_t_key_t_value(9, None::).unwrap(); + let mut value = Some(42); + assert!(nullable.try_get_value(9, &mut value)); + assert_eq!(value, None); + + let enumerated = + CacheDictionary::new(2, Box::new(LruRemovalStrategy::::new().unwrap())).unwrap(); + enumerated.add_with_t_key_t_value(1, Some(1)).unwrap(); + enumerated.add_with_t_key_t_value(2, Some(2)).unwrap(); + let mut entries = enumerated.get_enumerator().unwrap(); + assert_eq!(entries.next(), Some((1, Some(1)))); + enumerated.add_with_t_key_t_value(3, Some(3)).unwrap(); + assert!(!enumerated.contains_key(2).unwrap()); + } + + #[test] + fn double_and_multi_value_dictionaries_preserve_pairs_and_duplicates() { + let double = DoubleDictionary::new_with_constructor().unwrap(); + double.add(1, "a", Some(10)).unwrap(); + let mut value = None; + assert!(double.try_get_value_with_t_key2_t_value("a", &mut value)); + assert_eq!(value, Some(10)); + assert!(double.remove_with_t_key1(1).unwrap()); + assert_eq!(double.count(), 0); + let multi = MultiValueDictionary::new_with_constructor().unwrap(); + multi.add("key", Some(1)).unwrap(); + multi.add("key", Some(1)).unwrap(); + multi.add("key", Some(2)).unwrap(); + assert_eq!(multi.item("key"), vec![Some(1), Some(1), Some(2)]); + assert!(multi.remove_with_t_key_t_value("key", Some(1)).unwrap()); + assert_eq!(multi.item("key"), vec![Some(1), Some(2)]); + + multi + .add_range("empty", Box::new(std::iter::empty())) + .unwrap(); + assert!(multi.contains_key("empty").unwrap()); + let mut enumerator = multi.get_enumerator().unwrap(); + multi.add("later", Some(3)).unwrap(); + assert!(catch_unwind(AssertUnwindSafe(|| enumerator.next())).is_err()); + } + + #[test] + fn double_dictionary_callbacks_are_reentrant_and_run_without_collection_locks() { + let dictionary = Arc::new(DoubleDictionary::new_with_constructor().unwrap()); + dictionary.add(1, "one", Some(10)).unwrap(); + dictionary.add(2, "two", Some(20)).unwrap(); + + let observer = Arc::clone(&dictionary); + dictionary + .for_each_with_action_b56adc7f(Box::new(move |_| { + assert_eq!(observer.count(), 2); + })) + .unwrap(); + + let mut nullable = Some(1); + dictionary.add(3, "three", None).unwrap(); + assert!(dictionary.try_get_value_with_t_key1_t_value(3, &mut nullable)); + assert_eq!(nullable, None); + } + + #[test] + fn expiration_and_sliding_access_use_the_injected_clock_without_sleep() { + let clock = Arc::new(ManualClock::new()); + let cache = ExpiringCache::new_with_clock(clock.clone()).unwrap(); + cache + .add_with_t_key_t_value_time_span("sliding", Some(7), Duration::from_millis(10)) + .unwrap(); + clock.advance(8); + assert_eq!(cache.item("sliding"), Some(7)); + clock.advance(8); + assert!(cache.contains("sliding").unwrap()); + clock.advance(3); + assert!(!cache.contains("sliding").unwrap()); + } + + #[test] + fn hierarchical_token_bucket_refills_and_rolls_back_deterministically() { + let clock = Arc::new(ManualClock::new()); + let parent = TokenBucket::new_with_clock(None, 10, 1000, clock.clone()).unwrap(); + let child = + TokenBucket::new_with_clock(Some(parent.clone()), 20, 2000, clock.clone()).unwrap(); + clock.advance(10); + assert!(child.remove_tokens_with_int32(8).unwrap()); + assert_eq!(child.content(), 12); + assert_eq!(parent.content(), 2); + assert!(!child.remove_tokens_with_int32(5).unwrap()); + assert_eq!(child.content(), 12); + } + + #[test] + fn concurrent_cache_and_bucket_operations_preserve_atomic_invariants_without_sleep() { + const WORKERS: usize = 16; + let clock = Arc::new(ManualClock::new()); + let cache = Arc::new(ExpiringCache::new_with_clock(clock.clone()).unwrap()); + let start = Arc::new(Barrier::new(WORKERS)); + let handles: Vec<_> = (0..WORKERS) + .map(|value| { + let cache = Arc::clone(&cache); + let start = Arc::clone(&start); + thread::spawn(move || { + start.wait(); + cache + .add_with_t_key_t_value_double("one-key", Some(value), 60.0) + .unwrap() + }) + }) + .collect(); + let successful_adds = handles + .into_iter() + .map(|handle| handle.join().unwrap()) + .filter(|success| *success) + .count(); + assert_eq!(successful_adds, 1); + assert_eq!(cache.count(), 1); + + let bucket = Arc::new(TokenBucket::new_with_clock(None, 10, 1000, clock.clone()).unwrap()); + clock.advance(10); + let start = Arc::new(Barrier::new(WORKERS)); + let handles: Vec<_> = (0..WORKERS) + .map(|_| { + let bucket = Arc::clone(&bucket); + let start = Arc::clone(&start); + thread::spawn(move || { + start.wait(); + bucket.remove_tokens_with_int32(1).unwrap() + }) + }) + .collect(); + let successful_removals = handles + .into_iter() + .map(|handle| handle.join().unwrap()) + .filter(|success| *success) + .count(); + assert_eq!(successful_removals, 10); + assert_eq!(bucket.content(), 0); + } +} diff --git a/crates/libremetaverse-types/src/generated.rs b/crates/libremetaverse-types/src/generated.rs index 28366d1..3a3accf 100644 --- a/crates/libremetaverse-types/src/generated.rs +++ b/crates/libremetaverse-types/src/generated.rs @@ -191,142 +191,30 @@ pub enum AttachmentPoint { pub use crate::crc32::CRC32; /// C# type: `T:LibreMetaverse.CacheDictionary`2`. -pub struct CacheDictionary { - entries: std::collections::HashMap, - _marker: std::marker::PhantomData<(TKey, TValue)>, -} -impl CacheDictionary { - /// C# member: `M:LibreMetaverse.CacheDictionary`2.#ctor(System.Int32,LibreMetaverse.ICacheDictionaryRemovalStrategy{`0})`. - pub fn new( - max_size: i32, - removal_strategy: Box>, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.CacheDictionary`2.#ctor(System.Int32,LibreMetaverse.ICacheDictionaryRemovalStrategy{`0})", - ) - } - /// C# member: `M:LibreMetaverse.CacheDictionary`2.Add(System.Collections.Generic.KeyValuePair{`0,`1})`. - pub fn add_with_key_value_pair( - &self, - item: (TKey, Option), - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.CacheDictionary`2.Add(System.Collections.Generic.KeyValuePair{`0,`1})", - ) - } - /// C# member: `M:LibreMetaverse.CacheDictionary`2.Add(`0,`1)`. - pub fn add_with_t_key_t_value( - &self, - key: TKey, - value: Option, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.CacheDictionary`2.Add(`0,`1)") - } - /// C# member: `M:LibreMetaverse.CacheDictionary`2.Clear`. - pub fn clear(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.CacheDictionary`2.Clear") - } - /// C# member: `M:LibreMetaverse.CacheDictionary`2.Contains(System.Collections.Generic.KeyValuePair{`0,`1})`. - pub fn contains(&self, item: (TKey, Option)) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.CacheDictionary`2.Contains(System.Collections.Generic.KeyValuePair{`0,`1})", - ) - } - /// C# member: `M:LibreMetaverse.CacheDictionary`2.ContainsKey(`0)`. - pub fn contains_key(&self, key: TKey) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.CacheDictionary`2.ContainsKey(`0)") - } - /// C# member: `M:LibreMetaverse.CacheDictionary`2.CopyTo(System.Collections.Generic.KeyValuePair{`0,`1}[],System.Int32)`. - pub fn copy_to( - &self, - array: Vec<(TKey, TValue)>, - array_index: i32, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.CacheDictionary`2.CopyTo(System.Collections.Generic.KeyValuePair{`0,`1}[],System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.CacheDictionary`2.GetEnumerator`. - pub fn get_enumerator( - &self, - ) -> Result)>>, crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.CacheDictionary`2.GetEnumerator") - } - /// C# member: `M:LibreMetaverse.CacheDictionary`2.Remove(System.Collections.Generic.KeyValuePair{`0,`1})`. - pub fn remove_with_key_value_pair( - &self, - item: (TKey, Option), - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.CacheDictionary`2.Remove(System.Collections.Generic.KeyValuePair{`0,`1})", - ) - } - /// C# member: `M:LibreMetaverse.CacheDictionary`2.Remove(`0)`. - pub fn remove_with_t_key(&self, key: TKey) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.CacheDictionary`2.Remove(`0)") - } - /// C# member: `M:LibreMetaverse.CacheDictionary`2.TryGetValue(`0,`1@)`. - pub fn try_get_value(&self, key: TKey, value: &mut Option) -> bool { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.CacheDictionary`2.TryGetValue(`0,`1@)" - ) - } - /// C# member: `P:LibreMetaverse.CacheDictionary`2.Count`. - pub fn count(&self) -> i32 { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.CacheDictionary`2.Count") - } - /// C# member: `P:LibreMetaverse.CacheDictionary`2.IsReadOnly`. - pub fn is_read_only(&self) -> bool { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.CacheDictionary`2.IsReadOnly") - } - /// C# member: `P:LibreMetaverse.CacheDictionary`2.Item(`0)`. - pub fn item(&self, key: Option) -> Option { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.CacheDictionary`2.Item(`0)") - } - /// Setter for C# member: `P:LibreMetaverse.CacheDictionary`2.Item(`0)`. - pub fn set_item(&mut self, key: Option, value: Option) { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.CacheDictionary`2.Item(`0)") - } - /// C# member: `P:LibreMetaverse.CacheDictionary`2.Keys`. - pub fn keys(&self) -> Vec { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.CacheDictionary`2.Keys") - } - /// C# member: `P:LibreMetaverse.CacheDictionary`2.Values`. - pub fn values(&self) -> Vec> { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.CacheDictionary`2.Values") - } -} +/// C# member: `M:LibreMetaverse.CacheDictionary`2.#ctor(System.Int32,LibreMetaverse.ICacheDictionaryRemovalStrategy{`0})`. +/// C# member: `M:LibreMetaverse.CacheDictionary`2.Add(System.Collections.Generic.KeyValuePair{`0,`1})`. +/// C# member: `M:LibreMetaverse.CacheDictionary`2.Add(`0,`1)`. +/// C# member: `M:LibreMetaverse.CacheDictionary`2.Clear`. +/// C# member: `M:LibreMetaverse.CacheDictionary`2.Contains(System.Collections.Generic.KeyValuePair{`0,`1})`. +/// C# member: `M:LibreMetaverse.CacheDictionary`2.ContainsKey(`0)`. +/// C# member: `M:LibreMetaverse.CacheDictionary`2.CopyTo(System.Collections.Generic.KeyValuePair{`0,`1}[],System.Int32)`. +/// C# member: `M:LibreMetaverse.CacheDictionary`2.GetEnumerator`. +/// C# member: `M:LibreMetaverse.CacheDictionary`2.Remove(System.Collections.Generic.KeyValuePair{`0,`1})`. +/// C# member: `M:LibreMetaverse.CacheDictionary`2.Remove(`0)`. +/// C# member: `M:LibreMetaverse.CacheDictionary`2.TryGetValue(`0,`1@)`. +/// C# member: `P:LibreMetaverse.CacheDictionary`2.Count`. +/// C# member: `P:LibreMetaverse.CacheDictionary`2.IsReadOnly`. +/// C# member: `P:LibreMetaverse.CacheDictionary`2.Item(`0)`. +/// C# member: `P:LibreMetaverse.CacheDictionary`2.Keys`. +/// C# member: `P:LibreMetaverse.CacheDictionary`2.Values`. +pub use crate::collections::CacheDictionary; /// C# type: `T:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator`. -pub struct CacheDictionaryCacheDictionaryEnumerator { - _marker: std::marker::PhantomData<(TKey, TValue)>, -} -impl CacheDictionaryCacheDictionaryEnumerator { - /// C# member: `M:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator.Dispose`. - pub fn dispose(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator.Dispose", - ) - } - /// C# member: `M:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator.MoveNext`. - pub fn move_next(&self) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator.MoveNext", - ) - } - /// C# member: `M:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator.Reset`. - pub fn reset(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator.Reset", - ) - } - /// C# member: `P:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator.Current`. - pub fn current(&self) -> (TKey, Option) { - libremetaverse_types::unimplemented_api!( - "P:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator.Current" - ) - } -} +/// C# member: `M:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator.Dispose`. +/// C# member: `M:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator.MoveNext`. +/// C# member: `M:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator.Reset`. +/// C# member: `P:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator.Current`. +pub use crate::collections::CacheDictionaryCacheDictionaryEnumerator; /// C# type: `T:LibreMetaverse.ClickAction`. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -384,187 +272,36 @@ pub enum ClickAction { pub use crate::color4::Color4; /// C# type: `T:LibreMetaverse.DoubleDictionary`3`. -pub struct DoubleDictionary { - by_first: std::collections::HashMap, - by_second: std::collections::HashMap, - _marker: std::marker::PhantomData<(TKey1, TKey2, TValue)>, -} -impl DoubleDictionary { - /// C# member: `M:LibreMetaverse.DoubleDictionary`3.#ctor`. - pub fn new_with_constructor() -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.DoubleDictionary`3.#ctor") - } - /// C# member: `M:LibreMetaverse.DoubleDictionary`3.#ctor(System.Int32)`. - pub fn new_with_int32(capacity: i32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.DoubleDictionary`3.#ctor(System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.DoubleDictionary`3.Add(`0,`1,`2)`. - pub fn add(&self, key1: TKey1, key2: TKey2, value: Option) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.DoubleDictionary`3.Add(`0,`1,`2)") - } - /// C# member: `M:LibreMetaverse.DoubleDictionary`3.Clear`. - pub fn clear(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.DoubleDictionary`3.Clear") - } - /// C# member: `M:LibreMetaverse.DoubleDictionary`3.ContainsKey(`0)`. - pub fn contains_key_with_t_key1(&self, key: TKey1) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.DoubleDictionary`3.ContainsKey(`0)") - } - /// C# member: `M:LibreMetaverse.DoubleDictionary`3.ContainsKey(`1)`. - pub fn contains_key_with_t_key2(&self, key: TKey2) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.DoubleDictionary`3.ContainsKey(`1)") - } - /// C# member: `M:LibreMetaverse.DoubleDictionary`3.Dispose`. - pub fn dispose(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.DoubleDictionary`3.Dispose") - } - /// C# member: `M:LibreMetaverse.DoubleDictionary`3.FindAll(System.Predicate{`2})`. - pub fn find_all( - &self, - predicate: Box) -> bool + Send + Sync>, - ) -> Result>, crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.DoubleDictionary`3.FindAll(System.Predicate{`2})", - ) - } - /// C# member: `M:LibreMetaverse.DoubleDictionary`3.FindValue(System.Predicate{`2})`. - pub fn find_value( - &self, - predicate: Box) -> bool + Send + Sync>, - ) -> Result, crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.DoubleDictionary`3.FindValue(System.Predicate{`2})", - ) - } - /// C# member: `M:LibreMetaverse.DoubleDictionary`3.ForEach(System.Action{System.Collections.Generic.KeyValuePair{`0,`2}})`. - pub fn for_each_with_action( - &self, - action: Box)) + Send + Sync>, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.DoubleDictionary`3.ForEach(System.Action{System.Collections.Generic.KeyValuePair{`0,`2}})", - ) - } - /// C# member: `M:LibreMetaverse.DoubleDictionary`3.ForEach(System.Action{System.Collections.Generic.KeyValuePair{`1,`2}})`. - pub fn for_each_with_action_4dc2e201( - &self, - action: Box)) + Send + Sync>, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.DoubleDictionary`3.ForEach(System.Action{System.Collections.Generic.KeyValuePair{`1,`2}})", - ) - } - /// C# member: `M:LibreMetaverse.DoubleDictionary`3.ForEach(System.Action{`2})`. - pub fn for_each_with_action_b56adc7f( - &self, - action: Box) + Send + Sync>, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.DoubleDictionary`3.ForEach(System.Action{`2})", - ) - } - /// C# member: `M:LibreMetaverse.DoubleDictionary`3.Remove(`0)`. - pub fn remove_with_t_key1(&self, key1: TKey1) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.DoubleDictionary`3.Remove(`0)") - } - /// C# member: `M:LibreMetaverse.DoubleDictionary`3.Remove(`0,`1)`. - pub fn remove_with_t_key1_t_key2( - &self, - key1: TKey1, - key2: TKey2, - ) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.DoubleDictionary`3.Remove(`0,`1)") - } - /// C# member: `M:LibreMetaverse.DoubleDictionary`3.Remove(`1)`. - pub fn remove_with_t_key2(&self, key2: TKey2) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.DoubleDictionary`3.Remove(`1)") - } - /// C# member: `M:LibreMetaverse.DoubleDictionary`3.RemoveAll(System.Predicate{`2})`. - pub fn remove_all( - &self, - predicate: Box) -> bool + Send + Sync>, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.DoubleDictionary`3.RemoveAll(System.Predicate{`2})", - ) - } - /// C# member: `M:LibreMetaverse.DoubleDictionary`3.TryGetValue(`0,`2@)`. - pub fn try_get_value_with_t_key1_t_value( - &self, - key: TKey1, - value: &mut Option, - ) -> bool { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.DoubleDictionary`3.TryGetValue(`0,`2@)" - ) - } - /// C# member: `M:LibreMetaverse.DoubleDictionary`3.TryGetValue(`1,`2@)`. - pub fn try_get_value_with_t_key2_t_value( - &self, - key: TKey2, - value: &mut Option, - ) -> bool { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.DoubleDictionary`3.TryGetValue(`1,`2@)" - ) - } - /// C# member: `P:LibreMetaverse.DoubleDictionary`3.Count`. - pub fn count(&self) -> i32 { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.DoubleDictionary`3.Count") - } -} +/// C# member: `M:LibreMetaverse.DoubleDictionary`3.#ctor`. +/// C# member: `M:LibreMetaverse.DoubleDictionary`3.#ctor(System.Int32)`. +/// C# member: `M:LibreMetaverse.DoubleDictionary`3.Add(`0,`1,`2)`. +/// C# member: `M:LibreMetaverse.DoubleDictionary`3.Clear`. +/// C# member: `M:LibreMetaverse.DoubleDictionary`3.ContainsKey(`0)`. +/// C# member: `M:LibreMetaverse.DoubleDictionary`3.ContainsKey(`1)`. +/// C# member: `M:LibreMetaverse.DoubleDictionary`3.Dispose`. +/// C# member: `M:LibreMetaverse.DoubleDictionary`3.FindAll(System.Predicate{`2})`. +/// C# member: `M:LibreMetaverse.DoubleDictionary`3.FindValue(System.Predicate{`2})`. +/// C# member: `M:LibreMetaverse.DoubleDictionary`3.ForEach(System.Action{System.Collections.Generic.KeyValuePair{`0,`2}})`. +/// C# member: `M:LibreMetaverse.DoubleDictionary`3.ForEach(System.Action{System.Collections.Generic.KeyValuePair{`1,`2}})`. +/// C# member: `M:LibreMetaverse.DoubleDictionary`3.ForEach(System.Action{`2})`. +/// C# member: `M:LibreMetaverse.DoubleDictionary`3.Remove(`0)`. +/// C# member: `M:LibreMetaverse.DoubleDictionary`3.Remove(`0,`1)`. +/// C# member: `M:LibreMetaverse.DoubleDictionary`3.Remove(`1)`. +/// C# member: `M:LibreMetaverse.DoubleDictionary`3.RemoveAll(System.Predicate{`2})`. +/// C# member: `M:LibreMetaverse.DoubleDictionary`3.TryGetValue(`0,`2@)`. +/// C# member: `M:LibreMetaverse.DoubleDictionary`3.TryGetValue(`1,`2@)`. +/// C# member: `P:LibreMetaverse.DoubleDictionary`3.Count`. +pub use crate::collections::DoubleDictionary; /// C# type: `T:LibreMetaverse.EmptyRemovalStrategy`1`. -pub struct EmptyRemovalStrategy { - keys: Vec, - _marker: std::marker::PhantomData<(TKey,)>, -} -impl EmptyRemovalStrategy { - /// C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.#ctor`. - pub fn new() -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.EmptyRemovalStrategy`1.#ctor") - } - /// C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.Clear`. - pub fn clear(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.EmptyRemovalStrategy`1.Clear") - } - /// C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.GetKeyToRemove`. - pub fn get_key_to_remove(&self) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.EmptyRemovalStrategy`1.GetKeyToRemove", - ) - } - /// C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.Initialize(System.Int32)`. - pub fn initialize(&self, max_size: i32) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.EmptyRemovalStrategy`1.Initialize(System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.KeyAccessed(`0)`. - pub fn key_accessed(&self, key: TKey) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.EmptyRemovalStrategy`1.KeyAccessed(`0)", - ) - } - /// C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.KeyAdded(`0)`. - pub fn key_added(&self, key: TKey) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.EmptyRemovalStrategy`1.KeyAdded(`0)", - ) - } - /// C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.KeyRemoved(`0)`. - pub fn key_removed(&self, key: TKey) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.EmptyRemovalStrategy`1.KeyRemoved(`0)", - ) - } -} -impl libremetaverse_types::ICacheDictionaryRemovalStrategy - for EmptyRemovalStrategy -{ -} +/// C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.#ctor`. +/// C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.Clear`. +/// C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.GetKeyToRemove`. +/// C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.Initialize(System.Int32)`. +/// C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.KeyAccessed(`0)`. +/// C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.KeyAdded(`0)`. +/// C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.KeyRemoved(`0)`. +pub use crate::collections::EmptyRemovalStrategy; /// C# type: `T:LibreMetaverse.EnumInfoAttribute`. /// C# member: `F:LibreMetaverse.EnumInfoAttribute.Text`. @@ -577,130 +314,23 @@ pub use crate::enum_compat::EnumInfoAttribute; pub use crate::enum_compat::EnumInfoExtensions; /// C# type: `T:LibreMetaverse.ExpiringCache`2`. -pub struct ExpiringCache { - entries: std::collections::HashMap, - _marker: std::marker::PhantomData<(TKey, TValue)>, -} -impl ExpiringCache { - /// C# member: `M:LibreMetaverse.ExpiringCache`2.#ctor`. - pub fn new() -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.ExpiringCache`2.#ctor") - } - /// C# member: `M:LibreMetaverse.ExpiringCache`2.Add(`0,`1,System.Double)`. - pub fn add_with_t_key_t_value_double( - &self, - key: TKey, - value: Option, - expiration_seconds: f64, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.ExpiringCache`2.Add(`0,`1,System.Double)", - ) - } - /// C# member: `M:LibreMetaverse.ExpiringCache`2.Add(`0,`1,System.TimeSpan)`. - pub fn add_with_t_key_t_value_time_span( - &self, - key: TKey, - value: Option, - sliding_expiration: std::time::Duration, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.ExpiringCache`2.Add(`0,`1,System.TimeSpan)", - ) - } - /// C# member: `M:LibreMetaverse.ExpiringCache`2.AddOrUpdate(`0,`1,System.Double)`. - pub fn add_or_update_with_t_key_t_value_double( - &self, - key: TKey, - value: Option, - expiration_seconds: f64, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.ExpiringCache`2.AddOrUpdate(`0,`1,System.Double)", - ) - } - /// C# member: `M:LibreMetaverse.ExpiringCache`2.AddOrUpdate(`0,`1,System.TimeSpan)`. - pub fn add_or_update_with_t_key_t_value_time_span( - &self, - key: TKey, - value: Option, - sliding_expiration: std::time::Duration, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.ExpiringCache`2.AddOrUpdate(`0,`1,System.TimeSpan)", - ) - } - /// C# member: `M:LibreMetaverse.ExpiringCache`2.Clear`. - pub fn clear(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.ExpiringCache`2.Clear") - } - /// C# member: `M:LibreMetaverse.ExpiringCache`2.Contains(`0)`. - pub fn contains(&self, key: TKey) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.ExpiringCache`2.Contains(`0)") - } - /// C# member: `M:LibreMetaverse.ExpiringCache`2.CopyTo(System.Array,System.Int32)`. - pub fn copy_to( - &self, - array: libremetaverse_types::compat::Array, - start_index: i32, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.ExpiringCache`2.CopyTo(System.Array,System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.ExpiringCache`2.Dispose`. - pub fn dispose(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.ExpiringCache`2.Dispose") - } - /// C# member: `M:LibreMetaverse.ExpiringCache`2.Remove(`0)`. - pub fn remove(&self, key: TKey) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.ExpiringCache`2.Remove(`0)") - } - /// C# member: `M:LibreMetaverse.ExpiringCache`2.TryGetValue(`0,`1@)`. - pub fn try_get_value(&self, key: TKey, value: &mut Option) -> bool { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.ExpiringCache`2.TryGetValue(`0,`1@)" - ) - } - /// C# member: `M:LibreMetaverse.ExpiringCache`2.Update(`0,`1)`. - pub fn update_with_t_key_t_value( - &self, - key: TKey, - value: Option, - ) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.ExpiringCache`2.Update(`0,`1)") - } - /// C# member: `M:LibreMetaverse.ExpiringCache`2.Update(`0,`1,System.Double)`. - pub fn update_with_t_key_t_value_double( - &self, - key: TKey, - value: Option, - expiration_seconds: f64, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.ExpiringCache`2.Update(`0,`1,System.Double)", - ) - } - /// C# member: `M:LibreMetaverse.ExpiringCache`2.Update(`0,`1,System.TimeSpan)`. - pub fn update_with_t_key_t_value_time_span( - &self, - key: TKey, - value: Option, - sliding_expiration: std::time::Duration, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.ExpiringCache`2.Update(`0,`1,System.TimeSpan)", - ) - } - /// C# member: `P:LibreMetaverse.ExpiringCache`2.Count`. - pub fn count(&self) -> i32 { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.ExpiringCache`2.Count") - } - /// C# member: `P:LibreMetaverse.ExpiringCache`2.Item(`0)`. - pub fn item(&self, key: TKey) -> Option { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.ExpiringCache`2.Item(`0)") - } -} +/// C# member: `M:LibreMetaverse.ExpiringCache`2.#ctor`. +/// C# member: `M:LibreMetaverse.ExpiringCache`2.Add(`0,`1,System.Double)`. +/// C# member: `M:LibreMetaverse.ExpiringCache`2.Add(`0,`1,System.TimeSpan)`. +/// C# member: `M:LibreMetaverse.ExpiringCache`2.AddOrUpdate(`0,`1,System.Double)`. +/// C# member: `M:LibreMetaverse.ExpiringCache`2.AddOrUpdate(`0,`1,System.TimeSpan)`. +/// C# member: `M:LibreMetaverse.ExpiringCache`2.Clear`. +/// C# member: `M:LibreMetaverse.ExpiringCache`2.Contains(`0)`. +/// C# member: `M:LibreMetaverse.ExpiringCache`2.CopyTo(System.Array,System.Int32)`. +/// C# member: `M:LibreMetaverse.ExpiringCache`2.Dispose`. +/// C# member: `M:LibreMetaverse.ExpiringCache`2.Remove(`0)`. +/// C# member: `M:LibreMetaverse.ExpiringCache`2.TryGetValue(`0,`1@)`. +/// C# member: `M:LibreMetaverse.ExpiringCache`2.Update(`0,`1)`. +/// C# member: `M:LibreMetaverse.ExpiringCache`2.Update(`0,`1,System.Double)`. +/// C# member: `M:LibreMetaverse.ExpiringCache`2.Update(`0,`1,System.TimeSpan)`. +/// C# member: `P:LibreMetaverse.ExpiringCache`2.Count`. +/// C# member: `P:LibreMetaverse.ExpiringCache`2.Item(`0)`. +pub use crate::collections::ExpiringCache; /// C# type: `T:LibreMetaverse.ExtraParamType`. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -838,44 +468,13 @@ impl HoleType { } /// C# type: `T:LibreMetaverse.ICacheDictionaryRemovalStrategy`1`. -pub trait ICacheDictionaryRemovalStrategy { - /// C# member: `M:LibreMetaverse.ICacheDictionaryRemovalStrategy`1.Clear`. - fn clear(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.ICacheDictionaryRemovalStrategy`1.Clear", - ) - } - /// C# member: `M:LibreMetaverse.ICacheDictionaryRemovalStrategy`1.GetKeyToRemove`. - fn get_key_to_remove(&self) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.ICacheDictionaryRemovalStrategy`1.GetKeyToRemove", - ) - } - /// C# member: `M:LibreMetaverse.ICacheDictionaryRemovalStrategy`1.Initialize(System.Int32)`. - fn initialize(&self, max_size: i32) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.ICacheDictionaryRemovalStrategy`1.Initialize(System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.ICacheDictionaryRemovalStrategy`1.KeyAccessed(`0)`. - fn key_accessed(&self, key: TKey) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.ICacheDictionaryRemovalStrategy`1.KeyAccessed(`0)", - ) - } - /// C# member: `M:LibreMetaverse.ICacheDictionaryRemovalStrategy`1.KeyAdded(`0)`. - fn key_added(&self, key: TKey) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.ICacheDictionaryRemovalStrategy`1.KeyAdded(`0)", - ) - } - /// C# member: `M:LibreMetaverse.ICacheDictionaryRemovalStrategy`1.KeyRemoved(`0)`. - fn key_removed(&self, key: TKey) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.ICacheDictionaryRemovalStrategy`1.KeyRemoved(`0)", - ) - } -} +/// C# member: `M:LibreMetaverse.ICacheDictionaryRemovalStrategy`1.Clear`. +/// C# member: `M:LibreMetaverse.ICacheDictionaryRemovalStrategy`1.GetKeyToRemove`. +/// C# member: `M:LibreMetaverse.ICacheDictionaryRemovalStrategy`1.Initialize(System.Int32)`. +/// C# member: `M:LibreMetaverse.ICacheDictionaryRemovalStrategy`1.KeyAccessed(`0)`. +/// C# member: `M:LibreMetaverse.ICacheDictionaryRemovalStrategy`1.KeyAdded(`0)`. +/// C# member: `M:LibreMetaverse.ICacheDictionaryRemovalStrategy`1.KeyRemoved(`0)`. +pub use crate::collections::ICacheDictionaryRemovalStrategy; /// C# type: `T:LibreMetaverse.InventoryType`. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -935,52 +534,14 @@ pub enum JointType { } /// C# type: `T:LibreMetaverse.LruRemovalStrategy`1`. -pub struct LruRemovalStrategy { - keys: Vec, - _marker: std::marker::PhantomData<(TKey,)>, -} -impl LruRemovalStrategy { - /// C# member: `M:LibreMetaverse.LruRemovalStrategy`1.#ctor`. - pub fn new() -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.LruRemovalStrategy`1.#ctor") - } - /// C# member: `M:LibreMetaverse.LruRemovalStrategy`1.Clear`. - pub fn clear(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.LruRemovalStrategy`1.Clear") - } - /// C# member: `M:LibreMetaverse.LruRemovalStrategy`1.GetKeyToRemove`. - pub fn get_key_to_remove(&self) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LruRemovalStrategy`1.GetKeyToRemove", - ) - } - /// C# member: `M:LibreMetaverse.LruRemovalStrategy`1.Initialize(System.Int32)`. - pub fn initialize(&self, max_size: i32) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LruRemovalStrategy`1.Initialize(System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.LruRemovalStrategy`1.KeyAccessed(`0)`. - pub fn key_accessed(&self, key: TKey) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LruRemovalStrategy`1.KeyAccessed(`0)", - ) - } - /// C# member: `M:LibreMetaverse.LruRemovalStrategy`1.KeyAdded(`0)`. - pub fn key_added(&self, key: TKey) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.LruRemovalStrategy`1.KeyAdded(`0)") - } - /// C# member: `M:LibreMetaverse.LruRemovalStrategy`1.KeyRemoved(`0)`. - pub fn key_removed(&self, key: TKey) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.LruRemovalStrategy`1.KeyRemoved(`0)", - ) - } -} -impl libremetaverse_types::ICacheDictionaryRemovalStrategy - for LruRemovalStrategy -{ -} +/// C# member: `M:LibreMetaverse.LruRemovalStrategy`1.#ctor`. +/// C# member: `M:LibreMetaverse.LruRemovalStrategy`1.Clear`. +/// C# member: `M:LibreMetaverse.LruRemovalStrategy`1.GetKeyToRemove`. +/// C# member: `M:LibreMetaverse.LruRemovalStrategy`1.Initialize(System.Int32)`. +/// C# member: `M:LibreMetaverse.LruRemovalStrategy`1.KeyAccessed(`0)`. +/// C# member: `M:LibreMetaverse.LruRemovalStrategy`1.KeyAdded(`0)`. +/// C# member: `M:LibreMetaverse.LruRemovalStrategy`1.KeyRemoved(`0)`. +pub use crate::collections::LruRemovalStrategy; /// C# type: `T:LibreMetaverse.Material`. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -1078,319 +639,49 @@ pub enum Material { pub use crate::geometry::Matrix4; /// C# type: `T:LibreMetaverse.MruRemovalStrategy`1`. -pub struct MruRemovalStrategy { - keys: Vec, - _marker: std::marker::PhantomData<(TKey,)>, -} -impl MruRemovalStrategy { - /// C# member: `M:LibreMetaverse.MruRemovalStrategy`1.#ctor`. - pub fn new() -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.MruRemovalStrategy`1.#ctor") - } - /// C# member: `M:LibreMetaverse.MruRemovalStrategy`1.Clear`. - pub fn clear(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.MruRemovalStrategy`1.Clear") - } - /// C# member: `M:LibreMetaverse.MruRemovalStrategy`1.GetKeyToRemove`. - pub fn get_key_to_remove(&self) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MruRemovalStrategy`1.GetKeyToRemove", - ) - } - /// C# member: `M:LibreMetaverse.MruRemovalStrategy`1.Initialize(System.Int32)`. - pub fn initialize(&self, max_size: i32) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MruRemovalStrategy`1.Initialize(System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.MruRemovalStrategy`1.KeyAccessed(`0)`. - pub fn key_accessed(&self, key: TKey) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MruRemovalStrategy`1.KeyAccessed(`0)", - ) - } - /// C# member: `M:LibreMetaverse.MruRemovalStrategy`1.KeyAdded(`0)`. - pub fn key_added(&self, key: TKey) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.MruRemovalStrategy`1.KeyAdded(`0)") - } - /// C# member: `M:LibreMetaverse.MruRemovalStrategy`1.KeyRemoved(`0)`. - pub fn key_removed(&self, key: TKey) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MruRemovalStrategy`1.KeyRemoved(`0)", - ) - } -} -impl libremetaverse_types::ICacheDictionaryRemovalStrategy - for MruRemovalStrategy -{ -} +/// C# member: `M:LibreMetaverse.MruRemovalStrategy`1.#ctor`. +/// C# member: `M:LibreMetaverse.MruRemovalStrategy`1.Clear`. +/// C# member: `M:LibreMetaverse.MruRemovalStrategy`1.GetKeyToRemove`. +/// C# member: `M:LibreMetaverse.MruRemovalStrategy`1.Initialize(System.Int32)`. +/// C# member: `M:LibreMetaverse.MruRemovalStrategy`1.KeyAccessed(`0)`. +/// C# member: `M:LibreMetaverse.MruRemovalStrategy`1.KeyAdded(`0)`. +/// C# member: `M:LibreMetaverse.MruRemovalStrategy`1.KeyRemoved(`0)`. +pub use crate::collections::MruRemovalStrategy; /// C# type: `T:LibreMetaverse.MultiValueDictionary`2`. -pub struct MultiValueDictionary { - entries: std::collections::HashMap>, - _marker: std::marker::PhantomData<(TKey, TValue)>, -} -impl MultiValueDictionary { - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.#ctor`. - pub fn new_with_constructor() -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.MultiValueDictionary`2.#ctor") - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}})`. - pub fn new_with_i_enumerable( - enumerable: Box>)>>, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}})", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}},System.Collections.Generic.IEqualityComparer{`0})`. - pub fn new_with_i_enumerable_i_equality_comparer( - enumerable: Box>)>>, - comparer: libremetaverse_types::compat::IEqualityComparer, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}},System.Collections.Generic.IEqualityComparer{`0})", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Collections.Generic.IEqualityComparer{`0})`. - pub fn new_with_i_equality_comparer( - comparer: libremetaverse_types::compat::IEqualityComparer, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Collections.Generic.IEqualityComparer{`0})", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Int32)`. - pub fn new_with_int32(capacity: i32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Int32,System.Collections.Generic.IEqualityComparer{`0})`. - pub fn new_with_int32_i_equality_comparer( - capacity: i32, - comparer: libremetaverse_types::compat::IEqualityComparer, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Int32,System.Collections.Generic.IEqualityComparer{`0})", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Add(`0,`1)`. - pub fn add(&self, key: TKey, value: Option) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.MultiValueDictionary`2.Add(`0,`1)") - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.AddRange(`0,System.Collections.Generic.IEnumerable{`1})`. - pub fn add_range( - &self, - key: TKey, - values: Box>>, - ) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.AddRange(`0,System.Collections.Generic.IEnumerable{`1})", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Clear`. - pub fn clear(&self) -> Result<(), crate::Error> { - libremetaverse_types::not_implemented("M:LibreMetaverse.MultiValueDictionary`2.Clear") - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Contains(`0,`1)`. - pub fn contains(&self, key: TKey, value: Option) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.Contains(`0,`1)", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.ContainsKey(`0)`. - pub fn contains_key(&self, key: TKey) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.ContainsKey(`0)", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.ContainsValue(`1)`. - pub fn contains_value(&self, value: Option) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.ContainsValue(`1)", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1`. - pub fn create_with_method< - TValueCollection: libremetaverse_types::compat::Collection + Default, - >() -> Result>, crate::Error> - { - libremetaverse_types::not_implemented("M:LibreMetaverse.MultiValueDictionary`2.Create``1") - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}})`. - pub fn create_with_i_enumerable< - TValueCollection: libremetaverse_types::compat::Collection + Default, - >( - enumerable: Box>)>>, - ) -> Result>, crate::Error> - { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}})", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}},System.Collections.Generic.IEqualityComparer{`0})`. - pub fn create_with_i_enumerable_i_equality_comparer< - TValueCollection: libremetaverse_types::compat::Collection + Default, - >( - enumerable: Box>)>>, - comparer: libremetaverse_types::compat::IEqualityComparer, - ) -> Result>, crate::Error> - { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}},System.Collections.Generic.IEqualityComparer{`0})", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}},System.Collections.Generic.IEqualityComparer{`0},System.Func{``0})`. - pub fn create_with_i_enumerable_i_equality_comparer_func< - TValueCollection: libremetaverse_types::compat::Collection, - >( - enumerable: Box>)>>, - comparer: libremetaverse_types::compat::IEqualityComparer, - collection_factory: Box TValueCollection + Send + Sync>, - ) -> Result>, crate::Error> - { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}},System.Collections.Generic.IEqualityComparer{`0},System.Func{``0})", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}},System.Func{``0})`. - pub fn create_with_i_enumerable_func< - TValueCollection: libremetaverse_types::compat::Collection, - >( - enumerable: Box>)>>, - collection_factory: Box TValueCollection + Send + Sync>, - ) -> Result>, crate::Error> - { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}},System.Func{``0})", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEqualityComparer{`0})`. - pub fn create_with_i_equality_comparer< - TValueCollection: libremetaverse_types::compat::Collection + Default, - >( - comparer: libremetaverse_types::compat::IEqualityComparer, - ) -> Result>, crate::Error> - { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEqualityComparer{`0})", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEqualityComparer{`0},System.Func{``0})`. - pub fn create_with_i_equality_comparer_func< - TValueCollection: libremetaverse_types::compat::Collection, - >( - comparer: libremetaverse_types::compat::IEqualityComparer, - collection_factory: Box TValueCollection + Send + Sync>, - ) -> Result>, crate::Error> - { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEqualityComparer{`0},System.Func{``0})", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Func{``0})`. - pub fn create_with_func>( - collection_factory: Box TValueCollection + Send + Sync>, - ) -> Result>, crate::Error> - { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Func{``0})", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Int32)`. - pub fn create_with_int32< - TValueCollection: libremetaverse_types::compat::Collection + Default, - >( - capacity: i32, - ) -> Result>, crate::Error> - { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Int32,System.Collections.Generic.IEqualityComparer{`0})`. - pub fn create_with_int32_i_equality_comparer< - TValueCollection: libremetaverse_types::compat::Collection + Default, - >( - capacity: i32, - comparer: libremetaverse_types::compat::IEqualityComparer, - ) -> Result>, crate::Error> - { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Int32,System.Collections.Generic.IEqualityComparer{`0})", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Int32,System.Collections.Generic.IEqualityComparer{`0},System.Func{``0})`. - pub fn create_with_int32_i_equality_comparer_func< - TValueCollection: libremetaverse_types::compat::Collection, - >( - capacity: i32, - comparer: libremetaverse_types::compat::IEqualityComparer, - collection_factory: Box TValueCollection + Send + Sync>, - ) -> Result>, crate::Error> - { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Int32,System.Collections.Generic.IEqualityComparer{`0},System.Func{``0})", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Int32,System.Func{``0})`. - pub fn create_with_int32_func< - TValueCollection: libremetaverse_types::compat::Collection, - >( - capacity: i32, - collection_factory: Box TValueCollection + Send + Sync>, - ) -> Result>, crate::Error> - { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Int32,System.Func{``0})", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.GetEnumerator`. - pub fn get_enumerator( - &self, - ) -> Result>)>>, crate::Error> { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.GetEnumerator", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Remove(`0)`. - pub fn remove_with_t_key(&self, key: TKey) -> Result { - libremetaverse_types::not_implemented("M:LibreMetaverse.MultiValueDictionary`2.Remove(`0)") - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Remove(`0,`1)`. - pub fn remove_with_t_key_t_value( - &self, - key: TKey, - value: Option, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.MultiValueDictionary`2.Remove(`0,`1)", - ) - } - /// C# member: `M:LibreMetaverse.MultiValueDictionary`2.TryGetValue(`0,System.Collections.Generic.IReadOnlyCollection{`1}@)`. - pub fn try_get_value(&self, key: TKey, value: &mut Option>>) -> bool { - libremetaverse_types::unimplemented_api!( - "M:LibreMetaverse.MultiValueDictionary`2.TryGetValue(`0,System.Collections.Generic.IReadOnlyCollection{`1}@)" - ) - } - /// C# member: `P:LibreMetaverse.MultiValueDictionary`2.Count`. - pub fn count(&self) -> i32 { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.MultiValueDictionary`2.Count") - } - /// C# member: `P:LibreMetaverse.MultiValueDictionary`2.Item(`0)`. - pub fn item(&self, key: TKey) -> Vec> { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.MultiValueDictionary`2.Item(`0)") - } - /// C# member: `P:LibreMetaverse.MultiValueDictionary`2.Keys`. - pub fn keys(&self) -> Box> { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.MultiValueDictionary`2.Keys") - } - /// C# member: `P:LibreMetaverse.MultiValueDictionary`2.Values`. - pub fn values(&self) -> Box>>> { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.MultiValueDictionary`2.Values") - } -} +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.#ctor`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}})`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}},System.Collections.Generic.IEqualityComparer{`0})`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Collections.Generic.IEqualityComparer{`0})`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Int32)`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Int32,System.Collections.Generic.IEqualityComparer{`0})`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Add(`0,`1)`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.AddRange(`0,System.Collections.Generic.IEnumerable{`1})`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Clear`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Contains(`0,`1)`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.ContainsKey(`0)`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.ContainsValue(`1)`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}})`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}},System.Collections.Generic.IEqualityComparer{`0})`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}},System.Collections.Generic.IEqualityComparer{`0},System.Func{``0})`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}},System.Func{``0})`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEqualityComparer{`0})`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEqualityComparer{`0},System.Func{``0})`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Func{``0})`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Int32)`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Int32,System.Collections.Generic.IEqualityComparer{`0})`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Int32,System.Collections.Generic.IEqualityComparer{`0},System.Func{``0})`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Int32,System.Func{``0})`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.GetEnumerator`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Remove(`0)`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.Remove(`0,`1)`. +/// C# member: `M:LibreMetaverse.MultiValueDictionary`2.TryGetValue(`0,System.Collections.Generic.IReadOnlyCollection{`1}@)`. +/// C# member: `P:LibreMetaverse.MultiValueDictionary`2.Count`. +/// C# member: `P:LibreMetaverse.MultiValueDictionary`2.Item(`0)`. +/// C# member: `P:LibreMetaverse.MultiValueDictionary`2.Keys`. +/// C# member: `P:LibreMetaverse.MultiValueDictionary`2.Values`. +pub use crate::collections::MultiValueDictionary; /// C# type: `T:LibreMetaverse.ObjectCategory`. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -1693,63 +984,14 @@ impl SoundFlags { } /// C# type: `T:LibreMetaverse.TokenBucket`. -pub struct TokenBucket { - content: i32, - max_burst: i32, - drip_rate: i32, -} -impl TokenBucket { - /// C# member: `M:LibreMetaverse.TokenBucket.#ctor(LibreMetaverse.TokenBucket,System.Int32,System.Int32)`. - pub fn new( - parent: libremetaverse_types::TokenBucket, - max_burst: i32, - drip_rate: i32, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.TokenBucket.#ctor(LibreMetaverse.TokenBucket,System.Int32,System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.TokenBucket.RemoveTokens(System.Int32)`. - pub fn remove_tokens_with_int32(&self, amount: i32) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.TokenBucket.RemoveTokens(System.Int32)", - ) - } - /// C# member: `M:LibreMetaverse.TokenBucket.RemoveTokens(System.Int32,System.Boolean@)`. - pub fn remove_tokens_with_int32_boolean( - &self, - amount: i32, - drip_succeeded: &mut bool, - ) -> Result { - libremetaverse_types::not_implemented( - "M:LibreMetaverse.TokenBucket.RemoveTokens(System.Int32,System.Boolean@)", - ) - } - /// C# member: `P:LibreMetaverse.TokenBucket.Content`. - pub fn content(&self) -> i32 { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.TokenBucket.Content") - } - /// C# member: `P:LibreMetaverse.TokenBucket.DripRate`. - pub fn drip_rate(&self) -> i32 { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.TokenBucket.DripRate") - } - /// Setter for C# member: `P:LibreMetaverse.TokenBucket.DripRate`. - pub fn set_drip_rate(&mut self, value: i32) { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.TokenBucket.DripRate") - } - /// C# member: `P:LibreMetaverse.TokenBucket.MaxBurst`. - pub fn max_burst(&self) -> i32 { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.TokenBucket.MaxBurst") - } - /// Setter for C# member: `P:LibreMetaverse.TokenBucket.MaxBurst`. - pub fn set_max_burst(&mut self, value: i32) { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.TokenBucket.MaxBurst") - } - /// C# member: `P:LibreMetaverse.TokenBucket.Parent`. - pub fn parent(&self) -> libremetaverse_types::TokenBucket { - libremetaverse_types::unimplemented_api!("P:LibreMetaverse.TokenBucket.Parent") - } -} +/// C# member: `M:LibreMetaverse.TokenBucket.#ctor(LibreMetaverse.TokenBucket,System.Int32,System.Int32)`. +/// C# member: `M:LibreMetaverse.TokenBucket.RemoveTokens(System.Int32)`. +/// C# member: `M:LibreMetaverse.TokenBucket.RemoveTokens(System.Int32,System.Boolean@)`. +/// C# member: `P:LibreMetaverse.TokenBucket.Content`. +/// C# member: `P:LibreMetaverse.TokenBucket.DripRate`. +/// C# member: `P:LibreMetaverse.TokenBucket.MaxBurst`. +/// C# member: `P:LibreMetaverse.TokenBucket.Parent`. +pub use crate::collections::TokenBucket; /// C# type: `T:LibreMetaverse.UUID`. /// C# member: `F:LibreMetaverse.UUID.Zero`. diff --git a/crates/libremetaverse-types/src/lib.rs b/crates/libremetaverse-types/src/lib.rs index 76a9b73..a41f84b 100644 --- a/crates/libremetaverse-types/src/lib.rs +++ b/crates/libremetaverse-types/src/lib.rs @@ -3,6 +3,7 @@ extern crate self as libremetaverse_types; mod byte_order; +mod collections; mod color4; pub mod compat; mod crc32; diff --git a/tests/api-compile/src/lib.rs b/tests/api-compile/src/lib.rs index 96869fc..418b75a 100644 --- a/tests/api-compile/src/lib.rs +++ b/tests/api-compile/src/lib.rs @@ -173737,83 +173737,113 @@ fn member_29180(value: &mut libremetaverse_types::CRC32) { fn type_2946(_: &libremetaverse_types::CacheDictionary) {} // C# member: `M:LibreMetaverse.CacheDictionary`2.#ctor(System.Int32,LibreMetaverse.ICacheDictionaryRemovalStrategy{`0})`. -fn member_29181() { +fn member_29181() { let _ = libremetaverse_types::CacheDictionary::::new(argument(), argument()); } // C# member: `M:LibreMetaverse.CacheDictionary`2.Add(System.Collections.Generic.KeyValuePair{`0,`1})`. -fn member_29182(value: &mut libremetaverse_types::CacheDictionary) { +fn member_29182( + value: &mut libremetaverse_types::CacheDictionary, +) { let _ = value.add_with_key_value_pair(argument()); } // C# member: `M:LibreMetaverse.CacheDictionary`2.Add(`0,`1)`. -fn member_29183(value: &mut libremetaverse_types::CacheDictionary) { +fn member_29183( + value: &mut libremetaverse_types::CacheDictionary, +) { let _ = value.add_with_t_key_t_value(argument(), argument()); } // C# member: `M:LibreMetaverse.CacheDictionary`2.Clear`. -fn member_29184(value: &mut libremetaverse_types::CacheDictionary) { +fn member_29184( + value: &mut libremetaverse_types::CacheDictionary, +) { let _ = value.clear(); } // C# member: `M:LibreMetaverse.CacheDictionary`2.Contains(System.Collections.Generic.KeyValuePair{`0,`1})`. -fn member_29185(value: &mut libremetaverse_types::CacheDictionary) { +fn member_29185( + value: &mut libremetaverse_types::CacheDictionary, +) { let _ = value.contains(argument()); } // C# member: `M:LibreMetaverse.CacheDictionary`2.ContainsKey(`0)`. -fn member_29186(value: &mut libremetaverse_types::CacheDictionary) { +fn member_29186( + value: &mut libremetaverse_types::CacheDictionary, +) { let _ = value.contains_key(argument()); } // C# member: `M:LibreMetaverse.CacheDictionary`2.CopyTo(System.Collections.Generic.KeyValuePair{`0,`1}[],System.Int32)`. -fn member_29187(value: &mut libremetaverse_types::CacheDictionary) { +fn member_29187( + value: &mut libremetaverse_types::CacheDictionary, +) { let _ = value.copy_to(argument(), argument()); } // C# member: `M:LibreMetaverse.CacheDictionary`2.GetEnumerator`. -fn member_29188(value: &mut libremetaverse_types::CacheDictionary) { +fn member_29188( + value: &mut libremetaverse_types::CacheDictionary, +) { let _ = value.get_enumerator(); } // C# member: `M:LibreMetaverse.CacheDictionary`2.Remove(System.Collections.Generic.KeyValuePair{`0,`1})`. -fn member_29189(value: &mut libremetaverse_types::CacheDictionary) { +fn member_29189( + value: &mut libremetaverse_types::CacheDictionary, +) { let _ = value.remove_with_key_value_pair(argument()); } // C# member: `M:LibreMetaverse.CacheDictionary`2.Remove(`0)`. -fn member_29190(value: &mut libremetaverse_types::CacheDictionary) { +fn member_29190( + value: &mut libremetaverse_types::CacheDictionary, +) { let _ = value.remove_with_t_key(argument()); } // C# member: `M:LibreMetaverse.CacheDictionary`2.TryGetValue(`0,`1@)`. -fn member_29191(value: &mut libremetaverse_types::CacheDictionary) { +fn member_29191( + value: &mut libremetaverse_types::CacheDictionary, +) { let _ = value.try_get_value(argument(), argument()); } // C# member: `P:LibreMetaverse.CacheDictionary`2.Count`. -fn member_29192(value: &mut libremetaverse_types::CacheDictionary) { +fn member_29192( + value: &mut libremetaverse_types::CacheDictionary, +) { let _ = value.count(); } // C# member: `P:LibreMetaverse.CacheDictionary`2.IsReadOnly`. -fn member_29193(value: &mut libremetaverse_types::CacheDictionary) { +fn member_29193( + value: &mut libremetaverse_types::CacheDictionary, +) { let _ = value.is_read_only(); } // C# member: `P:LibreMetaverse.CacheDictionary`2.Item(`0)`. -fn member_29194(value: &mut libremetaverse_types::CacheDictionary) { +fn member_29194( + value: &mut libremetaverse_types::CacheDictionary, +) { let _ = value.item(argument()); let _ = value.set_item(argument(), argument()); } // C# member: `P:LibreMetaverse.CacheDictionary`2.Keys`. -fn member_29195(value: &mut libremetaverse_types::CacheDictionary) { +fn member_29195( + value: &mut libremetaverse_types::CacheDictionary, +) { let _ = value.keys(); } // C# member: `P:LibreMetaverse.CacheDictionary`2.Values`. -fn member_29196(value: &mut libremetaverse_types::CacheDictionary) { +fn member_29196( + value: &mut libremetaverse_types::CacheDictionary, +) { let _ = value.values(); } @@ -173824,28 +173854,28 @@ fn type_2947( } // C# member: `M:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator.Dispose`. -fn member_29197( +fn member_29197( value: &mut libremetaverse_types::CacheDictionaryCacheDictionaryEnumerator, ) { let _ = value.dispose(); } // C# member: `M:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator.MoveNext`. -fn member_29198( +fn member_29198( value: &mut libremetaverse_types::CacheDictionaryCacheDictionaryEnumerator, ) { let _ = value.move_next(); } // C# member: `M:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator.Reset`. -fn member_29199( +fn member_29199( value: &mut libremetaverse_types::CacheDictionaryCacheDictionaryEnumerator, ) { let _ = value.reset(); } // C# member: `P:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator.Current`. -fn member_29200( +fn member_29200( value: &mut libremetaverse_types::CacheDictionaryCacheDictionaryEnumerator, ) { let _ = value.current(); @@ -174087,130 +174117,130 @@ fn type_2950( } // C# member: `M:LibreMetaverse.DoubleDictionary`3.#ctor`. -fn member_29240() { +fn member_29240() { let _ = libremetaverse_types::DoubleDictionary::::new_with_constructor(); } // C# member: `M:LibreMetaverse.DoubleDictionary`3.#ctor(System.Int32)`. -fn member_29241() { +fn member_29241() { let _ = libremetaverse_types::DoubleDictionary::::new_with_int32(argument()); } // C# member: `M:LibreMetaverse.DoubleDictionary`3.Add(`0,`1,`2)`. -fn member_29242( +fn member_29242( value: &mut libremetaverse_types::DoubleDictionary, ) { let _ = value.add(argument(), argument(), argument()); } // C# member: `M:LibreMetaverse.DoubleDictionary`3.Clear`. -fn member_29243( +fn member_29243( value: &mut libremetaverse_types::DoubleDictionary, ) { let _ = value.clear(); } // C# member: `M:LibreMetaverse.DoubleDictionary`3.ContainsKey(`0)`. -fn member_29244( +fn member_29244( value: &mut libremetaverse_types::DoubleDictionary, ) { let _ = value.contains_key_with_t_key1(argument()); } // C# member: `M:LibreMetaverse.DoubleDictionary`3.ContainsKey(`1)`. -fn member_29245( +fn member_29245( value: &mut libremetaverse_types::DoubleDictionary, ) { let _ = value.contains_key_with_t_key2(argument()); } // C# member: `M:LibreMetaverse.DoubleDictionary`3.Dispose`. -fn member_29246( +fn member_29246( value: &mut libremetaverse_types::DoubleDictionary, ) { let _ = value.dispose(); } // C# member: `M:LibreMetaverse.DoubleDictionary`3.FindAll(System.Predicate{`2})`. -fn member_29247( +fn member_29247( value: &mut libremetaverse_types::DoubleDictionary, ) { let _ = value.find_all(argument()); } // C# member: `M:LibreMetaverse.DoubleDictionary`3.FindValue(System.Predicate{`2})`. -fn member_29248( +fn member_29248( value: &mut libremetaverse_types::DoubleDictionary, ) { let _ = value.find_value(argument()); } // C# member: `M:LibreMetaverse.DoubleDictionary`3.ForEach(System.Action{System.Collections.Generic.KeyValuePair{`0,`2}})`. -fn member_29249( +fn member_29249( value: &mut libremetaverse_types::DoubleDictionary, ) { let _ = value.for_each_with_action(argument()); } // C# member: `M:LibreMetaverse.DoubleDictionary`3.ForEach(System.Action{System.Collections.Generic.KeyValuePair{`1,`2}})`. -fn member_29250( +fn member_29250( value: &mut libremetaverse_types::DoubleDictionary, ) { let _ = value.for_each_with_action_4dc2e201(argument()); } // C# member: `M:LibreMetaverse.DoubleDictionary`3.ForEach(System.Action{`2})`. -fn member_29251( +fn member_29251( value: &mut libremetaverse_types::DoubleDictionary, ) { let _ = value.for_each_with_action_b56adc7f(argument()); } // C# member: `M:LibreMetaverse.DoubleDictionary`3.Remove(`0)`. -fn member_29252( +fn member_29252( value: &mut libremetaverse_types::DoubleDictionary, ) { let _ = value.remove_with_t_key1(argument()); } // C# member: `M:LibreMetaverse.DoubleDictionary`3.Remove(`0,`1)`. -fn member_29253( +fn member_29253( value: &mut libremetaverse_types::DoubleDictionary, ) { let _ = value.remove_with_t_key1_t_key2(argument(), argument()); } // C# member: `M:LibreMetaverse.DoubleDictionary`3.Remove(`1)`. -fn member_29254( +fn member_29254( value: &mut libremetaverse_types::DoubleDictionary, ) { let _ = value.remove_with_t_key2(argument()); } // C# member: `M:LibreMetaverse.DoubleDictionary`3.RemoveAll(System.Predicate{`2})`. -fn member_29255( +fn member_29255( value: &mut libremetaverse_types::DoubleDictionary, ) { let _ = value.remove_all(argument()); } // C# member: `M:LibreMetaverse.DoubleDictionary`3.TryGetValue(`0,`2@)`. -fn member_29256( +fn member_29256( value: &mut libremetaverse_types::DoubleDictionary, ) { let _ = value.try_get_value_with_t_key1_t_value(argument(), argument()); } // C# member: `M:LibreMetaverse.DoubleDictionary`3.TryGetValue(`1,`2@)`. -fn member_29257( +fn member_29257( value: &mut libremetaverse_types::DoubleDictionary, ) { let _ = value.try_get_value_with_t_key2_t_value(argument(), argument()); } // C# member: `P:LibreMetaverse.DoubleDictionary`3.Count`. -fn member_29258( +fn member_29258( value: &mut libremetaverse_types::DoubleDictionary, ) { let _ = value.count(); @@ -174220,37 +174250,49 @@ fn member_29258( fn type_2951(_: &libremetaverse_types::EmptyRemovalStrategy) {} // C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.#ctor`. -fn member_29259() { +fn member_29259() { let _ = libremetaverse_types::EmptyRemovalStrategy::::new(); } // C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.Clear`. -fn member_29260(value: &mut libremetaverse_types::EmptyRemovalStrategy) { +fn member_29260( + value: &mut libremetaverse_types::EmptyRemovalStrategy, +) { let _ = value.clear(); } // C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.GetKeyToRemove`. -fn member_29261(value: &mut libremetaverse_types::EmptyRemovalStrategy) { +fn member_29261( + value: &mut libremetaverse_types::EmptyRemovalStrategy, +) { let _ = value.get_key_to_remove(); } // C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.Initialize(System.Int32)`. -fn member_29262(value: &mut libremetaverse_types::EmptyRemovalStrategy) { +fn member_29262( + value: &mut libremetaverse_types::EmptyRemovalStrategy, +) { let _ = value.initialize(argument()); } // C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.KeyAccessed(`0)`. -fn member_29263(value: &mut libremetaverse_types::EmptyRemovalStrategy) { +fn member_29263( + value: &mut libremetaverse_types::EmptyRemovalStrategy, +) { let _ = value.key_accessed(argument()); } // C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.KeyAdded(`0)`. -fn member_29264(value: &mut libremetaverse_types::EmptyRemovalStrategy) { +fn member_29264( + value: &mut libremetaverse_types::EmptyRemovalStrategy, +) { let _ = value.key_added(argument()); } // C# member: `M:LibreMetaverse.EmptyRemovalStrategy`1.KeyRemoved(`0)`. -fn member_29265(value: &mut libremetaverse_types::EmptyRemovalStrategy) { +fn member_29265( + value: &mut libremetaverse_types::EmptyRemovalStrategy, +) { let _ = value.key_removed(argument()); } @@ -174284,82 +174326,112 @@ fn member_29269() { fn type_2954(_: &libremetaverse_types::ExpiringCache) {} // C# member: `M:LibreMetaverse.ExpiringCache`2.#ctor`. -fn member_29270() { +fn member_29270() { let _ = libremetaverse_types::ExpiringCache::::new(); } // C# member: `M:LibreMetaverse.ExpiringCache`2.Add(`0,`1,System.Double)`. -fn member_29271(value: &mut libremetaverse_types::ExpiringCache) { +fn member_29271( + value: &mut libremetaverse_types::ExpiringCache, +) { let _ = value.add_with_t_key_t_value_double(argument(), argument(), argument()); } // C# member: `M:LibreMetaverse.ExpiringCache`2.Add(`0,`1,System.TimeSpan)`. -fn member_29272(value: &mut libremetaverse_types::ExpiringCache) { +fn member_29272( + value: &mut libremetaverse_types::ExpiringCache, +) { let _ = value.add_with_t_key_t_value_time_span(argument(), argument(), argument()); } // C# member: `M:LibreMetaverse.ExpiringCache`2.AddOrUpdate(`0,`1,System.Double)`. -fn member_29273(value: &mut libremetaverse_types::ExpiringCache) { +fn member_29273( + value: &mut libremetaverse_types::ExpiringCache, +) { let _ = value.add_or_update_with_t_key_t_value_double(argument(), argument(), argument()); } // C# member: `M:LibreMetaverse.ExpiringCache`2.AddOrUpdate(`0,`1,System.TimeSpan)`. -fn member_29274(value: &mut libremetaverse_types::ExpiringCache) { +fn member_29274( + value: &mut libremetaverse_types::ExpiringCache, +) { let _ = value.add_or_update_with_t_key_t_value_time_span(argument(), argument(), argument()); } // C# member: `M:LibreMetaverse.ExpiringCache`2.Clear`. -fn member_29275(value: &mut libremetaverse_types::ExpiringCache) { +fn member_29275( + value: &mut libremetaverse_types::ExpiringCache, +) { let _ = value.clear(); } // C# member: `M:LibreMetaverse.ExpiringCache`2.Contains(`0)`. -fn member_29276(value: &mut libremetaverse_types::ExpiringCache) { +fn member_29276( + value: &mut libremetaverse_types::ExpiringCache, +) { let _ = value.contains(argument()); } // C# member: `M:LibreMetaverse.ExpiringCache`2.CopyTo(System.Array,System.Int32)`. -fn member_29277(value: &mut libremetaverse_types::ExpiringCache) { +fn member_29277( + value: &mut libremetaverse_types::ExpiringCache, +) { let _ = value.copy_to(argument(), argument()); } // C# member: `M:LibreMetaverse.ExpiringCache`2.Dispose`. -fn member_29278(value: &mut libremetaverse_types::ExpiringCache) { +fn member_29278( + value: &mut libremetaverse_types::ExpiringCache, +) { let _ = value.dispose(); } // C# member: `M:LibreMetaverse.ExpiringCache`2.Remove(`0)`. -fn member_29279(value: &mut libremetaverse_types::ExpiringCache) { +fn member_29279( + value: &mut libremetaverse_types::ExpiringCache, +) { let _ = value.remove(argument()); } // C# member: `M:LibreMetaverse.ExpiringCache`2.TryGetValue(`0,`1@)`. -fn member_29280(value: &mut libremetaverse_types::ExpiringCache) { +fn member_29280( + value: &mut libremetaverse_types::ExpiringCache, +) { let _ = value.try_get_value(argument(), argument()); } // C# member: `M:LibreMetaverse.ExpiringCache`2.Update(`0,`1)`. -fn member_29281(value: &mut libremetaverse_types::ExpiringCache) { +fn member_29281( + value: &mut libremetaverse_types::ExpiringCache, +) { let _ = value.update_with_t_key_t_value(argument(), argument()); } // C# member: `M:LibreMetaverse.ExpiringCache`2.Update(`0,`1,System.Double)`. -fn member_29282(value: &mut libremetaverse_types::ExpiringCache) { +fn member_29282( + value: &mut libremetaverse_types::ExpiringCache, +) { let _ = value.update_with_t_key_t_value_double(argument(), argument(), argument()); } // C# member: `M:LibreMetaverse.ExpiringCache`2.Update(`0,`1,System.TimeSpan)`. -fn member_29283(value: &mut libremetaverse_types::ExpiringCache) { +fn member_29283( + value: &mut libremetaverse_types::ExpiringCache, +) { let _ = value.update_with_t_key_t_value_time_span(argument(), argument(), argument()); } // C# member: `P:LibreMetaverse.ExpiringCache`2.Count`. -fn member_29284(value: &mut libremetaverse_types::ExpiringCache) { +fn member_29284( + value: &mut libremetaverse_types::ExpiringCache, +) { let _ = value.count(); } // C# member: `P:LibreMetaverse.ExpiringCache`2.Item(`0)`. -fn member_29285(value: &mut libremetaverse_types::ExpiringCache) { +fn member_29285( + value: &mut libremetaverse_types::ExpiringCache, +) { let _ = value.item(argument()); } @@ -174813,37 +174885,49 @@ fn member_29367() { fn type_2962(_: &libremetaverse_types::LruRemovalStrategy) {} // C# member: `M:LibreMetaverse.LruRemovalStrategy`1.#ctor`. -fn member_29368() { +fn member_29368() { let _ = libremetaverse_types::LruRemovalStrategy::::new(); } // C# member: `M:LibreMetaverse.LruRemovalStrategy`1.Clear`. -fn member_29369(value: &mut libremetaverse_types::LruRemovalStrategy) { +fn member_29369( + value: &mut libremetaverse_types::LruRemovalStrategy, +) { let _ = value.clear(); } // C# member: `M:LibreMetaverse.LruRemovalStrategy`1.GetKeyToRemove`. -fn member_29370(value: &mut libremetaverse_types::LruRemovalStrategy) { +fn member_29370( + value: &mut libremetaverse_types::LruRemovalStrategy, +) { let _ = value.get_key_to_remove(); } // C# member: `M:LibreMetaverse.LruRemovalStrategy`1.Initialize(System.Int32)`. -fn member_29371(value: &mut libremetaverse_types::LruRemovalStrategy) { +fn member_29371( + value: &mut libremetaverse_types::LruRemovalStrategy, +) { let _ = value.initialize(argument()); } // C# member: `M:LibreMetaverse.LruRemovalStrategy`1.KeyAccessed(`0)`. -fn member_29372(value: &mut libremetaverse_types::LruRemovalStrategy) { +fn member_29372( + value: &mut libremetaverse_types::LruRemovalStrategy, +) { let _ = value.key_accessed(argument()); } // C# member: `M:LibreMetaverse.LruRemovalStrategy`1.KeyAdded(`0)`. -fn member_29373(value: &mut libremetaverse_types::LruRemovalStrategy) { +fn member_29373( + value: &mut libremetaverse_types::LruRemovalStrategy, +) { let _ = value.key_added(argument()); } // C# member: `M:LibreMetaverse.LruRemovalStrategy`1.KeyRemoved(`0)`. -fn member_29374(value: &mut libremetaverse_types::LruRemovalStrategy) { +fn member_29374( + value: &mut libremetaverse_types::LruRemovalStrategy, +) { let _ = value.key_removed(argument()); } @@ -175252,37 +175336,49 @@ fn member_29452(value: &mut libremetaverse_types::Matrix4) { fn type_2965(_: &libremetaverse_types::MruRemovalStrategy) {} // C# member: `M:LibreMetaverse.MruRemovalStrategy`1.#ctor`. -fn member_29453() { +fn member_29453() { let _ = libremetaverse_types::MruRemovalStrategy::::new(); } // C# member: `M:LibreMetaverse.MruRemovalStrategy`1.Clear`. -fn member_29454(value: &mut libremetaverse_types::MruRemovalStrategy) { +fn member_29454( + value: &mut libremetaverse_types::MruRemovalStrategy, +) { let _ = value.clear(); } // C# member: `M:LibreMetaverse.MruRemovalStrategy`1.GetKeyToRemove`. -fn member_29455(value: &mut libremetaverse_types::MruRemovalStrategy) { +fn member_29455( + value: &mut libremetaverse_types::MruRemovalStrategy, +) { let _ = value.get_key_to_remove(); } // C# member: `M:LibreMetaverse.MruRemovalStrategy`1.Initialize(System.Int32)`. -fn member_29456(value: &mut libremetaverse_types::MruRemovalStrategy) { +fn member_29456( + value: &mut libremetaverse_types::MruRemovalStrategy, +) { let _ = value.initialize(argument()); } // C# member: `M:LibreMetaverse.MruRemovalStrategy`1.KeyAccessed(`0)`. -fn member_29457(value: &mut libremetaverse_types::MruRemovalStrategy) { +fn member_29457( + value: &mut libremetaverse_types::MruRemovalStrategy, +) { let _ = value.key_accessed(argument()); } // C# member: `M:LibreMetaverse.MruRemovalStrategy`1.KeyAdded(`0)`. -fn member_29458(value: &mut libremetaverse_types::MruRemovalStrategy) { +fn member_29458( + value: &mut libremetaverse_types::MruRemovalStrategy, +) { let _ = value.key_added(argument()); } // C# member: `M:LibreMetaverse.MruRemovalStrategy`1.KeyRemoved(`0)`. -fn member_29459(value: &mut libremetaverse_types::MruRemovalStrategy) { +fn member_29459( + value: &mut libremetaverse_types::MruRemovalStrategy, +) { let _ = value.key_removed(argument()); } @@ -175290,24 +175386,24 @@ fn member_29459(value: &mut libremetaverse_types::MruRemovalStrategy fn type_2966(_: &libremetaverse_types::MultiValueDictionary) {} // C# member: `M:LibreMetaverse.MultiValueDictionary`2.#ctor`. -fn member_29460() { +fn member_29460() { let _ = libremetaverse_types::MultiValueDictionary::::new_with_constructor(); } // C# member: `M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}})`. -fn member_29461() { +fn member_29461() { let _ = libremetaverse_types::MultiValueDictionary::::new_with_i_enumerable( argument(), ); } // C# member: `M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}},System.Collections.Generic.IEqualityComparer{`0})`. -fn member_29462() { +fn member_29462() { let _ = libremetaverse_types::MultiValueDictionary::::new_with_i_enumerable_i_equality_comparer(argument(), argument()); } // C# member: `M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Collections.Generic.IEqualityComparer{`0})`. -fn member_29463() { +fn member_29463() { let _ = libremetaverse_types::MultiValueDictionary::::new_with_i_equality_comparer( argument(), @@ -175315,52 +175411,52 @@ fn member_29463() { } // C# member: `M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Int32)`. -fn member_29464() { +fn member_29464() { let _ = libremetaverse_types::MultiValueDictionary::::new_with_int32(argument()); } // C# member: `M:LibreMetaverse.MultiValueDictionary`2.#ctor(System.Int32,System.Collections.Generic.IEqualityComparer{`0})`. -fn member_29465() { +fn member_29465() { let _ = libremetaverse_types::MultiValueDictionary::::new_with_int32_i_equality_comparer(argument(), argument()); } // C# member: `M:LibreMetaverse.MultiValueDictionary`2.Add(`0,`1)`. -fn member_29466( +fn member_29466( value: &mut libremetaverse_types::MultiValueDictionary, ) { let _ = value.add(argument(), argument()); } // C# member: `M:LibreMetaverse.MultiValueDictionary`2.AddRange(`0,System.Collections.Generic.IEnumerable{`1})`. -fn member_29467( +fn member_29467( value: &mut libremetaverse_types::MultiValueDictionary, ) { let _ = value.add_range(argument(), argument()); } // C# member: `M:LibreMetaverse.MultiValueDictionary`2.Clear`. -fn member_29468( +fn member_29468( value: &mut libremetaverse_types::MultiValueDictionary, ) { let _ = value.clear(); } // C# member: `M:LibreMetaverse.MultiValueDictionary`2.Contains(`0,`1)`. -fn member_29469( +fn member_29469( value: &mut libremetaverse_types::MultiValueDictionary, ) { let _ = value.contains(argument(), argument()); } // C# member: `M:LibreMetaverse.MultiValueDictionary`2.ContainsKey(`0)`. -fn member_29470( +fn member_29470( value: &mut libremetaverse_types::MultiValueDictionary, ) { let _ = value.contains_key(argument()); } // C# member: `M:LibreMetaverse.MultiValueDictionary`2.ContainsValue(`1)`. -fn member_29471( +fn member_29471( value: &mut libremetaverse_types::MultiValueDictionary, ) { let _ = value.contains_value(argument()); @@ -175368,8 +175464,8 @@ fn member_29471( // C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1`. fn member_29472< - TKey, - TValue, + TKey: Clone + PartialEq, + TValue: Clone + PartialEq, TValueCollection: libremetaverse_types::compat::Collection + Default, >() { let _ = libremetaverse_types::MultiValueDictionary::::create_with_method::< @@ -175379,8 +175475,8 @@ fn member_29472< // C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}})`. fn member_29473< - TKey, - TValue, + TKey: Clone + PartialEq, + TValue: Clone + PartialEq, TValueCollection: libremetaverse_types::compat::Collection + Default, >() { let _ = libremetaverse_types::MultiValueDictionary::::create_with_i_enumerable::< @@ -175390,8 +175486,8 @@ fn member_29473< // C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}},System.Collections.Generic.IEqualityComparer{`0})`. fn member_29474< - TKey, - TValue, + TKey: Clone + PartialEq, + TValue: Clone + PartialEq, TValueCollection: libremetaverse_types::compat::Collection + Default, >() { let _ = libremetaverse_types::MultiValueDictionary::::create_with_i_enumerable_i_equality_comparer::(argument(), argument()); @@ -175399,8 +175495,8 @@ fn member_29474< // C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}},System.Collections.Generic.IEqualityComparer{`0},System.Func{``0})`. fn member_29475< - TKey, - TValue, + TKey: Clone + PartialEq, + TValue: Clone + PartialEq, TValueCollection: libremetaverse_types::compat::Collection, >() { let _ = libremetaverse_types::MultiValueDictionary::::create_with_i_enumerable_i_equality_comparer_func::(argument(), argument(), argument()); @@ -175408,8 +175504,8 @@ fn member_29475< // C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{`0,System.Collections.Generic.IReadOnlyCollection{`1}}},System.Func{``0})`. fn member_29476< - TKey, - TValue, + TKey: Clone + PartialEq, + TValue: Clone + PartialEq, TValueCollection: libremetaverse_types::compat::Collection, >() { let _ = @@ -175420,8 +175516,8 @@ fn member_29476< // C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEqualityComparer{`0})`. fn member_29477< - TKey, - TValue, + TKey: Clone + PartialEq, + TValue: Clone + PartialEq, TValueCollection: libremetaverse_types::compat::Collection + Default, >() { let _ = @@ -175432,8 +175528,8 @@ fn member_29477< // C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Collections.Generic.IEqualityComparer{`0},System.Func{``0})`. fn member_29478< - TKey, - TValue, + TKey: Clone + PartialEq, + TValue: Clone + PartialEq, TValueCollection: libremetaverse_types::compat::Collection, >() { let _ = libremetaverse_types::MultiValueDictionary::::create_with_i_equality_comparer_func::(argument(), argument()); @@ -175441,8 +175537,8 @@ fn member_29478< // C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Func{``0})`. fn member_29479< - TKey, - TValue, + TKey: Clone + PartialEq, + TValue: Clone + PartialEq, TValueCollection: libremetaverse_types::compat::Collection, >() { let _ = libremetaverse_types::MultiValueDictionary::::create_with_func::< @@ -175452,8 +175548,8 @@ fn member_29479< // C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Int32)`. fn member_29480< - TKey, - TValue, + TKey: Clone + PartialEq, + TValue: Clone + PartialEq, TValueCollection: libremetaverse_types::compat::Collection + Default, >() { let _ = libremetaverse_types::MultiValueDictionary::::create_with_int32::< @@ -175463,8 +175559,8 @@ fn member_29480< // C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Int32,System.Collections.Generic.IEqualityComparer{`0})`. fn member_29481< - TKey, - TValue, + TKey: Clone + PartialEq, + TValue: Clone + PartialEq, TValueCollection: libremetaverse_types::compat::Collection + Default, >() { let _ = libremetaverse_types::MultiValueDictionary::::create_with_int32_i_equality_comparer::(argument(), argument()); @@ -175472,8 +175568,8 @@ fn member_29481< // C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Int32,System.Collections.Generic.IEqualityComparer{`0},System.Func{``0})`. fn member_29482< - TKey, - TValue, + TKey: Clone + PartialEq, + TValue: Clone + PartialEq, TValueCollection: libremetaverse_types::compat::Collection, >() { let _ = libremetaverse_types::MultiValueDictionary::::create_with_int32_i_equality_comparer_func::(argument(), argument(), argument()); @@ -175481,8 +175577,8 @@ fn member_29482< // C# member: `M:LibreMetaverse.MultiValueDictionary`2.Create``1(System.Int32,System.Func{``0})`. fn member_29483< - TKey, - TValue, + TKey: Clone + PartialEq, + TValue: Clone + PartialEq, TValueCollection: libremetaverse_types::compat::Collection, >() { let _ = libremetaverse_types::MultiValueDictionary::::create_with_int32_func::< @@ -175491,56 +175587,56 @@ fn member_29483< } // C# member: `M:LibreMetaverse.MultiValueDictionary`2.GetEnumerator`. -fn member_29484( +fn member_29484( value: &mut libremetaverse_types::MultiValueDictionary, ) { let _ = value.get_enumerator(); } // C# member: `M:LibreMetaverse.MultiValueDictionary`2.Remove(`0)`. -fn member_29485( +fn member_29485( value: &mut libremetaverse_types::MultiValueDictionary, ) { let _ = value.remove_with_t_key(argument()); } // C# member: `M:LibreMetaverse.MultiValueDictionary`2.Remove(`0,`1)`. -fn member_29486( +fn member_29486( value: &mut libremetaverse_types::MultiValueDictionary, ) { let _ = value.remove_with_t_key_t_value(argument(), argument()); } // C# member: `M:LibreMetaverse.MultiValueDictionary`2.TryGetValue(`0,System.Collections.Generic.IReadOnlyCollection{`1}@)`. -fn member_29487( +fn member_29487( value: &mut libremetaverse_types::MultiValueDictionary, ) { let _ = value.try_get_value(argument(), argument()); } // C# member: `P:LibreMetaverse.MultiValueDictionary`2.Count`. -fn member_29488( +fn member_29488( value: &mut libremetaverse_types::MultiValueDictionary, ) { let _ = value.count(); } // C# member: `P:LibreMetaverse.MultiValueDictionary`2.Item(`0)`. -fn member_29489( +fn member_29489( value: &mut libremetaverse_types::MultiValueDictionary, ) { let _ = value.item(argument()); } // C# member: `P:LibreMetaverse.MultiValueDictionary`2.Keys`. -fn member_29490( +fn member_29490( value: &mut libremetaverse_types::MultiValueDictionary, ) { let _ = value.keys(); } // C# member: `P:LibreMetaverse.MultiValueDictionary`2.Values`. -fn member_29491( +fn member_29491( value: &mut libremetaverse_types::MultiValueDictionary, ) { let _ = value.values(); diff --git a/tests/red-suite-baseline.json b/tests/red-suite-baseline.json index 07fee8f..7856867 100644 --- a/tests/red-suite-baseline.json +++ b/tests/red-suite-baseline.json @@ -20,5 +20,5 @@ "LibreMetaverse.Tests/TypeTests.cs::TypeTests.VectorCasting::test", "LibreMetaverse.Tests/UtilsConversionsTests.cs::UtilsConversionsTests.StringToBytes::test" ], - "support_passes": 56 + "support_passes": 62 } diff --git a/tools/generate_api_shims.py b/tools/generate_api_shims.py index 44883f2..ec6302f 100644 --- a/tools/generate_api_shims.py +++ b/tools/generate_api_shims.py @@ -38,13 +38,23 @@ TARGETS = { # implementations. The generated module keeps catalog markers and re-exports # the hand-written type so coverage remains deterministic. NATIVE_TYPES = { + "T:LibreMetaverse.CacheDictionary`2": "crate::collections::CacheDictionary", + "T:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator": "crate::collections::CacheDictionaryCacheDictionaryEnumerator", "T:LibreMetaverse.Color4": "crate::color4::Color4", "T:LibreMetaverse.CRC32": "crate::crc32::CRC32", + "T:LibreMetaverse.DoubleDictionary`3": "crate::collections::DoubleDictionary", + "T:LibreMetaverse.EmptyRemovalStrategy`1": "crate::collections::EmptyRemovalStrategy", "T:LibreMetaverse.EnumInfoAttribute": "crate::enum_compat::EnumInfoAttribute", "T:LibreMetaverse.EnumInfoExtensions": "crate::enum_compat::EnumInfoExtensions", + "T:LibreMetaverse.ExpiringCache`2": "crate::collections::ExpiringCache", + "T:LibreMetaverse.ICacheDictionaryRemovalStrategy`1": "crate::collections::ICacheDictionaryRemovalStrategy", + "T:LibreMetaverse.LruRemovalStrategy`1": "crate::collections::LruRemovalStrategy", "T:LibreMetaverse.Matrix4": "crate::geometry::Matrix4", + "T:LibreMetaverse.MruRemovalStrategy`1": "crate::collections::MruRemovalStrategy", + "T:LibreMetaverse.MultiValueDictionary`2": "crate::collections::MultiValueDictionary", "T:LibreMetaverse.Quaternion": "crate::geometry::Quaternion", "T:LibreMetaverse.Ray": "crate::vectors::Ray", + "T:LibreMetaverse.TokenBucket": "crate::collections::TokenBucket", "T:LibreMetaverse.UUID": "crate::uuid::UUID", "T:LibreMetaverse.Vector2": "crate::vectors::Vector2", "T:LibreMetaverse.Vector3": "crate::vectors::Vector3", @@ -64,6 +74,33 @@ NATIVE_MEMBER_BODIES = { "crate::byte_order::write_double_little_endian(dest, pos, value)", } +NATIVE_OWNER_BOUNDS = { + "T:LibreMetaverse.CacheDictionary`2": { + "TKey": "TKey: Clone + PartialEq", + "TValue": "TValue: Clone + PartialEq", + }, + "T:LibreMetaverse.CacheDictionary`2.CacheDictionaryEnumerator": { + "TKey": "TKey: Clone", + "TValue": "TValue: Clone", + }, + "T:LibreMetaverse.DoubleDictionary`3": { + "TKey1": "TKey1: Clone + PartialEq", + "TKey2": "TKey2: Clone + PartialEq", + "TValue": "TValue: Clone + PartialEq", + }, + "T:LibreMetaverse.EmptyRemovalStrategy`1": {"TKey": "TKey: Clone + PartialEq + Send"}, + "T:LibreMetaverse.ExpiringCache`2": { + "TKey": "TKey: Clone + PartialEq", + "TValue": "TValue: Clone", + }, + "T:LibreMetaverse.LruRemovalStrategy`1": {"TKey": "TKey: Clone + PartialEq + Send"}, + "T:LibreMetaverse.MruRemovalStrategy`1": {"TKey": "TKey: Clone + PartialEq + Send"}, + "T:LibreMetaverse.MultiValueDictionary`2": { + "TKey": "TKey: Clone + PartialEq", + "TValue": "TValue: Clone + PartialEq", + }, +} + MAIN_TARGET = ROOT / "crates/libremetaverse/src/generated.rs" WIRE_NAMESPACES = ( "LibreMetaverse.Assets", @@ -455,7 +492,11 @@ def render_compile_fixture( member_index += 1 row = member_rows[member["doc_id"]] method_names = generic_names(member) - parameters = [*owner_names, *generic_declarations(member, mapper, owner_names)] + owner_bounds = NATIVE_OWNER_BOUNDS.get(item["doc_id"], {}) + parameters = [ + *(owner_bounds.get(name, name) for name in owner_names), + *generic_declarations(member, mapper, owner_names), + ] if member["doc_id"] == "M:LibreMetaverse.Utils.EnumTryParse``1(System.String,``0@)": parameters = [ *owner_names, @@ -858,10 +899,16 @@ def coverage_report(catalog: dict, coverage: dict[str, tuple[int, int, bool]]) - if item["doc_id"] in native_type_ids or member["doc_id"] in NATIVE_MEMBER_BODIES } if native_type_ids or native_member_ids: - status = ( - f"native implementation: {len(native_type_ids):,} types / " - f"{len(native_member_ids):,} members; remaining surface is callable failure-only shims" - ) + if (len(native_type_ids), len(native_member_ids)) == (types, members): + status = ( + f"native implementation: {len(native_type_ids):,} types / " + f"{len(native_member_ids):,} members; no generated shims remain" + ) + else: + status = ( + f"native implementation: {len(native_type_ids):,} types / " + f"{len(native_member_ids):,} members; remaining surface is callable failure-only shims" + ) else: status = "callable failure-only shim" if complete else f"partial callable shim ({got_types:,} types / {got_members:,} members)" total_types += got_types diff --git a/tools/generate_rust_mapping.py b/tools/generate_rust_mapping.py index 9f62b9f..6bd7543 100644 --- a/tools/generate_rust_mapping.py +++ b/tools/generate_rust_mapping.py @@ -189,10 +189,22 @@ MEMBER_TYPE_OVERRIDES = { ), } MEMBER_SIGNATURE_OVERRIDES = { + "M:LibreMetaverse.CacheDictionary`2.CopyTo(System.Collections.Generic.KeyValuePair{`0,`1}[],System.Int32)": ( + "pub fn copy_to(&self, array: &mut [(TKey, Option)], array_index: i32) -> Result<(), crate::Error>", + "shared_self,mutable_borrow,owned", + ), "M:LibreMetaverse.Utils.DoubleToBytes(System.Double,System.Byte[],System.Int32)": ( "pub fn double_to_bytes_with_double_bytes_int32(value: f64, dest: &mut [u8], pos: i32) -> Result<(), crate::Error>", "owned,mutable_borrow,owned", ), + "M:LibreMetaverse.ExpiringCache`2.CopyTo(System.Array,System.Int32)": ( + "pub fn copy_to(&self, array: &mut [(TKey, Option)], start_index: i32) -> Result<(), crate::Error>", + "shared_self,mutable_borrow,owned", + ), + "P:LibreMetaverse.ExpiringCache`2.Item(`0)": ( + "pub fn item(&self, key: TKey) -> Option", + "shared_self,owned", + ), "M:LibreMetaverse.Utils.EnumTryParse``1(System.String,``0@)": ( "pub fn enum_try_parse(str_type: String, result: &mut Option) -> Result", "owned,mutable_borrow",