Implement vector color and ray compatibility

This commit is contained in:
2026-08-08 22:28:48 +00:00
parent 28a6f54f7e
commit 3068e5ee9e
13 changed files with 2724 additions and 1835 deletions

View File

@@ -52,9 +52,12 @@ Running `cargo test --workspace` is intentionally red during the shim stage.
## Native implementation progress ## Native implementation progress
Milestone 04 implementation has begun. `libremetaverse-types` now provides Milestone 04 implementation has begun. `libremetaverse-types` now provides
native UUID, incremental CRC-32, and little-endian floating-point byte helpers. native UUID, incremental CRC-32, little-endian floating-point byte helpers,
UUID protocol bytes use explicit network order while `compat::Guid` conversions Vector2/Vector3/Vector3d/Vector4 arithmetic and serialization, Color4 color
preserve the mixed-endian .NET byte-array layout. The remaining Types surfaces conversion, and Ray storage. UUID protocol bytes use explicit network order
stay visibly failure-only until their owning milestone issues are completed. while `compat::Guid` conversions preserve the mixed-endian .NET byte-array
layout. Vector and color byte encodings are explicitly little-endian and do not
depend on host architecture. The remaining Types surfaces stay visibly
failure-only until their owning milestone issues are completed.
The controlled audit aggregates every expected failure by standardized C# The controlled audit aggregates every expected failure by standardized C#
member ID and rejects unrelated fixture, assertion, compile, or symbol errors. member ID and rejects unrelated fixture, assertion, compile, or symbol errors.

View File

