openusd/usdc/
mod.rs

1//! Binary file format (`usdc`) implementation.
2
3use std::{borrow::Cow, collections::HashMap, fmt::Debug, io, mem, path::Path};
4
5use anyhow::{bail, Result};
6use layout::ValueRep;
7
8mod coding;
9mod layout;
10mod reader;
11
12pub use layout::{version, Version};
13pub use reader::{CrateFile, ReadExt};
14
15use crate::sdf;
16
17#[derive(Default, Debug)]
18struct Spec {
19    /// Specifies the type of an object.
20    ty: sdf::SpecType,
21    /// Spec properties.
22    fields: HashMap<String, ValueRep>,
23}
24
25/// High level interface to binary data.
26#[derive(Debug)]
27pub struct CrateData<R> {
28    file: CrateFile<R>,
29    data: HashMap<sdf::Path, Spec>,
30}
31
32impl<R> CrateData<R>
33where
34    R: io::Read + io::Seek,
35{
36    /// Read binary data from any reader.
37    pub fn open(reader: R, safe: bool) -> Result<Self> {
38        let mut file = CrateFile::open(reader)?;
39
40        if safe {
41            file.validate()?;
42        }
43
44        // Build crate data
45
46        let mut data = HashMap::default();
47        let specs = mem::take(&mut file.specs);
48
49        for filespec in specs {
50            let path = file.paths[filespec.path_index].clone();
51            let ty = filespec.spec_type;
52
53            let mut fields = HashMap::default();
54            let mut index = filespec.fieldset_index;
55
56            while index < file.fieldsets.len() {
57                let current = match file.fieldsets[index] {
58                    Some(value) => value,
59                    None => break,
60                };
61
62                index += 1;
63
64                let field = &file.fields[current];
65                let name = file.tokens[field.token_index].clone();
66
67                fields.insert(name, field.value_rep);
68            }
69
70            data.insert(path, Spec { ty, fields });
71        }
72
73        Ok(Self { file, data })
74    }
75}
76
77impl<R> sdf::AbstractData for CrateData<R>
78where
79    R: io::Read + io::Seek,
80{
81    #[inline]
82    fn has_spec(&self, path: &sdf::Path) -> bool {
83        self.data.contains_key(path)
84    }
85
86    #[inline]
87    fn has_field(&self, path: &sdf::Path, field: &str) -> bool {
88        self.data.get(path).is_some_and(|spec| spec.fields.contains_key(field))
89    }
90
91    #[inline]
92    fn spec_type(&self, path: &sdf::Path) -> Option<sdf::SpecType> {
93        self.data.get(path).map(|spec| spec.ty)
94    }
95
96    fn get(&mut self, path: &sdf::Path, field: &str) -> Result<Cow<sdf::Value>> {
97        let Some(spec) = self.data.get(path) else {
98            bail!("No spec found for path: {}", path)
99        };
100
101        let Some(value_rep) = spec.fields.get(field).cloned() else {
102            bail!("No field found for path '{}' and field '{}'", path, field)
103        };
104
105        let value = self.file.value(value_rep)?;
106
107        Ok(Cow::Owned(value))
108    }
109
110    #[inline]
111    fn list(&self, path: &sdf::Path) -> Option<Vec<String>> {
112        self.data.get(path).map(|spec| spec.fields.keys().cloned().collect())
113    }
114}
115
116/// Read `usdc` data from a file on disk.
117pub fn read_file(path: impl AsRef<Path>) -> Result<Box<dyn sdf::AbstractData>> {
118    let file = std::fs::File::open(path)?;
119    let data = CrateData::open(file, true)?;
120
121    Ok(Box::new(data))
122}
123
124#[cfg(test)]
125mod tests {
126    use super::*;
127    use half::f16;
128
129    #[test]
130    fn test_crate_hierarchy() -> Result<()> {
131        let mut data =
132            read_file("./extern/usd-wg-assets/full_assets/ElephantWithMonochord/SoC-ElephantWithMonochord.usdc")?;
133
134        let prim_children: Vec<String> = data
135            .get(&sdf::Path::abs_root(), "primChildren")?
136            .into_owned()
137            .try_as_token_vec()
138            .unwrap();
139        assert_eq!(prim_children, vec!["SoC_ElephantWithMonochord".to_string()]);
140
141        let elephant: Vec<String> = data
142            .get(&sdf::path("/SoC_ElephantWithMonochord")?, "primChildren")?
143            .into_owned()
144            .try_as_token_vec()
145            .unwrap();
146
147        assert_eq!(
148            elephant,
149            vec![
150                "Materials".to_string(),
151                "Object".to_string(),
152                "CharacterAudioSource".to_string()
153            ]
154        );
155
156        let materials: Vec<String> = data
157            .get(&sdf::path("/SoC_ElephantWithMonochord/Materials")?, "primChildren")?
158            .into_owned()
159            .try_as_token_vec()
160            .unwrap();
161
162        assert_eq!(
163            materials,
164            vec!["Elefant_Mat_68050".to_string(), "Monochord_Mat_68062".to_string()]
165        );
166
167        Ok(())
168    }
169
170    #[test]
171    fn test_read_custom_layer_data() {
172        let mut data = read_file("fixtures/fields.usdc").unwrap();
173
174        let custom_layer_data = data.get(&sdf::Path::abs_root(), "customLayerData").unwrap();
175
176        // customLayerData = {
177        //  string test = "Test string"
178        // }
179        let copyright = custom_layer_data
180            .try_as_dictionary_ref()
181            .unwrap()
182            .get("test")
183            .unwrap()
184            .try_as_string_ref()
185            .unwrap();
186
187        assert_eq!(copyright, "Test string");
188    }
189
190    #[test]
191    fn test_read_bool() -> Result<()> {
192        let mut data = read_file("fixtures/fields.usdc")?;
193
194        let single = data
195            .get(&sdf::path("/World.flipNormals")?, "default")?
196            .into_owned()
197            .try_as_bool()
198            .unwrap();
199
200        assert!(single);
201
202        let bool_array = data
203            .get(&sdf::path("/World.boolArray")?, "default")?
204            .into_owned()
205            .try_as_bool_vec()
206            .unwrap();
207
208        assert_eq!(bool_array, vec![true, true, false, false, true, false]);
209
210        Ok(())
211    }
212
213    #[test]
214    fn test_read_chars() -> Result<()> {
215        let mut data = read_file("fixtures/fields.usdc")?;
216
217        let single_char = data
218            .get(&sdf::path("/World.singleChar")?, "default")?
219            .into_owned()
220            .try_as_uchar()
221            .unwrap();
222
223        assert_eq!(single_char, 128);
224
225        let char_array = data
226            .get(&sdf::path("/World.chars")?, "default")?
227            .into_owned()
228            .try_as_uchar_vec()
229            .unwrap();
230
231        assert_eq!(char_array, vec![128, 129, 130, 131, 132, 133, 134, 135, 136, 137]);
232
233        Ok(())
234    }
235
236    #[test]
237    fn test_read_quat_floats() -> Result<()> {
238        let mut data = read_file("fixtures/fields.usdc")?;
239
240        let quat = data
241            .get(&sdf::path("/World.quatfSingle")?, "default")?
242            .into_owned()
243            .try_as_quatf()
244            .unwrap();
245
246        assert_eq!(quat, vec![2.9, 8.5, 4.6, 1.4]);
247
248        let quat = data
249            .get(&sdf::path("/World.quatfArr")?, "default")?
250            .into_owned()
251            .try_as_quatf()
252            .unwrap();
253
254        assert_eq!(
255            quat,
256            vec![
257                3.5, 2.6, 3.6, 4.2, // 1
258                5.3, 6.3, 5.2, 2.4, // 2
259                4.3, 2.4, 6.4, 7.1, // 3
260            ]
261        );
262
263        Ok(())
264    }
265
266    #[test]
267    fn test_read_quat_doubles() -> Result<()> {
268        let mut data = read_file("fixtures/fields.usdc")?;
269
270        let quat = data
271            .get(&sdf::path("/World.quatdSingle")?, "default")?
272            .into_owned()
273            .try_as_quatd()
274            .unwrap();
275
276        assert_eq!(quat, vec![5.3, 6.3, 5.2, 2.4]);
277
278        let quat = data
279            .get(&sdf::path("/World.quatdArr")?, "default")?
280            .into_owned()
281            .try_as_quatd()
282            .unwrap();
283
284        assert_eq!(
285            quat,
286            vec![
287                3.5, 2.6, 3.6, 4.2, // 1
288                4.3, 2.4, 6.4, 7.1, // 2
289            ]
290        );
291
292        Ok(())
293    }
294
295    #[test]
296    fn test_read_quat_half() -> Result<()> {
297        let mut data = read_file("fixtures/fields.usdc")?;
298
299        let quat = data
300            .get(&sdf::path("/World.quathSingle")?, "default")?
301            .into_owned()
302            .try_as_quath()
303            .unwrap();
304
305        assert_eq!(
306            quat,
307            [4.6, 2.5, 7.6, 3.5].into_iter().map(f16::from_f32).collect::<Vec<_>>()
308        );
309
310        let quat = data
311            .get(&sdf::path("/World.quathArr")?, "default")?
312            .into_owned()
313            .try_as_quath()
314            .unwrap();
315
316        assert_eq!(
317            quat,
318            [
319                2.4, 7.8, 8.5, 4.7, // 1
320                6.7, 5.6, 5.3, 4.6, // 2
321            ]
322            .into_iter()
323            .map(f16::from_f32)
324            .collect::<Vec<_>>()
325        );
326
327        Ok(())
328    }
329
330    #[test]
331    fn test_read_sub_layers() -> Result<()> {
332        let mut data = read_file("fixtures/expressions.usdc")?;
333
334        let sub_layer_offsets = data
335            .get(&sdf::path("/")?, "subLayerOffsets")?
336            .into_owned()
337            .try_as_layer_offset_vec()
338            .unwrap()
339            .into_iter()
340            .next()
341            .unwrap();
342
343        assert_eq!(sub_layer_offsets.offset, 0.0);
344        assert_eq!(sub_layer_offsets.scale, 1.0);
345
346        let sub_layers = data
347            .get(&sdf::path("/")?, "subLayers")?
348            .into_owned()
349            .try_as_string_vec()
350            .unwrap();
351        assert_eq!(sub_layers, vec!["`\"render_pass_${RENDER_PASS}.usd\"`"]);
352
353        Ok(())
354    }
355
356    #[test]
357    fn test_read_variant_selection() -> Result<()> {
358        let mut data = read_file("fixtures/expressions.usdc")?;
359
360        // prepend variantSets = "displayVariantSet"
361        let variant_set_names = data
362            .get(&sdf::path("/asset1")?, "variantSetNames")?
363            .into_owned()
364            .try_as_string_list_op()
365            .unwrap();
366        assert_eq!(variant_set_names.prepended_items, vec!["displayVariantSet".to_string()]);
367
368        let variant_selection = data
369            .get(&sdf::path("/asset1")?, "variantSelection")?
370            .into_owned()
371            .try_as_variant_selection_map()
372            .unwrap();
373
374        assert_eq!(variant_selection.len(), 1);
375        assert_eq!(
376            variant_selection.get("displayVariantSet").unwrap(),
377            "`${VARIANT_CHOICE}`"
378        );
379
380        Ok(())
381    }
382
383    #[test]
384    fn test_read_connection() -> Result<()> {
385        let mut data = read_file("fixtures/connection.usdc")?;
386
387        let conn = data
388            .get(&sdf::path("/boardMat/stReader.inputs:varname")?, "connectionPaths")?
389            .into_owned()
390            .try_as_path_list_op()
391            .unwrap();
392
393        assert!(conn.explicit);
394        assert_eq!(
395            conn.explicit_items,
396            vec![sdf::path("/TexModel/boardMat.inputs:frame:stPrimvarName")?]
397        );
398
399        let conn = data
400            .get(&sdf::path("/boardMat.outputs:surface")?, "connectionPaths")?
401            .into_owned()
402            .try_as_path_list_op()
403            .unwrap();
404
405        assert!(conn.explicit);
406        assert_eq!(
407            conn.explicit_items,
408            vec![sdf::path("/TexModel/boardMat/PBRShader.outputs:surface")?]
409        );
410
411        Ok(())
412    }
413
414    #[test]
415    fn test_read_reference() -> Result<()> {
416        let mut data = read_file("fixtures/reference.usdc")?;
417
418        let references = data
419            .get(&sdf::path("/MarbleCollection/Marble_Red")?, "references")?
420            .into_owned()
421            .try_as_reference_list_op()
422            .unwrap();
423
424        assert!(references.appended_items.is_empty());
425        assert!(references.deleted_items.is_empty());
426        assert!(references.ordered_items.is_empty());
427
428        assert!(references.explicit);
429        assert_eq!(references.explicit_items.len(), 1);
430
431        assert_eq!(references.explicit_items[0].asset_path, "Marble.usd");
432        assert_eq!(references.explicit_items[0].prim_path, sdf::path("/Foo/Bar")?);
433
434        Ok(())
435    }
436
437    #[test]
438    fn test_read_payload() -> Result<()> {
439        let mut data = read_file("fixtures/payload.usdc")?;
440
441        let payload = data
442            .get(&sdf::path("/MySphere1")?, "payload")?
443            .into_owned()
444            .try_as_payload()
445            .unwrap();
446
447        assert_eq!(payload.asset_path, "./payload.usda");
448        assert_eq!(payload.prim_path, sdf::path("/MySphere")?);
449
450        assert!(payload.layer_offset.is_some());
451
452        let layer_offset = payload.layer_offset.unwrap();
453        assert_eq!(layer_offset.offset, 0.0);
454        assert_eq!(layer_offset.scale, 1.0);
455
456        let payload_list_op = data
457            .get(&sdf::path("/MySphere2")?, "payload")?
458            .into_owned()
459            .try_as_payload_list_op()
460            .unwrap();
461
462        assert!(!payload_list_op.explicit);
463
464        assert!(payload_list_op.explicit_items.is_empty());
465        assert!(payload_list_op.added_items.is_empty());
466        assert!(payload_list_op.appended_items.is_empty());
467        assert!(payload_list_op.deleted_items.is_empty());
468        assert!(payload_list_op.ordered_items.is_empty());
469
470        assert_eq!(payload_list_op.prepended_items.len(), 1);
471        assert_eq!(payload_list_op.prepended_items[0].asset_path, "./cube_payload.usda");
472        assert_eq!(payload_list_op.prepended_items[0].prim_path, sdf::path("/PayloadCube")?);
473
474        Ok(())
475    }
476
477    #[test]
478    fn test_read_doubles() -> Result<()> {
479        let mut data = read_file("fixtures/floats.usdc")?;
480
481        let single = data
482            .get(&sdf::path("/PrimD.single")?, "default")?
483            .into_owned()
484            .try_as_double()
485            .unwrap();
486        assert_eq!(single, 4.3_f64);
487
488        let array = data
489            .get(&sdf::path("/PrimD.simple")?, "default")?
490            .into_owned()
491            .try_as_double_vec()
492            .unwrap();
493        assert_eq!(array, vec![0.5, 1.7, 2.4, 3.5, 4.9, 5.3, 6.2, 7.8, 8.6, 9.3]);
494
495        let compressed = data
496            .get(&sdf::path("/PrimD.copressed")?, "default")?
497            .into_owned()
498            .try_as_double_vec()
499            .unwrap();
500        assert_eq!(
501            compressed,
502            vec![
503                0.5, 1.7, 2.4, 3.5, 4.9, 5.3, 6.2, 7.8, 8.6, 9.3, 5.3, 6.2, 7.8, 8.6, 9.3, 0.5, 1.7, 2.4, 3.5, 4.9,
504                0.5, 1.7, 2.4, 3.5, 4.9, 5.3, 6.2, 7.8, 8.6, 9.3, 5.3, 6.2, 7.8, 8.6, 9.3, 0.5, 1.7, 2.4, 3.5, 4.9,
505                0.5, 1.7, 2.4, 3.5, 4.9, 5.3, 6.2, 7.8, 8.6, 9.3, 5.3, 6.2, 7.8, 8.6, 9.3, 0.5, 1.7, 2.4, 3.5, 4.9,
506                0.5, 1.7, 2.4, 3.5, 4.9, 5.3, 6.2, 7.8, 8.6, 9.3, 5.3, 6.2, 7.8, 8.6, 9.3, 0.5, 1.7, 2.4, 3.5, 4.9,
507                0.5, 1.7, 2.4, 3.5, 4.9, 5.3, 6.2, 7.8, 8.6, 9.3, 5.3, 6.2, 7.8, 8.6, 9.3, 0.5, 1.7, 2.4, 3.5, 4.9,
508            ]
509        );
510
511        Ok(())
512    }
513
514    #[test]
515    fn test_read_floats() -> Result<()> {
516        let mut data = read_file("fixtures/floats.usdc")?;
517
518        let single = data
519            .get(&sdf::path("/PrimF.single")?, "default")?
520            .into_owned()
521            .try_as_float()
522            .unwrap();
523        assert_eq!(single, 3.5);
524
525        let array = data
526            .get(&sdf::path("/PrimF.simple")?, "default")?
527            .into_owned()
528            .try_as_float_vec()
529            .unwrap();
530        assert_eq!(array, vec![9.1, 2.3, 6.4, 7.4, 3.6, 4.3, 5.3, 5.6, 8.7, 4.7]);
531
532        let compressed = data
533            .get(&sdf::path("/PrimF.copressed")?, "default")?
534            .into_owned()
535            .try_as_float_vec()
536            .unwrap();
537
538        assert_eq!(
539            compressed,
540            vec![
541                9.1, 2.3, 6.4, 7.4, 3.6, 4.3, 5.3, 5.6, 8.7, 4.7, 4.7, 9.1, 2.3, 6.4, 7.4, 3.6, 4.3, 5.3, 5.6, 8.7,
542                8.7, 4.7, 9.1, 2.3, 6.4, 7.4, 3.6, 4.3, 5.3, 5.6, 5.6, 8.7, 4.7, 9.1, 2.3, 6.4, 7.4, 3.6, 4.3, 5.3,
543                5.3, 5.6, 8.7, 4.7, 9.1, 2.3, 6.4, 7.4, 3.6, 4.3,
544            ]
545        );
546
547        Ok(())
548    }
549
550    #[test]
551    fn test_read_halfs() -> Result<()> {
552        let mut data = read_file("fixtures/floats.usdc")?;
553
554        let single = data
555            .get(&sdf::path("/PrimH.single")?, "default")?
556            .into_owned()
557            .try_as_half()
558            .unwrap();
559
560        assert_eq!(single, f16::from_f32(2.9));
561
562        let array = data
563            .get(&sdf::path("/PrimH.simple")?, "default")?
564            .into_owned()
565            .try_as_half_vec()
566            .unwrap();
567
568        assert_eq!(
569            array,
570            [4.3, 5.3, 5.6, 8.7, 4.7, 9.1, 2.3, 6.4, 7.4, 3.6]
571                .into_iter()
572                .map(f16::from_f32)
573                .collect::<Vec<_>>()
574        );
575
576        let compressed = data
577            .get(&sdf::path("/PrimH.copressed")?, "default")?
578            .into_owned()
579            .try_as_half_vec()
580            .unwrap();
581
582        assert_eq!(
583            compressed,
584            [
585                4.3, 5.3, 5.6, 8.7, 4.7, 9.1, 2.3, 6.4, 7.4, 3.6, 3.6, 4.3, 5.3, 5.6, 8.7, 4.7, 9.1, 2.3, 6.4, 7.4,
586                7.4, 3.6, 4.3, 5.3, 5.6, 8.7, 4.7, 9.1, 2.3, 6.4, 6.4, 7.4, 3.6, 4.3, 5.3, 5.6, 8.7, 4.7, 9.1, 2.3,
587                2.3, 6.4, 7.4, 3.6, 4.3, 5.3, 5.6, 8.7, 4.7, 9.1,
588            ]
589            .into_iter()
590            .map(f16::from_f32)
591            .collect::<Vec<_>>()
592        );
593
594        Ok(())
595    }
596
597    #[test]
598    fn test_read_time_series() -> Result<()> {
599        let mut data = read_file("fixtures/timesamples.usdc")?;
600
601        let samples = data
602            .get(&sdf::path("/Prim.prop")?, "timeSamples")?
603            .into_owned()
604            .try_as_time_samples()
605            .unwrap();
606        assert_eq!(samples.len(), 2);
607
608        let keys = samples.iter().map(|(d, _)| d).copied().collect::<Vec<_>>();
609        assert_eq!(keys, vec![4.0, 5.0]);
610
611        assert!(matches!(&samples[0].1, sdf::Value::Double(x) if *x == 40.0_f64));
612        assert!(matches!(samples[1].1, sdf::Value::ValueBlock));
613
614        Ok(())
615    }
616
617    #[test]
618    fn test_read_ints_i32() -> Result<()> {
619        let mut data = read_file("fixtures/ints.usdc")?;
620
621        assert_eq!(
622            data.get(&sdf::path("/Prim32.single")?, "default")?
623                .into_owned()
624                .try_as_int()
625                .unwrap(),
626            12938
627        );
628
629        assert_eq!(
630            data.get(&sdf::path("/Prim32.compressed")?, "default")?
631                .into_owned()
632                .try_as_int_vec()
633                .unwrap(),
634            vec![
635                1, 2, 4, 5, -3, 4, 5, -2, 3, -0, 3, 2, 4, -2, 4, 1, 8, -1, 5, -5, 2, 6, -3, 4, 6, 3, -7, 2, -3, 3, 6,
636                2, 6, 6, -4, 2, -4, 6, -2, 4
637            ]
638        );
639
640        Ok(())
641    }
642
643    #[test]
644    fn test_read_ints_i64() -> Result<()> {
645        let mut data = read_file("fixtures/ints.usdc")?;
646
647        assert_eq!(
648            data.get(&sdf::path("/Prim64.single")?, "default")?
649                .into_owned()
650                .try_as_int_64()
651                .unwrap(),
652            1234567890
653        );
654
655        assert_eq!(
656            data.get(&sdf::path("/Prim64.compressed")?, "default")?
657                .into_owned()
658                .try_as_int_64_vec()
659                .unwrap(),
660            vec![
661                10, 23, 48, 45, -23, 43, 65, -23, 23, -10, 34, 23, 45, -12, 34, 16, 18, -12, 65, -65, 21, 67, -43, 34,
662                36, 34, -67, 25, -23, 63, 65, 23, 65, 63, -54, 23, -44, 65, -62, 54
663            ]
664        );
665
666        Ok(())
667    }
668
669    #[test]
670    fn test_read_ints_u32() -> Result<()> {
671        let mut data = read_file("fixtures/ints.usdc")?;
672
673        assert_eq!(
674            data.get(&sdf::path("/PrimU32.single")?, "default")?
675                .into_owned()
676                .try_as_uint()
677                .unwrap(),
678            80129
679        );
680
681        assert_eq!(
682            data.get(&sdf::path("/PrimU32.compressed")?, "default")?
683                .into_owned()
684                .try_as_uint_vec()
685                .unwrap(),
686            vec![
687                1, 2, 4, 5, 3, 4, 5, 2, 3, 0, 3, 2, 4, 2, 4, 1, 8, 1, 5, 5, 2, 6, 3, 4, 6, 3, 7, 2, 3, 3, 6, 2, 6, 6,
688                4, 2, 4, 6, 2, 4
689            ]
690        );
691
692        Ok(())
693    }
694
695    #[test]
696    fn test_read_ints_u64() -> Result<()> {
697        let mut data = read_file("fixtures/ints.usdc")?;
698
699        assert_eq!(
700            data.get(&sdf::path("/PrimU64.single")?, "default")?
701                .into_owned()
702                .try_as_uint_64()
703                .unwrap(),
704            432423654
705        );
706
707        assert_eq!(
708            data.get(&sdf::path("/PrimU64.compressed")?, "default")?
709                .into_owned()
710                .try_as_uint_64_vec()
711                .unwrap(),
712            vec![
713                34, 23, 45, 12, 34, 16, 18, 12, 65, 65, 10, 23, 48, 45, 23, 43, 65, 23, 23, 10, 65, 23, 65, 63, 54, 23,
714                44, 65, 62, 54, 21, 67, 43, 34, 36, 34, 67, 25, 23, 63,
715            ]
716        );
717
718        Ok(())
719    }
720
721    #[test]
722    fn test_read_array_fields() -> Result<()> {
723        let mut data = read_file("fixtures/fields.usdc")?;
724
725        // defaultPrim = "World"
726        let default_prim = data.get(&sdf::Path::abs_root(), "defaultPrim")?;
727        assert_eq!(default_prim.try_as_token_ref().unwrap(), "World");
728
729        // float4[] clippingPlanes = []
730        let clipping_planes = data.get(&sdf::path("/World.clippingPlanes")?, "default")?;
731        assert!(clipping_planes.into_owned().try_as_vec_4f_ref().unwrap().is_empty());
732
733        // float2 clippingRange = (1, 10000000)
734        let clipping_range = data.get(&sdf::path("/World.clippingRange")?, "default")?;
735        assert_eq!(
736            &clipping_range.into_owned().try_as_vec_2f().unwrap(),
737            &[1.0, 10000000.0]
738        );
739
740        // float3 diffuseColor = (0.18, 0.18, 0.18)
741        let diffuse_color = data.get(&sdf::path("/World.diffuseColor")?, "default")?;
742        assert_eq!(
743            &diffuse_color.into_owned().try_as_vec_3f().unwrap(),
744            &[0.18, 0.18, 0.18]
745        );
746
747        // int[] faceVertexCounts = [1, 2, 3, 4, 5, 6]
748        let face_vertex_counts = data.get(&sdf::path("/World.faceVertexCounts")?, "default")?;
749        assert_eq!(
750            &face_vertex_counts.into_owned().try_as_int_vec().unwrap(),
751            &[1, 2, 3, 4, 5, 6]
752        );
753
754        // normal3f[] normals = [(0, 1, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1), (0, 1, 0), (0, 0, 1), (1, 0, 0)]
755        let normals = data.get(&sdf::path("/World.normals")?, "default")?;
756        assert_eq!(
757            normals.try_as_vec_3f_ref().unwrap(),
758            &[0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0]
759        );
760
761        // double3 xformOp:rotateXYZ = (0, 0, 0)
762        let xform_op_rotate_xyz = data.get(&sdf::path("/World.xformOp:rotateXYZ")?, "default")?;
763        assert_eq!(xform_op_rotate_xyz.try_as_vec_3d_ref().unwrap(), &[0.0, 0.0, 0.0]);
764
765        // double3 xformOp:scale = (1, 1, 1)
766        let xform_op_scale = data.get(&sdf::path("/World.xformOp:scale")?, "default")?;
767        assert_eq!(xform_op_scale.try_as_vec_3d_ref().unwrap(), &[1.0, 1.0, 1.0]);
768
769        // double3 xformOp:translate = (0, 1, 0)
770        let xform_op_translate = data.get(&sdf::path("/World.xformOp:translate")?, "default")?;
771        assert_eq!(xform_op_translate.try_as_vec_3d_ref().unwrap(), &[0.0, 1.0, 0.0]);
772
773        Ok(())
774    }
775}