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