@@ -10879,9 +10879,9 @@ M:LibreMetaverse.Color4.GetFloatBytes method System.Byte[] LibreMetaverse.Color4
M:LibreMetaverse.Color4.GetHashCode method System.Int32 LibreMetaverse.Color4.GetHashCode() libremetaverse-types libremetaverse_types::Color4::get_hash_code pub fn get_hash_code(&self) -> i32 shared_self sync infallible_placeholder direct_snake_case method mapped M:LibreMetaverse.Color4.GetHashCode method System.Int32 LibreMetaverse.Color4.GetHashCode() libremetaverse-types libremetaverse_types::Color4::get_hash_code pub fn get_hash_code(&self) -> i32 shared_self sync infallible_placeholder direct_snake_case method mapped
M:LibreMetaverse.Color4.GetHue method System.Single LibreMetaverse.Color4.GetHue() libremetaverse-types libremetaverse_types::Color4::get_hue pub fn get_hue(&self) -> Result<f32, crate::Error> shared_self sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Color4.GetHue method System.Single LibreMetaverse.Color4.GetHue() libremetaverse-types libremetaverse_types::Color4::get_hue pub fn get_hue(&self) -> Result<f32, crate::Error> shared_self sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Color4.Lerp(LibreMetaverse.Color4,LibreMetaverse.Color4,System.Single) method LibreMetaverse.Color4 LibreMetaverse.Color4.Lerp(LibreMetaverse.Color4 value1, LibreMetaverse.Color4 value2, System.Single amount) libremetaverse-types libremetaverse_types::Color4::lerp pub fn lerp(value1: libremetaverse_types::Color4, value2: libremetaverse_types::Color4, amount: f32) -> Result<libremetaverse_types::Color4, crate::Error> owned,owned,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Color4.Lerp(LibreMetaverse.Color4,LibreMetaverse.Color4,System.Single) method LibreMetaverse.Color4 LibreMetaverse.Color4.Lerp(LibreMetaverse.Color4 value1, LibreMetaverse.Color4 value2, System.Single amount) libremetaverse-types libremetaverse_types::Color4::lerp pub fn lerp(value1: libremetaverse_types::Color4, value2: libremetaverse_types::Color4, amount: f32) -> Result<libremetaverse_types::Color4, crate::Error> owned,owned,owned sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Color4.ToBytes(System.Byte[],System.Int32) method System.Void LibreMetaverse.Color4.ToBytes(System.Byte[] dest, System.Int32 pos) libremetaverse-types libremetaverse_types::Color4::to_bytes_with_bytes_int32 pub fn to_bytes_with_bytes_int32(&self, dest: Vec<u8>, pos: i32) -> Result<(), crate::Error> shared_self,owned,owned sync Result<_, crate::Error> descriptive_overload_name method mapped M:LibreMetaverse.Color4.ToBytes(System.Byte[],System.Int32) method System.Void LibreMetaverse.Color4.ToBytes(System.Byte[] dest, System.Int32 pos) libremetaverse-types libremetaverse_types::Color4::to_bytes_with_bytes_int32 pub fn to_bytes_with_bytes_int32(&self, dest: &mut [u8], pos: i32) -> Result<(), crate::Error> shared_self,mutable_borrow,owned sync Result<_, crate::Error> descriptive_overload_name method mapped
M:LibreMetaverse.Color4.ToBytes(System.Byte[],System.Int32,System.Boolean) method System.Void LibreMetaverse.Color4.ToBytes(System.Byte[] dest, System.Int32 pos, System.Boolean inverted) libremetaverse-types libremetaverse_types::Color4::to_bytes_with_bytes_int32_boolean pub fn to_bytes_with_bytes_int32_boolean(&self, dest: Vec<u8>, pos: i32, inverted: bool) -> Result<(), crate::Error> shared_self,owned,owned,owned sync Result<_, crate::Error> descriptive_overload_name method mapped M:LibreMetaverse.Color4.ToBytes(System.Byte[],System.Int32,System.Boolean) method System.Void LibreMetaverse.Color4.ToBytes(System.Byte[] dest, System.Int32 pos, System.Boolean inverted) libremetaverse-types libremetaverse_types::Color4::to_bytes_with_bytes_int32_boolean pub fn to_bytes_with_bytes_int32_boolean(&self, dest: &mut [u8], pos: i32, inverted: bool) -> Result<(), crate::Error> shared_self,mutable_borrow,owned,owned sync Result<_, crate::Error> descriptive_overload_name method mapped
M:LibreMetaverse.Color4.ToFloatBytes(System.Byte[],System.Int32) method System.Void LibreMetaverse.Color4.ToFloatBytes(System.Byte[] dest, System.Int32 pos) libremetaverse-types libremetaverse_types::Color4::to_float_bytes pub fn to_float_bytes(&self, dest: Vec<u8>, pos: i32) -> Result<(), crate::Error> shared_self,owned,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Color4.ToFloatBytes(System.Byte[],System.Int32) method System.Void LibreMetaverse.Color4.ToFloatBytes(System.Byte[] dest, System.Int32 pos) libremetaverse-types libremetaverse_types::Color4::to_float_bytes pub fn to_float_bytes(&self, dest: &mut [u8], pos: i32) -> Result<(), crate::Error> shared_self,mutable_borrow,owned sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Color4.ToRGBString method System.String LibreMetaverse.Color4.ToRGBString() libremetaverse-types libremetaverse_types::Color4::to_rgb_string pub fn to_rgb_string(&self) -> Result<String, crate::Error> shared_self sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Color4.ToRGBString method System.String LibreMetaverse.Color4.ToRGBString() libremetaverse-types libremetaverse_types::Color4::to_rgb_string pub fn to_rgb_string(&self) -> Result<String, crate::Error> shared_self sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Color4.ToString method System.String LibreMetaverse.Color4.ToString() libremetaverse-types libremetaverse_types::Color4::to_string pub fn to_string(&self) -> String shared_self sync infallible_placeholder direct_snake_case method mapped M:LibreMetaverse.Color4.ToString method System.String LibreMetaverse.Color4.ToString() libremetaverse-types libremetaverse_types::Color4::to_string pub fn to_string(&self) -> String shared_self sync infallible_placeholder direct_snake_case method mapped
M:LibreMetaverse.Color4.op_Addition(LibreMetaverse.Color4,LibreMetaverse.Color4) method LibreMetaverse.Color4 LibreMetaverse.Color4.op_Addition(LibreMetaverse.Color4 lhs, LibreMetaverse.Color4 rhs) libremetaverse-types libremetaverse_types::Color4::add pub fn add(lhs: libremetaverse_types::Color4, rhs: libremetaverse_types::Color4) -> libremetaverse_types::Color4 owned,owned sync infallible_placeholder direct_snake_case method mapped M:LibreMetaverse.Color4.op_Addition(LibreMetaverse.Color4,LibreMetaverse.Color4) method LibreMetaverse.Color4 LibreMetaverse.Color4.op_Addition(LibreMetaverse.Color4 lhs, LibreMetaverse.Color4 rhs) libremetaverse-types libremetaverse_types::Color4::add pub fn add(lhs: libremetaverse_types::Color4, rhs: libremetaverse_types::Color4) -> libremetaverse_types::Color4 owned,owned sync infallible_placeholder direct_snake_case method mapped
@@ -25231,7 +25231,7 @@ M:LibreMetaverse.Vector2.Normalize(LibreMetaverse.Vector2) method LibreMetaverse
M:LibreMetaverse.Vector2.Parse(System.String) method LibreMetaverse.Vector2 LibreMetaverse.Vector2.Parse(System.String val) libremetaverse-types libremetaverse_types::Vector2::parse pub fn parse(val: String) -> Result<libremetaverse_types::Vector2, crate::Error> owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector2.Parse(System.String) method LibreMetaverse.Vector2 LibreMetaverse.Vector2.Parse(System.String val) libremetaverse-types libremetaverse_types::Vector2::parse pub fn parse(val: String) -> Result<libremetaverse_types::Vector2, crate::Error> owned sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector2.SmoothStep(LibreMetaverse.Vector2,LibreMetaverse.Vector2,System.Single) method LibreMetaverse.Vector2 LibreMetaverse.Vector2.SmoothStep(LibreMetaverse.Vector2 value1, LibreMetaverse.Vector2 value2, System.Single amount) libremetaverse-types libremetaverse_types::Vector2::smooth_step pub fn smooth_step(value1: libremetaverse_types::Vector2, value2: libremetaverse_types::Vector2, amount: f32) -> Result<libremetaverse_types::Vector2, crate::Error> owned,owned,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector2.SmoothStep(LibreMetaverse.Vector2,LibreMetaverse.Vector2,System.Single) method LibreMetaverse.Vector2 LibreMetaverse.Vector2.SmoothStep(LibreMetaverse.Vector2 value1, LibreMetaverse.Vector2 value2, System.Single amount) libremetaverse-types libremetaverse_types::Vector2::smooth_step pub fn smooth_step(value1: libremetaverse_types::Vector2, value2: libremetaverse_types::Vector2, amount: f32) -> Result<libremetaverse_types::Vector2, crate::Error> owned,owned,owned sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector2.Subtract(LibreMetaverse.Vector2,LibreMetaverse.Vector2) method LibreMetaverse.Vector2 LibreMetaverse.Vector2.Subtract(LibreMetaverse.Vector2 value1, LibreMetaverse.Vector2 value2) libremetaverse-types libremetaverse_types::Vector2::subtract pub fn subtract(value1: libremetaverse_types::Vector2, value2: libremetaverse_types::Vector2) -> Result<libremetaverse_types::Vector2, crate::Error> owned,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector2.Subtract(LibreMetaverse.Vector2,LibreMetaverse.Vector2) method LibreMetaverse.Vector2 LibreMetaverse.Vector2.Subtract(LibreMetaverse.Vector2 value1, LibreMetaverse.Vector2 value2) libremetaverse-types libremetaverse_types::Vector2::subtract pub fn subtract(value1: libremetaverse_types::Vector2, value2: libremetaverse_types::Vector2) -> Result<libremetaverse_types::Vector2, crate::Error> owned,owned sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector2.ToBytes(System.Byte[],System.Int32) method System.Void LibreMetaverse.Vector2.ToBytes(System.Byte[] dest, System.Int32 pos) libremetaverse-types libremetaverse_types::Vector2::to_bytes pub fn to_bytes(&self, dest: Vec<u8>, pos: i32) -> Result<(), crate::Error> shared_self,owned,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector2.ToBytes(System.Byte[],System.Int32) method System.Void LibreMetaverse.Vector2.ToBytes(System.Byte[] dest, System.Int32 pos) libremetaverse-types libremetaverse_types::Vector2::to_bytes pub fn to_bytes(&self, dest: &mut [u8], pos: i32) -> Result<(), crate::Error> shared_self,mutable_borrow,owned sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector2.ToRawString method System.String LibreMetaverse.Vector2.ToRawString() libremetaverse-types libremetaverse_types::Vector2::to_raw_string pub fn to_raw_string(&self) -> Result<String, crate::Error> shared_self sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector2.ToRawString method System.String LibreMetaverse.Vector2.ToRawString() libremetaverse-types libremetaverse_types::Vector2::to_raw_string pub fn to_raw_string(&self) -> Result<String, crate::Error> shared_self sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector2.ToString method System.String LibreMetaverse.Vector2.ToString() libremetaverse-types libremetaverse_types::Vector2::to_string pub fn to_string(&self) -> String shared_self sync infallible_placeholder direct_snake_case method mapped M:LibreMetaverse.Vector2.ToString method System.String LibreMetaverse.Vector2.ToString() libremetaverse-types libremetaverse_types::Vector2::to_string pub fn to_string(&self) -> String shared_self sync infallible_placeholder direct_snake_case method mapped
M:LibreMetaverse.Vector2.Transform(LibreMetaverse.Vector2,LibreMetaverse.Matrix4) method LibreMetaverse.Vector2 LibreMetaverse.Vector2.Transform(LibreMetaverse.Vector2 position, LibreMetaverse.Matrix4 matrix) libremetaverse-types libremetaverse_types::Vector2::transform pub fn transform(position: libremetaverse_types::Vector2, matrix: libremetaverse_types::Matrix4) -> Result<libremetaverse_types::Vector2, crate::Error> owned,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector2.Transform(LibreMetaverse.Vector2,LibreMetaverse.Matrix4) method LibreMetaverse.Vector2 LibreMetaverse.Vector2.Transform(LibreMetaverse.Vector2 position, LibreMetaverse.Matrix4 matrix) libremetaverse-types libremetaverse_types::Vector2::transform pub fn transform(position: libremetaverse_types::Vector2, matrix: libremetaverse_types::Matrix4) -> Result<libremetaverse_types::Vector2, crate::Error> owned,owned sync Result<_, crate::Error> direct_snake_case method mapped
@@ -25281,7 +25281,7 @@ M:LibreMetaverse.Vector3.Parse(System.String) method LibreMetaverse.Vector3 Libr
M:LibreMetaverse.Vector3.RotationBetween(LibreMetaverse.Vector3,LibreMetaverse.Vector3) method LibreMetaverse.Quaternion LibreMetaverse.Vector3.RotationBetween(LibreMetaverse.Vector3 a, LibreMetaverse.Vector3 b) libremetaverse-types libremetaverse_types::Vector3::rotation_between pub fn rotation_between(a: libremetaverse_types::Vector3, b: libremetaverse_types::Vector3) -> Result<libremetaverse_types::Quaternion, crate::Error> owned,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector3.RotationBetween(LibreMetaverse.Vector3,LibreMetaverse.Vector3) method LibreMetaverse.Quaternion LibreMetaverse.Vector3.RotationBetween(LibreMetaverse.Vector3 a, LibreMetaverse.Vector3 b) libremetaverse-types libremetaverse_types::Vector3::rotation_between pub fn rotation_between(a: libremetaverse_types::Vector3, b: libremetaverse_types::Vector3) -> Result<libremetaverse_types::Quaternion, crate::Error> owned,owned sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector3.SmoothStep(LibreMetaverse.Vector3,LibreMetaverse.Vector3,System.Single) method LibreMetaverse.Vector3 LibreMetaverse.Vector3.SmoothStep(LibreMetaverse.Vector3 value1, LibreMetaverse.Vector3 value2, System.Single amount) libremetaverse-types libremetaverse_types::Vector3::smooth_step pub fn smooth_step(value1: libremetaverse_types::Vector3, value2: libremetaverse_types::Vector3, amount: f32) -> Result<libremetaverse_types::Vector3, crate::Error> owned,owned,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector3.SmoothStep(LibreMetaverse.Vector3,LibreMetaverse.Vector3,System.Single) method LibreMetaverse.Vector3 LibreMetaverse.Vector3.SmoothStep(LibreMetaverse.Vector3 value1, LibreMetaverse.Vector3 value2, System.Single amount) libremetaverse-types libremetaverse_types::Vector3::smooth_step pub fn smooth_step(value1: libremetaverse_types::Vector3, value2: libremetaverse_types::Vector3, amount: f32) -> Result<libremetaverse_types::Vector3, crate::Error> owned,owned,owned sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector3.Subtract(LibreMetaverse.Vector3,LibreMetaverse.Vector3) method LibreMetaverse.Vector3 LibreMetaverse.Vector3.Subtract(LibreMetaverse.Vector3 value1, LibreMetaverse.Vector3 value2) libremetaverse-types libremetaverse_types::Vector3::subtract pub fn subtract(value1: libremetaverse_types::Vector3, value2: libremetaverse_types::Vector3) -> Result<libremetaverse_types::Vector3, crate::Error> owned,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector3.Subtract(LibreMetaverse.Vector3,LibreMetaverse.Vector3) method LibreMetaverse.Vector3 LibreMetaverse.Vector3.Subtract(LibreMetaverse.Vector3 value1, LibreMetaverse.Vector3 value2) libremetaverse-types libremetaverse_types::Vector3::subtract pub fn subtract(value1: libremetaverse_types::Vector3, value2: libremetaverse_types::Vector3) -> Result<libremetaverse_types::Vector3, crate::Error> owned,owned sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector3.ToBytes(System.Byte[],System.Int32) method System.Void LibreMetaverse.Vector3.ToBytes(System.Byte[] dest, System.Int32 pos) libremetaverse-types libremetaverse_types::Vector3::to_bytes pub fn to_bytes(&self, dest: Vec<u8>, pos: i32) -> Result<(), crate::Error> shared_self,owned,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector3.ToBytes(System.Byte[],System.Int32) method System.Void LibreMetaverse.Vector3.ToBytes(System.Byte[] dest, System.Int32 pos) libremetaverse-types libremetaverse_types::Vector3::to_bytes pub fn to_bytes(&self, dest: &mut [u8], pos: i32) -> Result<(), crate::Error> shared_self,mutable_borrow,owned sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector3.ToRawString method System.String LibreMetaverse.Vector3.ToRawString() libremetaverse-types libremetaverse_types::Vector3::to_raw_string pub fn to_raw_string(&self) -> Result<String, crate::Error> shared_self sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector3.ToRawString method System.String LibreMetaverse.Vector3.ToRawString() libremetaverse-types libremetaverse_types::Vector3::to_raw_string pub fn to_raw_string(&self) -> Result<String, crate::Error> shared_self sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector3.ToString method System.String LibreMetaverse.Vector3.ToString() libremetaverse-types libremetaverse_types::Vector3::to_string pub fn to_string(&self) -> String shared_self sync infallible_placeholder direct_snake_case method mapped M:LibreMetaverse.Vector3.ToString method System.String LibreMetaverse.Vector3.ToString() libremetaverse-types libremetaverse_types::Vector3::to_string pub fn to_string(&self) -> String shared_self sync infallible_placeholder direct_snake_case method mapped
M:LibreMetaverse.Vector3.Transform(LibreMetaverse.Vector3,LibreMetaverse.Matrix4) method LibreMetaverse.Vector3 LibreMetaverse.Vector3.Transform(LibreMetaverse.Vector3 position, LibreMetaverse.Matrix4 matrix) libremetaverse-types libremetaverse_types::Vector3::transform pub fn transform(position: libremetaverse_types::Vector3, matrix: libremetaverse_types::Matrix4) -> Result<libremetaverse_types::Vector3, crate::Error> owned,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector3.Transform(LibreMetaverse.Vector3,LibreMetaverse.Matrix4) method LibreMetaverse.Vector3 LibreMetaverse.Vector3.Transform(LibreMetaverse.Vector3 position, LibreMetaverse.Matrix4 matrix) libremetaverse-types libremetaverse_types::Vector3::transform pub fn transform(position: libremetaverse_types::Vector3, matrix: libremetaverse_types::Matrix4) -> Result<libremetaverse_types::Vector3, crate::Error> owned,owned sync Result<_, crate::Error> direct_snake_case method mapped
@@ -25334,7 +25334,7 @@ M:LibreMetaverse.Vector3d.Normalize(LibreMetaverse.Vector3d) method LibreMetaver
M:LibreMetaverse.Vector3d.Parse(System.String) method LibreMetaverse.Vector3d LibreMetaverse.Vector3d.Parse(System.String val) libremetaverse-types libremetaverse_types::Vector3d::parse pub fn parse(val: String) -> Result<libremetaverse_types::Vector3d, crate::Error> owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector3d.Parse(System.String) method LibreMetaverse.Vector3d LibreMetaverse.Vector3d.Parse(System.String val) libremetaverse-types libremetaverse_types::Vector3d::parse pub fn parse(val: String) -> Result<libremetaverse_types::Vector3d, crate::Error> owned sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector3d.SmoothStep(LibreMetaverse.Vector3d,LibreMetaverse.Vector3d,System.Double) method LibreMetaverse.Vector3d LibreMetaverse.Vector3d.SmoothStep(LibreMetaverse.Vector3d value1, LibreMetaverse.Vector3d value2, System.Double amount) libremetaverse-types libremetaverse_types::Vector3d::smooth_step pub fn smooth_step(value1: libremetaverse_types::Vector3d, value2: libremetaverse_types::Vector3d, amount: f64) -> Result<libremetaverse_types::Vector3d, crate::Error> owned,owned,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector3d.SmoothStep(LibreMetaverse.Vector3d,LibreMetaverse.Vector3d,System.Double) method LibreMetaverse.Vector3d LibreMetaverse.Vector3d.SmoothStep(LibreMetaverse.Vector3d value1, LibreMetaverse.Vector3d value2, System.Double amount) libremetaverse-types libremetaverse_types::Vector3d::smooth_step pub fn smooth_step(value1: libremetaverse_types::Vector3d, value2: libremetaverse_types::Vector3d, amount: f64) -> Result<libremetaverse_types::Vector3d, crate::Error> owned,owned,owned sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector3d.Subtract(LibreMetaverse.Vector3d,LibreMetaverse.Vector3d) method LibreMetaverse.Vector3d LibreMetaverse.Vector3d.Subtract(LibreMetaverse.Vector3d value1, LibreMetaverse.Vector3d value2) libremetaverse-types libremetaverse_types::Vector3d::subtract pub fn subtract(value1: libremetaverse_types::Vector3d, value2: libremetaverse_types::Vector3d) -> Result<libremetaverse_types::Vector3d, crate::Error> owned,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector3d.Subtract(LibreMetaverse.Vector3d,LibreMetaverse.Vector3d) method LibreMetaverse.Vector3d LibreMetaverse.Vector3d.Subtract(LibreMetaverse.Vector3d value1, LibreMetaverse.Vector3d value2) libremetaverse-types libremetaverse_types::Vector3d::subtract pub fn subtract(value1: libremetaverse_types::Vector3d, value2: libremetaverse_types::Vector3d) -> Result<libremetaverse_types::Vector3d, crate::Error> owned,owned sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector3d.ToBytes(System.Byte[],System.Int32) method System.Void LibreMetaverse.Vector3d.ToBytes(System.Byte[] dest, System.Int32 pos) libremetaverse-types libremetaverse_types::Vector3d::to_bytes pub fn to_bytes(&self, dest: Vec<u8>, pos: i32) -> Result<(), crate::Error> shared_self,owned,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector3d.ToBytes(System.Byte[],System.Int32) method System.Void LibreMetaverse.Vector3d.ToBytes(System.Byte[] dest, System.Int32 pos) libremetaverse-types libremetaverse_types::Vector3d::to_bytes pub fn to_bytes(&self, dest: &mut [u8], pos: i32) -> Result<(), crate::Error> shared_self,mutable_borrow,owned sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector3d.ToRawString method System.String LibreMetaverse.Vector3d.ToRawString() libremetaverse-types libremetaverse_types::Vector3d::to_raw_string pub fn to_raw_string(&self) -> Result<String, crate::Error> shared_self sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector3d.ToRawString method System.String LibreMetaverse.Vector3d.ToRawString() libremetaverse-types libremetaverse_types::Vector3d::to_raw_string pub fn to_raw_string(&self) -> Result<String, crate::Error> shared_self sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector3d.ToString method System.String LibreMetaverse.Vector3d.ToString() libremetaverse-types libremetaverse_types::Vector3d::to_string pub fn to_string(&self) -> String shared_self sync infallible_placeholder direct_snake_case method mapped M:LibreMetaverse.Vector3d.ToString method System.String LibreMetaverse.Vector3d.ToString() libremetaverse-types libremetaverse_types::Vector3d::to_string pub fn to_string(&self) -> String shared_self sync infallible_placeholder direct_snake_case method mapped
M:LibreMetaverse.Vector3d.TryParse(System.String,LibreMetaverse.Vector3d@) method System.Boolean LibreMetaverse.Vector3d.TryParse(System.String val, out LibreMetaverse.Vector3d& result) libremetaverse-types libremetaverse_types::Vector3d::try_parse pub fn try_parse(val: String, result: &mut libremetaverse_types::Vector3d) -> bool owned,mutable_output sync infallible_placeholder direct_snake_case method mapped M:LibreMetaverse.Vector3d.TryParse(System.String,LibreMetaverse.Vector3d@) method System.Boolean LibreMetaverse.Vector3d.TryParse(System.String val, out LibreMetaverse.Vector3d& result) libremetaverse-types libremetaverse_types::Vector3d::try_parse pub fn try_parse(val: String, result: &mut libremetaverse_types::Vector3d) -> bool owned,mutable_output sync infallible_placeholder direct_snake_case method mapped
@@ -25383,7 +25383,7 @@ M:LibreMetaverse.Vector4.Normalize(LibreMetaverse.Vector4) method LibreMetaverse
M:LibreMetaverse.Vector4.Parse(System.String) method LibreMetaverse.Vector4 LibreMetaverse.Vector4.Parse(System.String val) libremetaverse-types libremetaverse_types::Vector4::parse pub fn parse(val: String) -> Result<libremetaverse_types::Vector4, crate::Error> owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector4.Parse(System.String) method LibreMetaverse.Vector4 LibreMetaverse.Vector4.Parse(System.String val) libremetaverse-types libremetaverse_types::Vector4::parse pub fn parse(val: String) -> Result<libremetaverse_types::Vector4, crate::Error> owned sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector4.SmoothStep(LibreMetaverse.Vector4,LibreMetaverse.Vector4,System.Single) method LibreMetaverse.Vector4 LibreMetaverse.Vector4.SmoothStep(LibreMetaverse.Vector4 value1, LibreMetaverse.Vector4 value2, System.Single amount) libremetaverse-types libremetaverse_types::Vector4::smooth_step pub fn smooth_step(value1: libremetaverse_types::Vector4, value2: libremetaverse_types::Vector4, amount: f32) -> Result<libremetaverse_types::Vector4, crate::Error> owned,owned,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector4.SmoothStep(LibreMetaverse.Vector4,LibreMetaverse.Vector4,System.Single) method LibreMetaverse.Vector4 LibreMetaverse.Vector4.SmoothStep(LibreMetaverse.Vector4 value1, LibreMetaverse.Vector4 value2, System.Single amount) libremetaverse-types libremetaverse_types::Vector4::smooth_step pub fn smooth_step(value1: libremetaverse_types::Vector4, value2: libremetaverse_types::Vector4, amount: f32) -> Result<libremetaverse_types::Vector4, crate::Error> owned,owned,owned sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector4.Subtract(LibreMetaverse.Vector4,LibreMetaverse.Vector4) method LibreMetaverse.Vector4 LibreMetaverse.Vector4.Subtract(LibreMetaverse.Vector4 value1, LibreMetaverse.Vector4 value2) libremetaverse-types libremetaverse_types::Vector4::subtract pub fn subtract(value1: libremetaverse_types::Vector4, value2: libremetaverse_types::Vector4) -> Result<libremetaverse_types::Vector4, crate::Error> owned,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector4.Subtract(LibreMetaverse.Vector4,LibreMetaverse.Vector4) method LibreMetaverse.Vector4 LibreMetaverse.Vector4.Subtract(LibreMetaverse.Vector4 value1, LibreMetaverse.Vector4 value2) libremetaverse-types libremetaverse_types::Vector4::subtract pub fn subtract(value1: libremetaverse_types::Vector4, value2: libremetaverse_types::Vector4) -> Result<libremetaverse_types::Vector4, crate::Error> owned,owned sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector4.ToBytes(System.Byte[],System.Int32) method System.Void LibreMetaverse.Vector4.ToBytes(System.Byte[] dest, System.Int32 pos) libremetaverse-types libremetaverse_types::Vector4::to_bytes pub fn to_bytes(&self, dest: Vec<u8>, pos: i32) -> Result<(), crate::Error> shared_self,owned,owned sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector4.ToBytes(System.Byte[],System.Int32) method System.Void LibreMetaverse.Vector4.ToBytes(System.Byte[] dest, System.Int32 pos) libremetaverse-types libremetaverse_types::Vector4::to_bytes pub fn to_bytes(&self, dest: &mut [u8], pos: i32) -> Result<(), crate::Error> shared_self,mutable_borrow,owned sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector4.ToRawString method System.String LibreMetaverse.Vector4.ToRawString() libremetaverse-types libremetaverse_types::Vector4::to_raw_string pub fn to_raw_string(&self) -> Result<String, crate::Error> shared_self sync Result<_, crate::Error> direct_snake_case method mapped M:LibreMetaverse.Vector4.ToRawString method System.String LibreMetaverse.Vector4.ToRawString() libremetaverse-types libremetaverse_types::Vector4::to_raw_string pub fn to_raw_string(&self) -> Result<String, crate::Error> shared_self sync Result<_, crate::Error> direct_snake_case method mapped
M:LibreMetaverse.Vector4.ToString method System.String LibreMetaverse.Vector4.ToString() libremetaverse-types libremetaverse_types::Vector4::to_string pub fn to_string(&self) -> String shared_self sync infallible_placeholder direct_snake_case method mapped M:LibreMetaverse.Vector4.ToString method System.String LibreMetaverse.Vector4.ToString() libremetaverse-types libremetaverse_types::Vector4::to_string pub fn to_string(&self) -> String shared_self sync infallible_placeholder direct_snake_case method mapped
M:LibreMetaverse.Vector4.Transform(LibreMetaverse.Vector2,LibreMetaverse.Matrix4) method LibreMetaverse.Vector4 LibreMetaverse.Vector4.Transform(LibreMetaverse.Vector2 position, LibreMetaverse.Matrix4 matrix) libremetaverse-types libremetaverse_types::Vector4::transform_with_vector2_matrix4 pub fn transform_with_vector2_matrix4(position: libremetaverse_types::Vector2, matrix: libremetaverse_types::Matrix4) -> Result<libremetaverse_types::Vector4, crate::Error> owned,owned sync Result<_, crate::Error> descriptive_overload_name method mapped M:LibreMetaverse.Vector4.Transform(LibreMetaverse.Vector2,LibreMetaverse.Matrix4) method LibreMetaverse.Vector4 LibreMetaverse.Vector4.Transform(LibreMetaverse.Vector2 position, LibreMetaverse.Matrix4 matrix) libremetaverse-types libremetaverse_types::Vector4::transform_with_vector2_matrix4 pub fn transform_with_vector2_matrix4(position: libremetaverse_types::Vector2, matrix: libremetaverse_types::Matrix4) -> Result<libremetaverse_types::Vector4, crate::Error> owned,owned sync Result<_, crate::Error> descriptive_overload_name method mapped
Can't render this file because it is too large.

