1use std::collections::HashMap;
2
3use crate::gf::f16;
4use strum::{EnumIs, EnumTryAs, IntoStaticStr};
5
6use crate::gf;
7use crate::tf::Token;
8
9use super::*;
10
11#[derive(Debug, Clone, PartialEq, EnumIs, EnumTryAs, IntoStaticStr, derive_more::From)]
26pub enum Value {
27 #[from(skip)]
29 None,
30
31 Bool(bool),
32 BoolVec(Vec<bool>),
33
34 Uchar(u8),
35 UcharVec(Vec<u8>),
36
37 Int(i32),
38 IntVec(Vec<i32>),
39
40 Uint(u32),
41 UintVec(Vec<u32>),
42
43 Int64(i64),
44 Int64Vec(Vec<i64>),
45
46 Uint64(u64),
47 Uint64Vec(Vec<u64>),
48
49 Half(f16),
50 HalfVec(Vec<f16>),
51
52 Float(f32),
53 FloatVec(Vec<f32>),
54
55 Double(f64),
56 DoubleVec(Vec<f64>),
57
58 String(String),
59 StringVec(Vec<String>),
60
61 Token(Token),
62 TokenVec(Vec<Token>),
63
64 AssetPath(AssetPath),
65 AssetPathVec(Vec<AssetPath>),
66
67 Quath(gf::Quath),
68 Quatf(gf::Quatf),
69 Quatd(gf::Quatd),
70 QuathVec(Vec<gf::Quath>),
71 QuatfVec(Vec<gf::Quatf>),
72 QuatdVec(Vec<gf::Quatd>),
73
74 Vec2h(gf::Vec2h),
75 Vec2f(gf::Vec2f),
76 Vec2d(gf::Vec2d),
77 Vec2i(gf::Vec2i),
78 Vec2hVec(Vec<gf::Vec2h>),
79 Vec2fVec(Vec<gf::Vec2f>),
80 Vec2dVec(Vec<gf::Vec2d>),
81 Vec2iVec(Vec<gf::Vec2i>),
82
83 Vec3h(gf::Vec3h),
84 Vec3f(gf::Vec3f),
85 Vec3d(gf::Vec3d),
86 Vec3i(gf::Vec3i),
87 Vec3hVec(Vec<gf::Vec3h>),
88 Vec3fVec(Vec<gf::Vec3f>),
89 Vec3dVec(Vec<gf::Vec3d>),
90 Vec3iVec(Vec<gf::Vec3i>),
91
92 Vec4h(gf::Vec4h),
93 Vec4f(gf::Vec4f),
94 Vec4d(gf::Vec4d),
95 Vec4i(gf::Vec4i),
96 Vec4hVec(Vec<gf::Vec4h>),
97 Vec4fVec(Vec<gf::Vec4f>),
98 Vec4dVec(Vec<gf::Vec4d>),
99 Vec4iVec(Vec<gf::Vec4i>),
100
101 Matrix2d(gf::Mat2d),
102 Matrix3d(gf::Mat3d),
103 Matrix4d(gf::Matrix4d),
104 Matrix2dVec(Vec<gf::Mat2d>),
105 Matrix3dVec(Vec<gf::Mat3d>),
106 Matrix4dVec(Vec<gf::Matrix4d>),
107
108 Specifier(Specifier),
109 Permission(Permission),
110 Variability(Variability),
111
112 Dictionary(HashMap<String, Value>),
113
114 TokenListOp(TokenListOp),
115 StringListOp(StringListOp),
116 PathListOp(PathListOp),
117 ReferenceListOp(ReferenceListOp),
118 IntListOp(IntListOp),
119 Int64ListOp(Int64ListOp),
120 UIntListOp(UintListOp),
121 UInt64ListOp(Uint64ListOp),
122 PayloadListOp(PayloadListOp),
123
124 Payload(Payload),
125 PathVec(Vec<Path>),
126 Relocates(RelocateList),
128 VariantSelectionMap(HashMap<String, String>),
129 TimeSamples(TimeSampleMap),
130
131 LayerOffsetVec(Vec<LayerOffset>),
132
133 #[from(skip)]
134 ValueBlock,
135 #[from(skip)]
136 Value,
137
138 ValueVec(Vec<Value>),
140
141 #[from(skip)]
142 UnregisteredValue(String),
143 #[from(skip)]
144 UnregisteredValueListOp(StringListOp),
145
146 TimeCode(TimeCode),
147 TimeCodeVec(Vec<TimeCode>),
148 #[from(skip)]
149 PathExpression(String),
150}
151
152#[cfg(feature = "serde")]
153impl serde::Serialize for Value {
154 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
155 use serde::ser::SerializeMap;
156
157 match self {
158 Value::None | Value::ValueBlock | Value::Value => serializer.serialize_none(),
159
160 Value::Bool(v) => v.serialize(serializer),
161 Value::BoolVec(v) => v.serialize(serializer),
162 Value::Uchar(v) => v.serialize(serializer),
163 Value::UcharVec(v) => v.serialize(serializer),
164 Value::Int(v) => v.serialize(serializer),
165 Value::IntVec(v) => v.serialize(serializer),
166 Value::Uint(v) => v.serialize(serializer),
167 Value::UintVec(v) => v.serialize(serializer),
168 Value::Int64(v) => v.serialize(serializer),
169 Value::Int64Vec(v) => v.serialize(serializer),
170 Value::Uint64(v) => v.serialize(serializer),
171 Value::Uint64Vec(v) => v.serialize(serializer),
172 Value::Half(v) => v.serialize(serializer),
173 Value::HalfVec(v) => v.serialize(serializer),
174 Value::Float(v) => v.serialize(serializer),
175 Value::FloatVec(v) => v.serialize(serializer),
176 Value::Double(v) => v.serialize(serializer),
177 Value::DoubleVec(v) => v.serialize(serializer),
178 Value::TimeCode(v) => v.serialize(serializer),
179 Value::TimeCodeVec(v) => v.serialize(serializer),
180
181 Value::String(v) | Value::PathExpression(v) => v.serialize(serializer),
182 Value::Token(v) => v.serialize(serializer),
183 Value::AssetPath(v) => v.serialize(serializer),
184 Value::StringVec(v) => v.serialize(serializer),
185 Value::TokenVec(v) => v.serialize(serializer),
186 Value::AssetPathVec(v) => v.serialize(serializer),
187
188 Value::Vec2h(v) => v.serialize(serializer),
189 Value::Vec3h(v) => v.serialize(serializer),
190 Value::Vec4h(v) => v.serialize(serializer),
191 Value::Quath(v) => v.serialize(serializer),
192 Value::Vec2f(v) => v.serialize(serializer),
193 Value::Vec3f(v) => v.serialize(serializer),
194 Value::Vec4f(v) => v.serialize(serializer),
195 Value::Quatf(v) => v.serialize(serializer),
196 Value::Vec2d(v) => v.serialize(serializer),
197 Value::Vec3d(v) => v.serialize(serializer),
198 Value::Vec4d(v) => v.serialize(serializer),
199 Value::Quatd(v) => v.serialize(serializer),
200 Value::Vec2i(v) => v.serialize(serializer),
201 Value::Vec3i(v) => v.serialize(serializer),
202 Value::Vec4i(v) => v.serialize(serializer),
203
204 Value::Vec2hVec(v) => v.serialize(serializer),
205 Value::Vec3hVec(v) => v.serialize(serializer),
206 Value::Vec4hVec(v) => v.serialize(serializer),
207 Value::QuathVec(v) => v.serialize(serializer),
208 Value::Vec2fVec(v) => v.serialize(serializer),
209 Value::Vec3fVec(v) => v.serialize(serializer),
210 Value::Vec4fVec(v) => v.serialize(serializer),
211 Value::QuatfVec(v) => v.serialize(serializer),
212 Value::Vec2dVec(v) => v.serialize(serializer),
213 Value::Vec3dVec(v) => v.serialize(serializer),
214 Value::Vec4dVec(v) => v.serialize(serializer),
215 Value::QuatdVec(v) => v.serialize(serializer),
216 Value::Vec2iVec(v) => v.serialize(serializer),
217 Value::Vec3iVec(v) => v.serialize(serializer),
218 Value::Vec4iVec(v) => v.serialize(serializer),
219
220 Value::Matrix2d(m) => m.0.chunks(2).collect::<Vec<_>>().serialize(serializer),
221 Value::Matrix3d(m) => m.0.chunks(3).collect::<Vec<_>>().serialize(serializer),
222 Value::Matrix4d(m) => m.0.chunks(4).collect::<Vec<_>>().serialize(serializer),
223 Value::Matrix2dVec(v) => v
224 .iter()
225 .map(|m| m.0.chunks(2).collect::<Vec<_>>())
226 .collect::<Vec<_>>()
227 .serialize(serializer),
228 Value::Matrix3dVec(v) => v
229 .iter()
230 .map(|m| m.0.chunks(3).collect::<Vec<_>>())
231 .collect::<Vec<_>>()
232 .serialize(serializer),
233 Value::Matrix4dVec(v) => v
234 .iter()
235 .map(|m| m.0.chunks(4).collect::<Vec<_>>())
236 .collect::<Vec<_>>()
237 .serialize(serializer),
238
239 Value::Specifier(v) => v.serialize(serializer),
240 Value::Permission(v) => v.serialize(serializer),
241 Value::Variability(v) => v.serialize(serializer),
242 Value::Dictionary(v) => v.serialize(serializer),
243
244 Value::TokenListOp(v) => v.serialize(serializer),
245 Value::StringListOp(v) => v.serialize(serializer),
246 Value::PathListOp(v) => v.serialize(serializer),
247 Value::ReferenceListOp(v) => v.serialize(serializer),
248 Value::IntListOp(v) => v.serialize(serializer),
249 Value::Int64ListOp(v) => v.serialize(serializer),
250 Value::UIntListOp(v) => v.serialize(serializer),
251 Value::UInt64ListOp(v) => v.serialize(serializer),
252 Value::PayloadListOp(v) => v.serialize(serializer),
253
254 Value::Payload(v) => v.serialize(serializer),
255 Value::PathVec(v) => v.serialize(serializer),
256 Value::Relocates(v) => {
257 let mut map = serializer.serialize_map(Some(v.len()))?;
258 for (src, tgt) in v {
259 map.serialize_entry(src.as_str(), tgt.as_str())?;
260 }
261 map.end()
262 }
263 Value::VariantSelectionMap(v) => v.serialize(serializer),
264 Value::LayerOffsetVec(v) => v.serialize(serializer),
265
266 Value::ValueVec(v) => v.serialize(serializer),
267
268 Value::UnregisteredValue(v) => v.serialize(serializer),
269 Value::UnregisteredValueListOp(v) => v.serialize(serializer),
270
271 Value::TimeSamples(v) => {
273 let mut map = serializer.serialize_map(Some(v.len()))?;
274 for (time, value) in v {
275 let key = if time.fract() == 0.0 && time.is_finite() {
276 format!("{}", *time as i64)
277 } else {
278 format!("{time}")
279 };
280 map.serialize_entry(&key, value)?;
281 }
282 map.end()
283 }
284 }
285 }
286}
287
288#[derive(Debug, Clone)]
290pub struct ValueConversionError {
291 expected: &'static str,
292 actual: &'static str,
293}
294
295impl ValueConversionError {
296 pub fn new(expected: &'static str, actual: &Value) -> Self {
298 Self {
299 expected,
300 actual: actual.into(),
301 }
302 }
303
304 pub fn err<T>(expected: &'static str, actual: &Value) -> Result<T, Self> {
306 Err(Self::new(expected, actual))
307 }
308}
309
310impl std::fmt::Display for ValueConversionError {
311 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
312 write!(f, "expected {}, got {}", self.expected, self.actual)
313 }
314}
315
316impl std::error::Error for ValueConversionError {}
317
318impl Value {
319 pub fn get<T: TryFrom<Value>>(self) -> Option<T> {
324 T::try_from(self).ok()
325 }
326
327 pub fn has_embedded_paths(&self) -> bool {
335 matches!(
336 self,
337 Value::PathVec(_)
338 | Value::PathListOp(_)
339 | Value::Relocates(_)
340 | Value::ReferenceListOp(_)
341 | Value::PayloadListOp(_)
342 )
343 }
344
345 pub fn remap_paths(&self, remap: impl Fn(&Path) -> Path) -> Value {
359 self.filter_map_paths(|path| Some(remap(path)))
360 }
361
362 pub fn filter_map_paths(&self, remap: impl Fn(&Path) -> Option<Path>) -> Value {
373 let remap = &remap;
374 match self {
375 Value::PathVec(paths) => Value::PathVec(paths.iter().filter_map(remap).collect()),
376 Value::PathListOp(op) => Value::PathListOp(op.clone().filter_map(|p| remap(&p))),
377 Value::Relocates(relocates) => Value::Relocates(
378 relocates
379 .iter()
380 .filter_map(|(s, t)| remap(s).map(|s| (s, remap(t).unwrap_or_else(|| t.clone()))))
383 .collect(),
384 ),
385 Value::ReferenceListOp(op) => Value::ReferenceListOp(op.clone().filter_map(|mut reference| {
386 if reference.asset_path.is_empty() && !reference.prim_path.is_empty() {
387 reference.prim_path = remap(&reference.prim_path)?;
388 }
389 Some(reference)
390 })),
391 Value::PayloadListOp(op) => Value::PayloadListOp(op.clone().filter_map(|mut payload| {
392 if payload.asset_path.is_empty() && !payload.prim_path.is_empty() {
393 payload.prim_path = remap(&payload.prim_path)?;
394 }
395 Some(payload)
396 })),
397 other => other.clone(),
398 }
399 }
400}
401
402macro_rules! impl_try_from_value {
409 ($target:ty, $method:ident, $label:literal) => {
411 impl TryFrom<Value> for $target {
412 type Error = ValueConversionError;
413
414 fn try_from(value: Value) -> Result<Self, Self::Error> {
415 let tag: &'static str = (&value).into();
416 value.$method().ok_or(ValueConversionError {
417 expected: $label,
418 actual: tag,
419 })
420 }
421 }
422 };
423 ($target:ty, $method:ident, $label:literal, map_into) => {
426 impl_try_from_value!($target, $method, $label, |v| v
427 .into_iter()
428 .map(Into::into)
429 .collect());
430 };
431 ($target:ty, $method:ident, $label:literal, $transform:expr) => {
434 impl TryFrom<Value> for $target {
435 type Error = ValueConversionError;
436
437 fn try_from(value: Value) -> Result<Self, Self::Error> {
438 let tag: &'static str = (&value).into();
439 value.$method().map($transform).ok_or(ValueConversionError {
440 expected: $label,
441 actual: tag,
442 })
443 }
444 }
445 };
446}
447
448impl_try_from_value!(bool, try_as_bool, "Bool");
449impl_try_from_value!(i32, try_as_int, "Int");
450impl_try_from_value!(u32, try_as_uint, "Uint");
451impl_try_from_value!(i64, try_as_int_64, "Int64");
452impl_try_from_value!(u64, try_as_uint_64, "Uint64");
453impl_try_from_value!(f32, try_as_float, "Float");
454impl_try_from_value!(f64, try_as_double, "Double");
455impl_try_from_value!(Specifier, try_as_specifier, "Specifier");
456impl_try_from_value!(Variability, try_as_variability, "Variability");
457impl_try_from_value!(ReferenceListOp, try_as_reference_list_op, "ReferenceListOp");
458impl_try_from_value!(PayloadListOp, try_as_payload_list_op, "PayloadListOp");
459impl_try_from_value!(PathListOp, try_as_path_list_op, "PathListOp");
460
461impl_try_from_value!(gf::Vec2f, try_as_vec_2f, "gf::Vec2f");
463impl_try_from_value!(gf::Vec2d, try_as_vec_2d, "gf::Vec2d");
464impl_try_from_value!(gf::Vec2i, try_as_vec_2i, "gf::Vec2i");
465impl_try_from_value!(gf::Vec2h, try_as_vec_2h, "gf::Vec2h");
466impl_try_from_value!(gf::Vec3f, try_as_vec_3f, "gf::Vec3f");
467impl_try_from_value!(gf::Vec3d, try_as_vec_3d, "gf::Vec3d");
468impl_try_from_value!(gf::Vec3i, try_as_vec_3i, "gf::Vec3i");
469impl_try_from_value!(gf::Vec3h, try_as_vec_3h, "gf::Vec3h");
470impl_try_from_value!(gf::Vec4f, try_as_vec_4f, "gf::Vec4f");
471impl_try_from_value!(gf::Vec4d, try_as_vec_4d, "gf::Vec4d");
472impl_try_from_value!(gf::Vec4i, try_as_vec_4i, "gf::Vec4i");
473impl_try_from_value!(gf::Vec4h, try_as_vec_4h, "gf::Vec4h");
474impl_try_from_value!(gf::Quatf, try_as_quatf, "gf::Quatf");
475impl_try_from_value!(gf::Quatd, try_as_quatd, "gf::Quatd");
476impl_try_from_value!(gf::Quath, try_as_quath, "gf::Quath");
477impl_try_from_value!(gf::Mat2d, try_as_matrix_2d, "gf::Mat2d");
478impl_try_from_value!(gf::Mat3d, try_as_matrix_3d, "gf::Mat3d");
479impl_try_from_value!(gf::Matrix4d, try_as_matrix_4d, "gf::Matrix4d");
480
481impl_try_from_value!(Vec<gf::Vec2f>, try_as_vec_2f_vec, "Vec2fVec");
483impl_try_from_value!(Vec<gf::Vec2d>, try_as_vec_2d_vec, "Vec2dVec");
484impl_try_from_value!(Vec<gf::Vec2i>, try_as_vec_2i_vec, "Vec2iVec");
485impl_try_from_value!(Vec<gf::Vec2h>, try_as_vec_2h_vec, "Vec2hVec");
486impl_try_from_value!(Vec<gf::Vec3f>, try_as_vec_3f_vec, "Vec3fVec");
487impl_try_from_value!(Vec<gf::Vec3d>, try_as_vec_3d_vec, "Vec3dVec");
488impl_try_from_value!(Vec<gf::Vec3i>, try_as_vec_3i_vec, "Vec3iVec");
489impl_try_from_value!(Vec<gf::Vec3h>, try_as_vec_3h_vec, "Vec3hVec");
490impl_try_from_value!(Vec<gf::Vec4f>, try_as_vec_4f_vec, "Vec4fVec");
491impl_try_from_value!(Vec<gf::Vec4d>, try_as_vec_4d_vec, "Vec4dVec");
492impl_try_from_value!(Vec<gf::Vec4i>, try_as_vec_4i_vec, "Vec4iVec");
493impl_try_from_value!(Vec<gf::Vec4h>, try_as_vec_4h_vec, "Vec4hVec");
494impl_try_from_value!(Vec<gf::Quatf>, try_as_quatf_vec, "QuatfVec");
495impl_try_from_value!(Vec<gf::Quatd>, try_as_quatd_vec, "QuatdVec");
496impl_try_from_value!(Vec<gf::Quath>, try_as_quath_vec, "QuathVec");
497impl_try_from_value!(Vec<gf::Mat2d>, try_as_matrix_2d_vec, "Matrix2dVec");
498impl_try_from_value!(Vec<gf::Mat3d>, try_as_matrix_3d_vec, "Matrix3dVec");
499impl_try_from_value!(Vec<gf::Matrix4d>, try_as_matrix_4d_vec, "Matrix4dVec");
500
501impl_try_from_value!(String, try_as_string, "String");
504impl_try_from_value!(Token, try_as_token, "Token");
505impl_try_from_value!(Vec<Token>, try_as_token_vec, "TokenVec");
506impl_try_from_value!(Vec<String>, try_as_string_vec, "StringVec");
507impl_try_from_value!(AssetPath, try_as_asset_path, "AssetPath");
508impl_try_from_value!(Vec<AssetPath>, try_as_asset_path_vec, "AssetPathVec");
509
510impl_try_from_value!(TokenListOp, try_as_token_list_op, "TokenListOp");
513impl_try_from_value!(RelocateList, try_as_relocates, "Relocates");
514impl_try_from_value!(TimeSampleMap, try_as_time_samples, "TimeSamples");
515impl_try_from_value!(Vec<LayerOffset>, try_as_layer_offset_vec, "LayerOffsetVec");
516
517impl_try_from_value!(Vec<f32>, try_as_float_vec, "FloatVec");
520impl_try_from_value!(Vec<f64>, try_as_double_vec, "DoubleVec");
521
522impl_try_from_value!([f32; 2], try_as_vec_2f, "gf::Vec2f", Into::into);
525impl_try_from_value!([f32; 3], try_as_vec_3f, "gf::Vec3f", Into::into);
526impl_try_from_value!([f32; 4], try_as_vec_4f, "gf::Vec4f", Into::into);
527impl_try_from_value!([f64; 2], try_as_vec_2d, "gf::Vec2d", Into::into);
528impl_try_from_value!([f64; 3], try_as_vec_3d, "gf::Vec3d", Into::into);
529impl_try_from_value!([f64; 4], try_as_vec_4d, "gf::Vec4d", Into::into);
530
531impl_try_from_value!(Vec<[f32; 2]>, try_as_vec_2f_vec, "Vec2fVec", map_into);
533impl_try_from_value!(Vec<[f32; 3]>, try_as_vec_3f_vec, "Vec3fVec", map_into);
534impl_try_from_value!(Vec<[f32; 4]>, try_as_vec_4f_vec, "Vec4fVec", map_into);
535
536impl<'a> From<&'a str> for Value {
540 fn from(value: &'a str) -> Self {
541 Value::String(value.to_string())
542 }
543}
544
545impl From<[f32; 2]> for Value {
546 fn from(v: [f32; 2]) -> Self {
547 Value::Vec2f(v.into())
548 }
549}
550impl From<[f32; 3]> for Value {
551 fn from(v: [f32; 3]) -> Self {
552 Value::Vec3f(v.into())
553 }
554}
555impl From<[f64; 2]> for Value {
556 fn from(v: [f64; 2]) -> Self {
557 Value::Vec2d(v.into())
558 }
559}
560impl From<[f64; 3]> for Value {
561 fn from(v: [f64; 3]) -> Self {
562 Value::Vec3d(v.into())
563 }
564}
565impl From<[i32; 2]> for Value {
566 fn from(v: [i32; 2]) -> Self {
567 Value::Vec2i(v.into())
568 }
569}
570impl From<[i32; 3]> for Value {
571 fn from(v: [i32; 3]) -> Self {
572 Value::Vec3i(v.into())
573 }
574}
575impl From<[i32; 4]> for Value {
576 fn from(v: [i32; 4]) -> Self {
577 Value::Vec4i(v.into())
578 }
579}
580impl From<[f64; 16]> for Value {
581 fn from(v: [f64; 16]) -> Self {
582 Value::Matrix4d(gf::Matrix4d(v))
583 }
584}
585
586impl Value {
589 pub fn vec2f(x: f32, y: f32) -> Self {
590 Self::Vec2f(gf::vec2f(x, y))
591 }
592 pub fn vec3f(x: f32, y: f32, z: f32) -> Self {
593 Self::Vec3f(gf::vec3f(x, y, z))
594 }
595 pub fn vec4f(x: f32, y: f32, z: f32, w: f32) -> Self {
596 Self::Vec4f(gf::vec4f(x, y, z, w))
597 }
598 pub fn vec2d(x: f64, y: f64) -> Self {
599 Self::Vec2d(gf::vec2d(x, y))
600 }
601 pub fn vec3d(x: f64, y: f64, z: f64) -> Self {
602 Self::Vec3d(gf::vec3d(x, y, z))
603 }
604 pub fn vec4d(x: f64, y: f64, z: f64, w: f64) -> Self {
605 Self::Vec4d(gf::vec4d(x, y, z, w))
606 }
607 pub fn vec2i(x: i32, y: i32) -> Self {
608 Self::Vec2i(gf::vec2i(x, y))
609 }
610 pub fn vec3i(x: i32, y: i32, z: i32) -> Self {
611 Self::Vec3i(gf::vec3i(x, y, z))
612 }
613 pub fn vec4i(x: i32, y: i32, z: i32, w: i32) -> Self {
614 Self::Vec4i(gf::vec4i(x, y, z, w))
615 }
616 pub fn vec2h(x: f16, y: f16) -> Self {
617 Self::Vec2h(gf::vec2h(x, y))
618 }
619 pub fn vec3h(x: f16, y: f16, z: f16) -> Self {
620 Self::Vec3h(gf::vec3h(x, y, z))
621 }
622 pub fn vec4h(x: f16, y: f16, z: f16, w: f16) -> Self {
623 Self::Vec4h(gf::vec4h(x, y, z, w))
624 }
625 pub fn quatf(w: f32, x: f32, y: f32, z: f32) -> Self {
626 Self::Quatf(gf::quatf(w, x, y, z))
627 }
628 pub fn quatd(w: f64, x: f64, y: f64, z: f64) -> Self {
629 Self::Quatd(gf::quatd(w, x, y, z))
630 }
631 pub fn quath(w: f16, x: f16, y: f16, z: f16) -> Self {
632 Self::Quath(gf::quath(w, x, y, z))
633 }
634
635 pub fn token(name: impl Into<Token>) -> Self {
638 Self::Token(name.into())
639 }
640
641 pub fn token_vec(items: impl IntoIterator<Item = impl Into<Token>>) -> Self {
645 Self::TokenVec(items.into_iter().map(Into::into).collect())
646 }
647
648 pub fn as_str(&self) -> Option<&str> {
655 match self {
656 Value::String(s) => Some(s),
657 Value::Token(s) => Some(s.as_str()),
658 Value::AssetPath(s) => Some(s.as_str()),
659 _ => None,
660 }
661 }
662
663 pub fn cast<T: FromValueCast>(self) -> Result<T, CastError> {
672 T::cast_from(self)
673 }
674}
675
676pub trait FromValueCast: Sized {
687 fn cast_from(value: Value) -> Result<Self, CastError>;
689}
690
691#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
693pub enum CastError {
694 #[error("cannot cast {actual} to {target}")]
696 TypeMismatch {
697 target: &'static str,
699 actual: &'static str,
701 },
702 #[error("{actual} value is out of range for {target}")]
705 OutOfRange {
706 target: &'static str,
708 actual: &'static str,
710 },
711}
712
713impl CastError {
714 fn mismatch<T>(actual: &'static str) -> Self {
715 Self::TypeMismatch {
716 target: std::any::type_name::<T>(),
717 actual,
718 }
719 }
720
721 fn out_of_range<T>(actual: &'static str) -> Self {
722 Self::OutOfRange {
723 target: std::any::type_name::<T>(),
724 actual,
725 }
726 }
727}
728
729fn cast_numeric<T: num_traits::NumCast>(value: Value) -> Result<T, CastError> {
738 use num_traits::NumCast;
739 let actual: &'static str = (&value).into();
740 let src_finite = match &value {
741 Value::Half(v) => v.is_finite(),
742 Value::Float(v) => v.is_finite(),
743 Value::Double(v) => v.is_finite(),
744 _ => true,
745 };
746 let out: T = match value {
747 Value::Uchar(v) => NumCast::from(v),
748 Value::Int(v) => NumCast::from(v),
749 Value::Uint(v) => NumCast::from(v),
750 Value::Int64(v) => NumCast::from(v),
751 Value::Uint64(v) => NumCast::from(v),
752 Value::Half(v) => NumCast::from(v),
753 Value::Float(v) => NumCast::from(v),
754 Value::Double(v) => NumCast::from(v),
755 Value::Bool(v) => NumCast::from(v as u8),
756 _ => return Err(CastError::mismatch::<T>(actual)),
757 }
758 .ok_or_else(|| CastError::out_of_range::<T>(actual))?;
759 if src_finite && out.to_f64().is_some_and(|f| !f.is_finite()) {
760 return Err(CastError::out_of_range::<T>(actual));
761 }
762 Ok(out)
763}
764
765macro_rules! impl_cast_numeric {
766 ($($t:ty),+ $(,)?) => {$(
767 impl FromValueCast for $t {
768 fn cast_from(value: Value) -> Result<Self, CastError> {
769 cast_numeric(value)
770 }
771 }
772 )+};
773}
774
775impl_cast_numeric!(u8, i32, u32, i64, u64, f16, f32, f64);
776
777impl FromValueCast for bool {
778 fn cast_from(value: Value) -> Result<Self, CastError> {
779 match value {
780 Value::Bool(b) => Ok(b),
781 other => Err(CastError::mismatch::<bool>((&other).into())),
782 }
783 }
784}
785
786impl FromValueCast for String {
787 fn cast_from(value: Value) -> Result<Self, CastError> {
788 match value {
789 Value::String(s) => Ok(s),
790 Value::Token(t) => Ok(t.into()),
791 Value::AssetPath(a) => Ok(a.authored_path),
792 other => Err(CastError::mismatch::<String>((&other).into())),
793 }
794 }
795}
796
797impl FromValueCast for Token {
798 fn cast_from(value: Value) -> Result<Self, CastError> {
799 match value {
800 Value::Token(t) => Ok(t),
801 Value::String(s) => Ok(Token::from(s)),
802 other => Err(CastError::mismatch::<Token>((&other).into())),
803 }
804 }
805}
806
807impl FromValueCast for Vec<String> {
808 fn cast_from(value: Value) -> Result<Self, CastError> {
809 match value {
810 Value::StringVec(v) => Ok(v),
811 Value::TokenVec(v) => Ok(v.into_iter().map(String::from).collect()),
812 Value::AssetPathVec(v) => Ok(v.into_iter().map(|a| a.authored_path).collect()),
813 other => Err(CastError::mismatch::<Vec<String>>((&other).into())),
814 }
815 }
816}
817
818fn require<R, U>(value: &Value, converted: Option<U>) -> Result<U, CastError> {
821 converted.ok_or_else(|| CastError::mismatch::<R>(value.into()))
822}
823
824fn vec3_as_f64(value: &Value) -> Option<[f64; 3]> {
827 Some(match value {
828 Value::Vec3f(v) => (*v).into(),
829 Value::Vec3d(v) => (*v).into(),
830 Value::Vec3h(v) => [f64::from(v.x), f64::from(v.y), f64::from(v.z)],
831 Value::Vec3i(v) => [v.x as f64, v.y as f64, v.z as f64],
832 _ => return None,
833 })
834}
835
836fn vec4_as_f64(value: &Value) -> Option<[f64; 4]> {
840 Some(match value {
841 Value::Vec4f(v) => [v.x as f64, v.y as f64, v.z as f64, v.w as f64],
842 Value::Vec4d(v) => (*v).into(),
843 Value::Vec4h(v) => [f64::from(v.x), f64::from(v.y), f64::from(v.z), f64::from(v.w)],
844 Value::Vec4i(v) => [v.x as f64, v.y as f64, v.z as f64, v.w as f64],
845 Value::Quatf(q) => (*q).into(),
846 Value::Quatd(q) => (*q).into(),
847 Value::Quath(q) => [f64::from(q.w), f64::from(q.x), f64::from(q.y), f64::from(q.z)],
848 _ => return None,
849 })
850}
851
852impl FromValueCast for [f64; 3] {
853 fn cast_from(value: Value) -> Result<Self, CastError> {
854 require::<Self, _>(&value, vec3_as_f64(&value))
855 }
856}
857
858impl FromValueCast for [f64; 4] {
859 fn cast_from(value: Value) -> Result<Self, CastError> {
860 require::<Self, _>(&value, vec4_as_f64(&value))
861 }
862}
863
864impl FromValueCast for [f32; 4] {
865 fn cast_from(value: Value) -> Result<Self, CastError> {
866 let a = require::<Self, _>(&value, vec4_as_f64(&value))?;
867 Ok([a[0] as f32, a[1] as f32, a[2] as f32, a[3] as f32])
868 }
869}
870
871impl FromValueCast for gf::Vec3f {
872 fn cast_from(value: Value) -> Result<Self, CastError> {
873 let [x, y, z] = require::<Self, _>(&value, vec3_as_f64(&value))?;
874 Ok(gf::vec3f(x as f32, y as f32, z as f32))
875 }
876}
877
878impl FromValueCast for Vec<f32> {
879 fn cast_from(value: Value) -> Result<Self, CastError> {
880 match value {
881 Value::FloatVec(v) => Ok(v),
882 Value::DoubleVec(v) => Ok(v.into_iter().map(|d| d as f32).collect()),
883 Value::HalfVec(v) => Ok(v.into_iter().map(f32::from).collect()),
884 Value::Vec2f(v) => Ok(vec![v.x, v.y]),
885 Value::Vec3f(v) => Ok(vec![v.x, v.y, v.z]),
886 Value::Vec4f(v) => Ok(vec![v.x, v.y, v.z, v.w]),
887 other => Err(CastError::mismatch::<Vec<f32>>((&other).into())),
888 }
889 }
890}
891
892impl FromValueCast for Vec<gf::Vec3f> {
893 fn cast_from(value: Value) -> Result<Self, CastError> {
894 match value {
895 Value::Vec3fVec(v) => Ok(v),
896 Value::Vec3dVec(v) => Ok(v
897 .into_iter()
898 .map(|d| gf::vec3f(d.x as f32, d.y as f32, d.z as f32))
899 .collect()),
900 Value::Vec3hVec(v) => Ok(v
901 .into_iter()
902 .map(|h| gf::vec3f(f32::from(h.x), f32::from(h.y), f32::from(h.z)))
903 .collect()),
904 other => Err(CastError::mismatch::<Vec<gf::Vec3f>>((&other).into())),
905 }
906 }
907}
908
909#[cfg(test)]
910mod tests {
911 use super::*;
912
913 #[test]
914 fn test_is() {
915 assert!(Value::Bool(true).is_bool());
917 assert!(!Value::Bool(true).is_bool_vec());
918
919 assert!(Value::Float(1.44).is_float());
920 assert!(!Value::Float(1.44).is_bool());
921 assert!(!Value::Float(1.44).is_float_vec());
922
923 assert!(Value::PayloadListOp(Default::default()).is_payload_list_op());
924 assert!(Value::UnregisteredValue(String::new()).is_unregistered_value());
925 }
926
927 #[test]
928 fn remap_paths_rewrites_embedded() {
929 let p = |s: &str| crate::sdf::path(s).unwrap();
930 let remap = |path: &Path| path.replace_prefix(&p("/A"), &p("/B")).unwrap_or_else(|| path.clone());
931
932 let op = Value::PathListOp(PathListOp::explicit([p("/A/Child"), p("/Other")]));
934 let items: Vec<String> = op
935 .remap_paths(remap)
936 .try_as_path_list_op()
937 .unwrap()
938 .explicit_items
939 .iter()
940 .map(|p| p.as_str().to_owned())
941 .collect();
942 assert_eq!(items, vec!["/B/Child", "/Other"]);
943
944 let pv = Value::PathVec(vec![p("/A/X")]).remap_paths(remap);
946 assert_eq!(pv.try_as_path_vec().unwrap()[0].as_str(), "/B/X");
947 let relocates = Value::Relocates(vec![(p("/A/From"), p("/A/To"))]).remap_paths(remap);
948 let pairs = relocates.try_as_relocates().unwrap();
949 assert_eq!((pairs[0].0.as_str(), pairs[0].1.as_str()), ("/B/From", "/B/To"));
950
951 assert_eq!(Value::Int(7).remap_paths(remap), Value::Int(7));
953 }
954
955 #[test]
956 fn try_from_scalars() {
957 assert!(bool::try_from(Value::Bool(true)).unwrap());
958 assert_eq!(i32::try_from(Value::Int(42)).unwrap(), 42);
959 assert_eq!(f32::try_from(Value::Float(1.5)).unwrap(), 1.5);
960 assert_eq!(f64::try_from(Value::Double(2.5)).unwrap(), 2.5);
961 assert_eq!(String::try_from(Value::String("hello".into())).unwrap(), "hello");
962 assert!(String::try_from(Value::Token("tok".into())).is_err());
964 }
965
966 #[test]
967 fn try_from_gf_types() {
968 let v3 = gf::vec3f(1.0, 2.0, 3.0);
969 assert_eq!(gf::Vec3f::try_from(Value::Vec3f(v3)).unwrap(), v3);
970
971 let q = gf::quatf(1.0, 0.0, 0.0, 0.0);
972 assert_eq!(gf::Quatf::try_from(Value::Quatf(q)).unwrap(), q);
973
974 let m = gf::Matrix4d::IDENTITY;
975 assert_eq!(gf::Matrix4d::try_from(Value::Matrix4d(m)).unwrap(), m);
976 }
977
978 #[test]
979 fn try_from_fixed_arrays() {
980 let v = gf::vec2f(1.0, 2.0);
981 assert_eq!(<[f32; 2]>::try_from(Value::Vec2f(v)).unwrap(), [1.0, 2.0]);
982
983 let v = gf::vec3f(1.0, 2.0, 3.0);
984 assert_eq!(<[f32; 3]>::try_from(Value::Vec3f(v)).unwrap(), [1.0, 2.0, 3.0]);
985
986 let v = gf::vec4f(1.0, 2.0, 3.0, 4.0);
987 assert_eq!(<[f32; 4]>::try_from(Value::Vec4f(v)).unwrap(), [1.0, 2.0, 3.0, 4.0]);
988
989 let v = gf::vec3d(1.0, 2.0, 3.0);
990 assert_eq!(<[f64; 3]>::try_from(Value::Vec3d(v)).unwrap(), [1.0, 2.0, 3.0]);
991 }
992
993 #[test]
994 fn try_from_vec() {
995 assert_eq!(Vec::<f32>::try_from(Value::FloatVec(vec![1.0])).unwrap(), vec![1.0]);
998 assert!(Vec::<f32>::try_from(Value::Vec3f(gf::vec3f(1.0, 2.0, 3.0))).is_err());
999
1000 assert_eq!(Vec::<f64>::try_from(Value::DoubleVec(vec![1.0])).unwrap(), vec![1.0]);
1001 assert!(Vec::<f64>::try_from(Value::Vec2d(gf::vec2d(1.0, 2.0))).is_err());
1002
1003 assert_eq!(
1005 Value::Vec3f(gf::vec3f(1.0, 2.0, 3.0)).cast::<Vec<f32>>().unwrap(),
1006 vec![1.0, 2.0, 3.0]
1007 );
1008 }
1009
1010 #[test]
1011 fn try_from_asset_path() {
1012 let scalar = AssetPath::try_from(Value::AssetPath("./tex.png".into())).unwrap();
1013 assert_eq!(scalar, AssetPath::new("./tex.png"));
1014
1015 let array = Vec::<AssetPath>::try_from(Value::AssetPathVec(vec!["a.png".into(), "b.png".into()])).unwrap();
1016 assert_eq!(array, vec![AssetPath::new("a.png"), AssetPath::new("b.png")]);
1017
1018 assert!(AssetPath::try_from(Value::String("a.png".into())).is_err());
1020
1021 assert_eq!(Value::from(scalar), Value::AssetPath("./tex.png".into()));
1023 assert_eq!(
1024 Value::from(array),
1025 Value::AssetPathVec(vec!["a.png".into(), "b.png".into()])
1026 );
1027 }
1028
1029 #[test]
1030 fn try_from_wrong_variant() {
1031 let err = f32::try_from(Value::Int(1)).unwrap_err();
1032 assert_eq!(err.to_string(), "expected Float, got Int");
1033
1034 let err = gf::Vec3f::try_from(Value::Bool(true)).unwrap_err();
1035 assert_eq!(err.to_string(), "expected gf::Vec3f, got Bool");
1036 }
1037
1038 #[test]
1039 fn cast_numeric_widen_narrow() {
1040 assert_eq!(Value::Int(42).cast::<f64>().unwrap(), 42.0);
1042 assert_eq!(Value::Double(2.0).cast::<i32>().unwrap(), 2);
1043 assert_eq!(Value::Uchar(255).cast::<i32>().unwrap(), 255);
1044 assert_eq!(Value::Half(f16::from_f32(1.5)).cast::<f32>().unwrap(), 1.5);
1045 }
1046
1047 #[test]
1048 fn cast_out_of_range() {
1049 assert!(matches!(
1051 Value::Double(1e40).cast::<i32>(),
1052 Err(CastError::OutOfRange { .. })
1053 ));
1054 assert!(matches!(
1057 Value::Double(f64::MAX).cast::<f32>(),
1058 Err(CastError::OutOfRange { .. })
1059 ));
1060 assert!(matches!(
1061 Value::Float(f32::MAX).cast::<f16>(),
1062 Err(CastError::OutOfRange { .. })
1063 ));
1064 assert_eq!(Value::Double(f64::INFINITY).cast::<f32>().unwrap(), f32::INFINITY);
1066 assert!(matches!(
1068 Value::Bool(true).cast::<gf::Vec3f>(),
1069 Err(CastError::TypeMismatch { .. })
1070 ));
1071 }
1072
1073 #[test]
1074 fn cast_string_token() {
1075 assert_eq!(Value::Token("t".into()).cast::<String>().unwrap(), "t");
1076 assert_eq!(Value::String("s".into()).cast::<Token>().unwrap(), Token::new("s"));
1077 assert_eq!(
1078 Value::TokenVec(vec!["a".into(), "b".into()])
1079 .cast::<Vec<String>>()
1080 .unwrap(),
1081 vec!["a".to_string(), "b".to_string()]
1082 );
1083 }
1084
1085 #[test]
1086 fn cast_vec_precision() {
1087 assert_eq!(
1089 Value::Vec3d(gf::vec3d(1.0, 2.0, 3.0)).cast::<gf::Vec3f>().unwrap(),
1090 gf::vec3f(1.0, 2.0, 3.0)
1091 );
1092 assert_eq!(
1094 Value::Vec3f(gf::vec3f(1.0, 2.0, 3.0)).cast::<[f64; 3]>().unwrap(),
1095 [1.0, 2.0, 3.0]
1096 );
1097 }
1098
1099 #[test]
1100 fn cast_quat_wxyz_order() {
1101 let q = gf::quatf(1.0, 2.0, 3.0, 4.0);
1103 assert_eq!(Value::Quatf(q).cast::<[f64; 4]>().unwrap(), [1.0, 2.0, 3.0, 4.0]);
1104 }
1105
1106 #[test]
1107 fn from_gf_roundtrip() {
1108 let v = gf::vec3f(1.0, 2.0, 3.0);
1109 assert_eq!(Value::from(v), Value::Vec3f(v));
1110
1111 let m = gf::Matrix4d::IDENTITY;
1112 assert_eq!(Value::from(m), Value::Matrix4d(m));
1113 }
1114}