Implement vector color and ray compatibility
This commit is contained in:
11
README.md
11
README.md
@@ -52,9 +52,12 @@ Running `cargo test --workspace` is intentionally red during the shim stage.
|
||||
## Native implementation progress
|
||||
|
||||
Milestone 04 implementation has begun. `libremetaverse-types` now provides
|
||||
native UUID, incremental CRC-32, and little-endian floating-point byte helpers.
|
||||
UUID protocol bytes use explicit network order while `compat::Guid` conversions
|
||||
preserve the mixed-endian .NET byte-array layout. The remaining Types surfaces
|
||||
stay visibly failure-only until their owning milestone issues are completed.
|
||||
native UUID, incremental CRC-32, little-endian floating-point byte helpers,
|
||||
Vector2/Vector3/Vector3d/Vector4 arithmetic and serialization, Color4 color
|
||||
conversion, and Ray storage. UUID protocol bytes use explicit network order
|
||||
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#
|
||||
member ID and rejects unrelated fixture, assertion, compile, or symbol errors.
|
||||
|
||||
@@ -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.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.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,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.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.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: &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: &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.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
|
||||
@@ -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.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.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.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
|
||||
@@ -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.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.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.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
|
||||
@@ -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.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.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.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
|
||||
@@ -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.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.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.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
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -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: 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.Voice.Vivox` | 64 | 531 | callable failure-only shim |
|
||||
| `LibreMetaverse.Voice.WebRTC` | 12 | 210 | callable failure-only shim |
|
||||
|
||||
429
crates/libremetaverse-types/src/color4.rs
Normal file
429
crates/libremetaverse-types/src/color4.rs
Normal 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))));
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::future::Future;
|
||||
use std::hash::Hash;
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
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 {}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Object {
|
||||
Color4(crate::Color4),
|
||||
String(String),
|
||||
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 {
|
||||
@@ -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)]
|
||||
pub struct Utf16CodeUnit(pub u16);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,11 +3,14 @@
|
||||
extern crate self as libremetaverse_types;
|
||||
|
||||
mod byte_order;
|
||||
mod color4;
|
||||
pub mod compat;
|
||||
mod crc32;
|
||||
mod generated;
|
||||
mod math_compat;
|
||||
pub mod shim;
|
||||
mod uuid;
|
||||
mod vectors;
|
||||
|
||||
pub use generated::*;
|
||||
pub use shim::{Error, NotImplemented, not_implemented};
|
||||
|
||||
189
crates/libremetaverse-types/src/math_compat.rs
Normal file
189
crates/libremetaverse-types/src/math_compat.rs
Normal 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"),
|
||||
}
|
||||
}
|
||||
1711
crates/libremetaverse-types/src/vectors.rs
Normal file
1711
crates/libremetaverse-types/src/vectors.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,7 @@ fn color_values(value: &Color4) -> [f32; 4] {
|
||||
[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] {
|
||||
[value.x, value.y]
|
||||
}
|
||||
|
||||
@@ -12,7 +12,10 @@
|
||||
},
|
||||
"allowed_parity_passes": [
|
||||
"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
|
||||
}
|
||||
|
||||
@@ -38,8 +38,14 @@ TARGETS = {
|
||||
# implementations. The generated module keeps catalog markers and re-exports
|
||||
# the hand-written type so coverage remains deterministic.
|
||||
NATIVE_TYPES = {
|
||||
"T:LibreMetaverse.Color4": "crate::color4::Color4",
|
||||
"T:LibreMetaverse.CRC32": "crate::crc32::CRC32",
|
||||
"T:LibreMetaverse.Ray": "crate::vectors::Ray",
|
||||
"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 = {
|
||||
|
||||
@@ -209,6 +209,34 @@ MEMBER_SIGNATURE_OVERRIDES = {
|
||||
"pub fn to_bytes(&self, dest: &mut [u8], pos: i32) -> Result<(), crate::Error>",
|
||||
"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)": (
|
||||
"pub fn new(client: Option<std::sync::Arc<libremetaverse::GridClient>>) "
|
||||
"-> Result<Self, crate::Error>",
|
||||
|
||||
Reference in New Issue
Block a user