View File

@@ -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.MeshFoundry` | 1 | 14 | callable failure-only shim |
| `LibreMetaverse.Rendering.Simple` | 1 | 6 | callable failure-only shim | | `LibreMetaverse.Rendering.Simple` | 1 | 6 | callable failure-only shim |
| `LibreMetaverse.StructuredData` | 16 | 295 | callable failure-only shim | | `LibreMetaverse.StructuredData` | 16 | 295 | callable failure-only shim |
| `LibreMetaverse.Types` | 45 | 942 | native implementation: 2 types / 34 members; remaining surface is callable failure-only shims | | `LibreMetaverse.Types` | 45 | 942 | native implementation: 8 types / 300 members; remaining surface is callable failure-only shims |
| `LibreMetaverse.Utilities` | 3 | 13 | callable failure-only shim | | `LibreMetaverse.Utilities` | 3 | 13 | callable failure-only shim |
| `LibreMetaverse.Voice.Vivox` | 64 | 531 | callable failure-only shim | | `LibreMetaverse.Voice.Vivox` | 64 | 531 | callable failure-only shim |
| `LibreMetaverse.Voice.WebRTC` | 12 | 210 | callable failure-only shim | | `LibreMetaverse.Voice.WebRTC` | 12 | 210 | callable failure-only shim |

View File

@@ -0,0 +1,429 @@
//! Native four-channel color compatible with `LibreMetaverse`'s `Color4`.
#![allow(clippy::cast_possible_truncation)] // Explicit C# numeric conversions are part of the API.
#![allow(clippy::cast_sign_loss)] // FloatToByte clamps before the reference-compatible cast.
#![allow(clippy::float_cmp)] // Exact component equality is required by the reference type.
#![allow(clippy::inherent_to_string)] // The mapped C# method is named ToString.
#![allow(clippy::items_after_statements)] // Constants stay next to their compatibility formulas.
#![allow(clippy::many_single_char_names)] // Color/HSV formulas use the reference channel names.
#![allow(clippy::missing_errors_doc)] // Result shapes are fixed by the public compatibility map.
#![allow(clippy::must_use_candidate)] // Attributes are not part of the mapped C# surface.
#![allow(clippy::needless_pass_by_value)] // Owned arguments mirror mapped C# value parameters.
#![allow(clippy::should_implement_trait)] // Operator entry points have fixed generated names.
use crate::Error;
use crate::compat::Object;
use crate::math_compat::{
checked_range, clamp_f32, compare_f32, format_f32, hash_f32, lerp_f32, max_f32, min_f32,
};
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Color4 {
pub r: f32,
pub g: f32,
pub b: f32,
pub a: f32,
}
impl Color4 {
#[must_use]
pub const fn black() -> Self {
Self {
r: 0.0,
g: 0.0,
b: 0.0,
a: 1.0,
}
}
#[must_use]
pub const fn white() -> Self {
Self {
r: 1.0,
g: 1.0,
b: 1.0,
a: 1.0,
}
}
pub fn new_with_byte_byte_byte_byte(r: u8, g: u8, b: u8, a: u8) -> Result<Self, Error> {
const QUANTA: f32 = 1.0 / 255.0;
Ok(Self {
r: f32::from(r) * QUANTA,
g: f32::from(g) * QUANTA,
b: f32::from(b) * QUANTA,
a: f32::from(a) * QUANTA,
})
}
pub fn new_with_single_single_single_single(
r: f32,
g: f32,
b: f32,
a: f32,
) -> Result<Self, Error> {
if r > 1.0 || g > 1.0 || b > 1.0 || a > 1.0 {
return Err(Error::Argument);
}
Ok(Self {
r: clamp_f32(r, 0.0, 1.0),
g: clamp_f32(g, 0.0, 1.0),
b: clamp_f32(b, 0.0, 1.0),
a: clamp_f32(a, 0.0, 1.0),
})
}
pub fn new_with_bytes_int32_boolean(
bytes: Vec<u8>,
pos: i32,
inverted: bool,
) -> Result<Self, Error> {
Self::from_bytes_slice(&bytes, pos, inverted, false)
}
pub fn new_with_bytes_int32_boolean_boolean(
bytes: Vec<u8>,
pos: i32,
inverted: bool,
alpha_inverted: bool,
) -> Result<Self, Error> {
Self::from_bytes_slice(&bytes, pos, inverted, alpha_inverted)
}
fn from_bytes_slice(
bytes: &[u8],
pos: i32,
inverted: bool,
alpha_inverted: bool,
) -> Result<Self, Error> {
let range = checked_range(pos, 4, bytes.len())?;
let values = &bytes[range];
const QUANTA: f32 = 1.0 / 255.0;
let channel = |value: u8| f32::from(if inverted { 255 - value } else { value }) * QUANTA;
let mut result = Self {
r: channel(values[0]),
g: channel(values[1]),
b: channel(values[2]),
a: channel(values[3]),
};
if alpha_inverted {
result.a = 1.0 - result.a;
}
Ok(result)
}
pub fn from_bytes_with_bytes_int32_boolean(
bytes: Vec<u8>,
pos: i32,
inverted: bool,
) -> Result<Self, Error> {
Self::new_with_bytes_int32_boolean(bytes, pos, inverted)
}
pub fn from_bytes_with_bytes_int32_boolean_boolean(
bytes: Vec<u8>,
pos: i32,
inverted: bool,
alpha_inverted: bool,
) -> Result<Self, Error> {
Self::new_with_bytes_int32_boolean_boolean(bytes, pos, inverted, alpha_inverted)
}
pub fn compare_to(&self, color: Self) -> Result<i32, Error> {
let this_hue = self.get_hue()?;
let that_hue = color.get_hue()?;
Ok(if this_hue < 0.0 && that_hue < 0.0 {
if self.r == color.r {
compare_f32(self.a, color.a)
} else {
compare_f32(self.r, color.r)
}
} else if this_hue == that_hue {
compare_f32(self.a, color.a)
} else {
compare_f32(this_hue, that_hue)
})
}
pub fn get_bytes_with_method(&self) -> Result<Vec<u8>, Error> {
self.get_bytes_with_boolean(false)
}
pub fn get_bytes_with_boolean(&self, inverted: bool) -> Result<Vec<u8>, Error> {
let mut bytes = vec![0; 4];
self.to_bytes_with_bytes_int32_boolean(&mut bytes, 0, inverted)?;
Ok(bytes)
}
pub fn get_float_bytes(&self) -> Result<Vec<u8>, Error> {
let mut bytes = vec![0; 16];
self.to_float_bytes(&mut bytes, 0)?;
Ok(bytes)
}
pub fn to_bytes_with_bytes_int32(&self, dest: &mut [u8], pos: i32) -> Result<(), Error> {
self.to_bytes_with_bytes_int32_boolean(dest, pos, false)
}
pub fn to_bytes_with_bytes_int32_boolean(
&self,
dest: &mut [u8],
pos: i32,
inverted: bool,
) -> Result<(), Error> {
for (offset, value) in [(0, self.r), (1, self.g), (2, self.b), (3, self.a)] {
let index = checked_range(
pos.checked_add(offset).ok_or(Error::IndexOutOfRange)?,
1,
dest.len(),
)?
.start;
let byte = float_to_byte(value);
dest[index] = if inverted { 255 - byte } else { byte };
}
Ok(())
}
pub fn to_float_bytes(&self, dest: &mut [u8], pos: i32) -> Result<(), Error> {
for (offset, value) in [(0, self.r), (4, self.g), (8, self.b), (12, self.a)] {
crate::byte_order::write_single_little_endian(
dest,
pos.checked_add(offset).ok_or(Error::IndexOutOfRange)?,
value,
)?;
}
Ok(())
}
pub fn get_hue(&self) -> Result<f32, Error> {
const HUE_MAX: f32 = 360.0;
let max = max_f32(max_f32(self.r, self.g), self.b);
let min = min_f32(min_f32(self.r, self.g), self.b);
let tolerance = (f64::from(max) * 0.000_01).abs();
if f64::from((max - min).abs()) < tolerance {
return Ok(-1.0);
}
if f64::from((self.r - max).abs()) < tolerance {
let b_delta = ((max - self.b) * (HUE_MAX / 6.0) + (max - min) / 2.0) / (max - min);
let g_delta = ((max - self.g) * (HUE_MAX / 6.0) + (max - min) / 2.0) / (max - min);
Ok(b_delta - g_delta)
} else if f64::from((self.g - max).abs()) < tolerance {
let r_delta = ((max - self.r) * (HUE_MAX / 6.0) + (max - min) / 2.0) / (max - min);
let b_delta = ((max - self.b) * (HUE_MAX / 6.0) + (max - min) / 2.0) / (max - min);
Ok(HUE_MAX / 3.0 + r_delta - b_delta)
} else {
let g_delta = ((max - self.g) * (HUE_MAX / 6.0) + (max - min) / 2.0) / (max - min);
let r_delta = ((max - self.r) * (HUE_MAX / 6.0) + (max - min) / 2.0) / (max - min);
Ok(2.0 * HUE_MAX / 3.0 + g_delta - r_delta)
}
}
pub fn from_hsv(hue: f64, saturation: f64, value: f64) -> Result<Self, Error> {
let (mut r, mut g, mut b) = (0.0, 0.0, 0.0);
if saturation == 0.0 {
r = value;
g = value;
b = value;
} else {
let sector_pos = hue / 60.0;
let sector_number = sector_pos.floor() as i32;
let fractional = sector_pos - f64::from(sector_number);
let p = value * (1.0 - saturation);
let q = value * (1.0 - saturation * fractional);
let t = value * (1.0 - saturation * (1.0 - fractional));
match sector_number {
0 => {
r = value;
g = t;
b = p;
}
1 => {
r = q;
g = value;
b = p;
}
2 => {
r = p;
g = value;
b = t;
}
3 => {
r = p;
g = q;
b = value;
}
4 => {
r = t;
g = p;
b = value;
}
5 => {
r = value;
g = p;
b = q;
}
_ => {}
}
}
Self::new_with_single_single_single_single(r as f32, g as f32, b as f32, 1.0)
}
pub fn lerp(value1: Self, value2: Self, amount: f32) -> Result<Self, Error> {
Self::new_with_single_single_single_single(
clamp_f32(lerp_f32(value1.r, value2.r, amount), 0.0, 1.0),
clamp_f32(lerp_f32(value1.g, value2.g, amount), 0.0, 1.0),
clamp_f32(lerp_f32(value1.b, value2.b, amount), 0.0, 1.0),
clamp_f32(lerp_f32(value1.a, value2.a, amount), 0.0, 1.0),
)
}
pub fn to_string(&self) -> String {
format!(
"<{}, {}, {}, {}>",
format_f32(self.r),
format_f32(self.g),
format_f32(self.b),
format_f32(self.a)
)
}
pub fn to_rgb_string(&self) -> Result<String, Error> {
Ok(format!(
"<{}, {}, {}>",
format_f32(self.r),
format_f32(self.g),
format_f32(self.b)
))
}
pub fn equals_with_object(&self, obj: Option<Object>) -> bool {
matches!(obj, Some(Object::Color4(value)) if Self::eq(*self, value))
}
pub fn equals_with_color4(&self, other: Self) -> bool {
Self::eq(*self, other)
}
pub fn get_hash_code(&self) -> i32 {
hash_f32(self.r) ^ hash_f32(self.g) ^ hash_f32(self.b) ^ hash_f32(self.a)
}
pub fn eq(lhs: Self, rhs: Self) -> bool {
lhs.r == rhs.r && lhs.g == rhs.g && lhs.b == rhs.b && lhs.a == rhs.a
}
pub fn ne(lhs: Self, rhs: Self) -> bool {
!Self::eq(lhs, rhs)
}
pub fn add(lhs: Self, rhs: Self) -> Self {
Self::channel_op(lhs, rhs, |a, b| a + b)
}
pub fn sub(lhs: Self, rhs: Self) -> Self {
Self::channel_op(lhs, rhs, |a, b| a - b)
}
pub fn mul(lhs: Self, rhs: Self) -> Self {
Self::channel_op(lhs, rhs, |a, b| a * b)
}
fn channel_op(lhs: Self, rhs: Self, op: impl Fn(f32, f32) -> f32) -> Self {
Self {
r: clamp_f32(op(lhs.r, rhs.r), 0.0, 1.0),
g: clamp_f32(op(lhs.g, rhs.g), 0.0, 1.0),
b: clamp_f32(op(lhs.b, rhs.b), 0.0, 1.0),
a: clamp_f32(op(lhs.a, rhs.a), 0.0, 1.0),
}
}
}
fn float_to_byte(value: f32) -> u8 {
(clamp_f32(value, 0.0, 1.0) * 255.0).floor() as u8
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn byte_and_float_serialization_match_golden_values() {
let color = Color4::new_with_single_single_single_single(1.0, 0.5, 0.25, 0.0).unwrap();
assert_eq!(color.get_bytes_with_method().unwrap(), [255, 127, 63, 0]);
assert_eq!(
color.get_bytes_with_boolean(true).unwrap(),
[0, 128, 192, 255]
);
let decoded =
Color4::new_with_bytes_int32_boolean_boolean(vec![0, 128, 192, 255], 0, true, true)
.unwrap();
assert_eq!(decoded.r, 1.0);
assert_eq!(decoded.a, 1.0);
let float_bytes = color.get_float_bytes().unwrap();
assert_eq!(&float_bytes[0..4], &1.0_f32.to_le_bytes());
assert_eq!(&float_bytes[4..8], &0.5_f32.to_le_bytes());
}
#[test]
fn output_preserves_partial_mutation_before_bad_index() {
let mut output = [0xaa; 2];
assert_eq!(
Color4::white().to_bytes_with_bytes_int32(&mut output, 0),
Err(Error::IndexOutOfRange)
);
assert_eq!(output, [255, 255]);
let mut floats = [0xaa; 6];
assert_eq!(
Color4::white().to_float_bytes(&mut floats, 0),
Err(Error::IndexOutOfRange)
);
assert_eq!(&floats[..4], &1.0_f32.to_le_bytes());
assert_eq!(&floats[4..], &[0xaa; 2]);
}
#[test]
fn constructor_clamping_hsv_and_channel_operators_match_reference() {
assert_eq!(
Color4::new_with_single_single_single_single(-1.0, 0.5, 0.0, 1.0).unwrap(),
Color4 {
r: 0.0,
g: 0.5,
b: 0.0,
a: 1.0
}
);
assert_eq!(
Color4::new_with_single_single_single_single(1.0001, 0.0, 0.0, 0.0),
Err(Error::Argument)
);
assert_eq!(
Color4::from_hsv(0.0, 1.0, 1.0).unwrap(),
Color4 {
r: 1.0,
g: 0.0,
b: 0.0,
a: 1.0
}
);
assert_eq!(
Color4::add(
Color4 {
r: 0.75,
g: 0.25,
b: 0.0,
a: 0.5
},
Color4 {
r: 0.5,
g: 0.5,
b: 0.5,
a: 0.75
}
),
Color4 {
r: 1.0,
g: 0.75,
b: 0.5,
a: 1.0
}
);
}
#[test]
fn hue_comparison_strings_and_hashes_match_reference_rules() {
let red = Color4 {
r: 1.0,
g: 0.0,
b: 0.0,
a: 1.0,
};
let green = Color4 {
r: 0.0,
g: 1.0,
b: 0.0,
a: 1.0,
};
assert_eq!(red.get_hue().unwrap(), 0.0);
assert_eq!(green.get_hue().unwrap(), 120.0);
assert_eq!(red.compare_to(green).unwrap(), -1);
assert_eq!(red.to_string(), "<1, 0, 0, 1>");
assert_eq!(red.to_rgb_string().unwrap(), "<1, 0, 0>");
let negative_zero = Color4 { r: -0.0, ..red };
let positive_zero = Color4 { r: 0.0, ..red };
assert_eq!(negative_zero.get_hash_code(), positive_zero.get_hash_code());
assert!(red.equals_with_object(Some(Object::from(red))));
}
}

View File

@@ -6,6 +6,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::future::Future; use std::future::Future;
use std::hash::Hash;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::pin::Pin; use std::pin::Pin;
use std::sync::{ use std::sync::{
@@ -19,10 +20,47 @@ pub trait ReadWrite: std::io::Read + std::io::Write {}
impl<T: std::io::Read + std::io::Write> ReadWrite for T {} impl<T: std::io::Read + std::io::Write> ReadWrite for T {}
#[derive(Clone, Debug, Eq, Hash, PartialEq)] #[derive(Clone, Debug)]
pub enum Object { pub enum Object {
Color4(crate::Color4),
String(String), String(String),
UUID(crate::UUID), UUID(crate::UUID),
Vector2(crate::Vector2),
Vector3(crate::Vector3),
Vector3d(crate::Vector3d),
Vector4(crate::Vector4),
}
impl PartialEq for Object {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Color4(lhs), Self::Color4(rhs)) => crate::Color4::eq(*lhs, *rhs),
(Self::String(lhs), Self::String(rhs)) => lhs == rhs,
(Self::UUID(lhs), Self::UUID(rhs)) => lhs == rhs,
(Self::Vector2(lhs), Self::Vector2(rhs)) => crate::Vector2::eq(*lhs, *rhs),
(Self::Vector3(lhs), Self::Vector3(rhs)) => crate::Vector3::eq(*lhs, *rhs),
(Self::Vector3d(lhs), Self::Vector3d(rhs)) => crate::Vector3d::eq(*lhs, *rhs),
(Self::Vector4(lhs), Self::Vector4(rhs)) => crate::Vector4::eq(*lhs, *rhs),
_ => false,
}
}
}
impl Eq for Object {}
impl std::hash::Hash for Object {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
std::mem::discriminant(self).hash(state);
match self {
Self::Color4(value) => value.get_hash_code().hash(state),
Self::String(value) => value.hash(state),
Self::UUID(value) => value.hash(state),
Self::Vector2(value) => value.get_hash_code().hash(state),
Self::Vector3(value) => value.get_hash_code().hash(state),
Self::Vector3d(value) => value.get_hash_code().hash(state),
Self::Vector4(value) => value.get_hash_code().hash(state),
}
}
} }
impl From<String> for Object { impl From<String> for Object {
@@ -37,6 +75,32 @@ impl From<&str> for Object {
} }
} }
impl From<crate::Color4> for Object {
fn from(value: crate::Color4) -> Self {
Self::Color4(value)
}
}
impl From<crate::Vector2> for Object {
fn from(value: crate::Vector2) -> Self {
Self::Vector2(value)
}
}
impl From<crate::Vector3> for Object {
fn from(value: crate::Vector3) -> Self {
Self::Vector3(value)
}
}
impl From<crate::Vector3d> for Object {
fn from(value: crate::Vector3d) -> Self {
Self::Vector3d(value)
}
}
impl From<crate::Vector4> for Object {
fn from(value: crate::Vector4) -> Self {
Self::Vector4(value)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Utf16CodeUnit(pub u16); pub struct Utf16CodeUnit(pub u16);

File diff suppressed because it is too large Load Diff

View File

@@ -3,11 +3,14 @@
extern crate self as libremetaverse_types; extern crate self as libremetaverse_types;
mod byte_order; mod byte_order;
mod color4;
pub mod compat; pub mod compat;
mod crc32; mod crc32;
mod generated; mod generated;
mod math_compat;
pub mod shim; pub mod shim;
mod uuid; mod uuid;
mod vectors;
pub use generated::*; pub use generated::*;
pub use shim::{Error, NotImplemented, not_implemented}; pub use shim::{Error, NotImplemented, not_implemented};

View File

@@ -0,0 +1,189 @@
//! Small helpers that preserve the scalar behavior used by the C# value types.
#![allow(clippy::cast_possible_truncation)] // Hashes intentionally fold raw IEEE bit patterns.
#![allow(clippy::cast_possible_wrap)] // .NET hash codes reinterpret unsigned IEEE bits as i32.
#![allow(clippy::float_cmp)] // Signed-zero and exact scalar compatibility require exact comparisons.
use crate::Error;
use std::cmp::Ordering;
pub(crate) fn checked_range(
pos: i32,
width: usize,
len: usize,
) -> Result<std::ops::Range<usize>, Error> {
let start = usize::try_from(pos).map_err(|_| Error::IndexOutOfRange)?;
let end = start.checked_add(width).ok_or(Error::IndexOutOfRange)?;
if end > len {
return Err(Error::IndexOutOfRange);
}
Ok(start..end)
}
pub(crate) fn clamp_f32(value: f32, min: f32, max: f32) -> f32 {
if value > max {
max
} else if value < min {
min
} else {
value
}
}
pub(crate) fn clamp_f64(value: f64, min: f64, max: f64) -> f64 {
if value > max {
max
} else if value < min {
min
} else {
value
}
}
pub(crate) fn lerp_f32(value1: f32, value2: f32, amount: f32) -> f32 {
value1 + (value2 - value1) * amount
}
pub(crate) fn lerp_f64(value1: f64, value2: f64, amount: f64) -> f64 {
value1 + (value2 - value1) * amount
}
pub(crate) fn smooth_step_f32(value1: f32, value2: f32, amount: f32) -> f32 {
let amount = clamp_f32(amount, 0.0, 1.0);
lerp_f32(value1, value2, amount * amount * (3.0 - 2.0 * amount))
}
pub(crate) fn smooth_step_f64(value1: f64, value2: f64, amount: f64) -> f64 {
let amount = clamp_f64(amount, 0.0, 1.0);
lerp_f64(value1, value2, amount * amount * (3.0 - 2.0 * amount))
}
pub(crate) fn compare_f32(lhs: f32, rhs: f32) -> i32 {
match (lhs.is_nan(), rhs.is_nan()) {
(true, true) => 0,
(true, false) => -1,
(false, true) => 1,
(false, false) => match lhs.partial_cmp(&rhs).expect("non-NaN floats are ordered") {
Ordering::Less => -1,
Ordering::Equal => 0,
Ordering::Greater => 1,
},
}
}
pub(crate) fn compare_f64(lhs: f64, rhs: f64) -> i32 {
match (lhs.is_nan(), rhs.is_nan()) {
(true, true) => 0,
(true, false) => -1,
(false, true) => 1,
(false, false) => match lhs.partial_cmp(&rhs).expect("non-NaN floats are ordered") {
Ordering::Less => -1,
Ordering::Equal => 0,
Ordering::Greater => 1,
},
}
}
pub(crate) fn hash_f32(value: f32) -> i32 {
let bits = if value == 0.0 {
0
} else if value.is_nan() {
0x7fc0_0000
} else {
value.to_bits()
};
bits as i32
}
pub(crate) fn hash_f64(value: f64) -> i32 {
let bits = if value == 0.0 {
0
} else if value.is_nan() {
0x7ff8_0000_0000_0000
} else {
value.to_bits()
};
((bits as u32) ^ ((bits >> 32) as u32)) as i32
}
pub(crate) fn max_f32(lhs: f32, rhs: f32) -> f32 {
if lhs.is_nan() {
lhs
} else if rhs.is_nan() {
rhs
} else if lhs == rhs {
if lhs == 0.0 && lhs.is_sign_negative() {
rhs
} else {
lhs
}
} else if lhs > rhs {
lhs
} else {
rhs
}
}
pub(crate) fn min_f32(lhs: f32, rhs: f32) -> f32 {
if lhs.is_nan() {
lhs
} else if rhs.is_nan() {
rhs
} else if lhs == rhs {
if lhs == 0.0 && lhs.is_sign_negative() {
lhs
} else {
rhs
}
} else if lhs < rhs {
lhs
} else {
rhs
}
}
pub(crate) fn max_f64(lhs: f64, rhs: f64) -> f64 {
if lhs.is_nan() {
lhs
} else if rhs.is_nan() {
rhs
} else {
lhs.max(rhs)
}
}
pub(crate) fn min_f64(lhs: f64, rhs: f64) -> f64 {
if lhs.is_nan() {
lhs
} else if rhs.is_nan() {
rhs
} else {
lhs.min(rhs)
}
}
pub(crate) fn parse_f32(value: &str) -> Result<f32, Error> {
value.trim().parse().map_err(|_| Error::Argument)
}
pub(crate) fn parse_f64(value: &str) -> Result<f64, Error> {
value.trim().parse().map_err(|_| Error::Argument)
}
pub(crate) fn format_f32(value: f32) -> String {
match value {
value if value.is_nan() => "NaN".to_owned(),
value if value == f32::INFINITY => "Infinity".to_owned(),
value if value == f32::NEG_INFINITY => "-Infinity".to_owned(),
value => value.to_string().replace('e', "E"),
}
}
pub(crate) fn format_f64(value: f64) -> String {
match value {
value if value.is_nan() => "NaN".to_owned(),
value if value == f64::INFINITY => "Infinity".to_owned(),
value if value == f64::NEG_INFINITY => "-Infinity".to_owned(),
value => value.to_string().replace('e', "E"),
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -23,6 +23,7 @@ fn color_values(value: &Color4) -> [f32; 4] {
[value.r, value.g, value.b, value.a] [value.r, value.g, value.b, value.a]
} }
#[allow(clippy::trivially_copy_pass_by_ref)] // Mirrors the reference-oriented test helper shape.
fn vector2_values(value: &Vector2) -> [f32; 2] { fn vector2_values(value: &Vector2) -> [f32; 2] {
[value.x, value.y] [value.x, value.y]
} }

View File

@@ -12,7 +12,10 @@
}, },
"allowed_parity_passes": [ "allowed_parity_passes": [
"LibreMetaverse.Tests/AppearanceManagerTests.cs::AppearanceManagerTests.BAKED_TEXTURE_COUNT_Is11::test", "LibreMetaverse.Tests/AppearanceManagerTests.cs::AppearanceManagerTests.BAKED_TEXTURE_COUNT_Is11::test",
"LibreMetaverse.Tests/MarketplaceFolderClassifierTests.cs::MarketplaceFolderClassifierTests.ValidateListing_ValidFlags_AreBitmaskComposable::test" "LibreMetaverse.Tests/MarketplaceFolderClassifierTests.cs::MarketplaceFolderClassifierTests.ValidateListing_ValidFlags_AreBitmaskComposable::test",
"LibreMetaverse.Tests/TypeTests.cs::TypeTests.UUIDs::test",
"LibreMetaverse.Tests/TypeTests.cs::TypeTests.Vector3ApproxEquals::test",
"LibreMetaverse.Tests/TypeTests.cs::TypeTests.VectorCasting::test"
], ],
"support_passes": 20 "support_passes": 42
} }

View File

@@ -38,8 +38,14 @@ TARGETS = {
# implementations. The generated module keeps catalog markers and re-exports # implementations. The generated module keeps catalog markers and re-exports
# the hand-written type so coverage remains deterministic. # the hand-written type so coverage remains deterministic.
NATIVE_TYPES = { NATIVE_TYPES = {
"T:LibreMetaverse.Color4": "crate::color4::Color4",
"T:LibreMetaverse.CRC32": "crate::crc32::CRC32", "T:LibreMetaverse.CRC32": "crate::crc32::CRC32",
"T:LibreMetaverse.Ray": "crate::vectors::Ray",
"T:LibreMetaverse.UUID": "crate::uuid::UUID", "T:LibreMetaverse.UUID": "crate::uuid::UUID",
"T:LibreMetaverse.Vector2": "crate::vectors::Vector2",
"T:LibreMetaverse.Vector3": "crate::vectors::Vector3",
"T:LibreMetaverse.Vector3d": "crate::vectors::Vector3d",
"T:LibreMetaverse.Vector4": "crate::vectors::Vector4",
} }
NATIVE_MEMBER_BODIES = { NATIVE_MEMBER_BODIES = {

View File

@@ -209,6 +209,34 @@ MEMBER_SIGNATURE_OVERRIDES = {
"pub fn to_bytes(&self, dest: &mut [u8], pos: i32) -> Result<(), crate::Error>", "pub fn to_bytes(&self, dest: &mut [u8], pos: i32) -> Result<(), crate::Error>",
"shared_self,mutable_borrow,owned", "shared_self,mutable_borrow,owned",
), ),
"M:LibreMetaverse.Color4.ToBytes(System.Byte[],System.Int32)": (
"pub fn to_bytes_with_bytes_int32(&self, dest: &mut [u8], pos: i32) -> Result<(), crate::Error>",
"shared_self,mutable_borrow,owned",
),
"M:LibreMetaverse.Color4.ToBytes(System.Byte[],System.Int32,System.Boolean)": (
"pub fn to_bytes_with_bytes_int32_boolean(&self, dest: &mut [u8], pos: i32, inverted: bool) -> Result<(), crate::Error>",
"shared_self,mutable_borrow,owned,owned",
),
"M:LibreMetaverse.Color4.ToFloatBytes(System.Byte[],System.Int32)": (
"pub fn to_float_bytes(&self, dest: &mut [u8], pos: i32) -> Result<(), crate::Error>",
"shared_self,mutable_borrow,owned",
),
"M:LibreMetaverse.Vector2.ToBytes(System.Byte[],System.Int32)": (
"pub fn to_bytes(&self, dest: &mut [u8], pos: i32) -> Result<(), crate::Error>",
"shared_self,mutable_borrow,owned",
),
"M:LibreMetaverse.Vector3.ToBytes(System.Byte[],System.Int32)": (
"pub fn to_bytes(&self, dest: &mut [u8], pos: i32) -> Result<(), crate::Error>",
"shared_self,mutable_borrow,owned",
),
"M:LibreMetaverse.Vector3d.ToBytes(System.Byte[],System.Int32)": (
"pub fn to_bytes(&self, dest: &mut [u8], pos: i32) -> Result<(), crate::Error>",
"shared_self,mutable_borrow,owned",
),
"M:LibreMetaverse.Vector4.ToBytes(System.Byte[],System.Int32)": (
"pub fn to_bytes(&self, dest: &mut [u8], pos: i32) -> Result<(), crate::Error>",
"shared_self,mutable_borrow,owned",
),
"M:LibreMetaverse.AppearanceManager.#ctor(LibreMetaverse.GridClient)": ( "M:LibreMetaverse.AppearanceManager.#ctor(LibreMetaverse.GridClient)": (
"pub fn new(client: Option<std::sync::Arc<libremetaverse::GridClient>>) " "pub fn new(client: Option<std::sync::Arc<libremetaverse::GridClient>>) "
"-> Result<Self, crate::Error>", "-> Result<Self, crate::Error>",