From 3e7e51e5749015ce6f0732765689b1cee2b1b2e7 Mon Sep 17 00:00:00 2001 From: Maksym Pavlenko Date: Tue, 7 Apr 2026 18:51:54 -0700 Subject: [PATCH 1/2] Allow type name on all prim specifiers The parser previously only accepted a type name after def and class. USD allows type names on over as well, e.g. over MfScope "TestOver". --- src/usda/parser.rs | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/usda/parser.rs b/src/usda/parser.rs index 44e3511..8d6d308 100644 --- a/src/usda/parser.rs +++ b/src/usda/parser.rs @@ -290,17 +290,14 @@ impl<'a> Parser<'a> { }; let mut name_token = self.fetch_next()?; - if specifier == sdf::Specifier::Def || specifier == sdf::Specifier::Class { - if let Some(prim_type) = name_token.clone().try_as_identifier() { - spec.add(FieldKey::TypeName, sdf::Value::Token(prim_type.to_string())); - name_token = self.fetch_next()?; - } + if let Token::Identifier(prim_type) = name_token { + spec.add(FieldKey::TypeName, sdf::Value::Token(prim_type.to_string())); + name_token = self.fetch_next()?; } - let name = name_token - .clone() - .try_as_string() - .ok_or_else(|| anyhow!("Unexpected token {name_token:?} (want String)"))?; + let Token::String(name) = name_token else { + bail!("Expected prim name string, got {name_token:?}"); + }; parent_children.push(name.to_string()); let prim_path = current_path.append_path(name)?; @@ -2569,4 +2566,29 @@ def Scope "Root" { ); assert_eq!(spec.fields.get("default"), Some(&sdf::Value::IntVec(vec![5, 6, 7]))); } + + /// `over` with a type name should parse the type and prim name. + #[test] + fn parse_over_with_type_name() { + let mut parser = Parser::new( + r#" +#usda 1.0 + +over MfScope "TestOver" +{ +} +"#, + ); + let data = parser.parse().unwrap(); + let path = sdf::path("/TestOver").unwrap(); + let spec = data.get(&path).expect("TestOver not found"); + assert_eq!( + spec.fields.get(FieldKey::Specifier.as_str()), + Some(&sdf::Value::Specifier(sdf::Specifier::Over)) + ); + assert_eq!( + spec.fields.get(FieldKey::TypeName.as_str()), + Some(&sdf::Value::Token("MfScope".into())) + ); + } } From a2a81b145a20724daffe01f1def93fdc472fbe78 Mon Sep 17 00:00:00 2001 From: Maksym Pavlenko Date: Tue, 7 Apr 2026 18:55:21 -0700 Subject: [PATCH 2/2] Support displayName prim metadata Parse displayName as a string metadata field on prims. Supports full UTF-8 content as per the USD spec. --- src/usda/parser.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/usda/parser.rs b/src/usda/parser.rs index 8d6d308..e91d7bc 100644 --- a/src/usda/parser.rs +++ b/src/usda/parser.rs @@ -792,6 +792,11 @@ impl<'a> Parser<'a> { let value = self.parse_bool().context("Unable to parse instanceable flag")?; spec.add(FieldKey::Instanceable, sdf::Value::Bool(value)); } + "displayName" => { + ensure!(list_op.is_none(), "displayName does not support list ops"); + let value = self.fetch_str().context("Unable to parse displayName")?; + spec.add("displayName", sdf::Value::String(value.to_owned())); + } other => bail!("Unsupported prim metadata: {other}"), } @@ -2591,4 +2596,39 @@ over MfScope "TestOver" Some(&sdf::Value::Token("MfScope".into())) ); } + + /// Prim metadata `displayName` should be parsed as a string. + #[test] + fn parse_prim_display_name() { + let mut parser = Parser::new( + r#" +#usda 1.0 + +def Scope "Root" ( + displayName = "My Root" +) +{ +} +"#, + ); + let data = parser.parse().unwrap(); + let path = sdf::path("/Root").unwrap(); + let spec = data.get(&path).unwrap(); + assert_eq!( + spec.fields.get("displayName"), + Some(&sdf::Value::String("My Root".into())) + ); + } + + #[test] + fn parse_prim_display_name_utf8() { + let input = "#usda 1.0\ndef Scope \"R\" (\n displayName = \"\u{1F680}\"\n)\n{\n}\n"; + let mut parser = Parser::new(input); + let data = parser.parse().unwrap(); + let spec = data.get(&sdf::path("/R").unwrap()).unwrap(); + assert_eq!( + spec.fields.get("displayName"), + Some(&sdf::Value::String("\u{1F680}".into())) + ); + } }