use openusd::sdf;
pub fn rust_type(kind: sdf::ValueKind) -> Option<syn::Type> {
let spelled = match kind.element_kind() {
Some(element) => format!("::std::vec::Vec<{}>", scalar_type(element)?),
None => scalar_type(kind)?.to_owned(),
};
Some(syn::parse_str(&spelled).expect("every spelling below is a Rust type"))
}
fn scalar_type(kind: sdf::ValueKind) -> Option<&'static str> {
Some(match kind {
sdf::ValueKind::Bool => "bool",
sdf::ValueKind::Uchar => "u8",
sdf::ValueKind::Int => "i32",
sdf::ValueKind::Uint => "u32",
sdf::ValueKind::Int64 => "i64",
sdf::ValueKind::Uint64 => "u64",
sdf::ValueKind::Half => "::openusd::gf::f16",
sdf::ValueKind::Float => "f32",
sdf::ValueKind::Double => "f64",
sdf::ValueKind::String => "::std::string::String",
sdf::ValueKind::Token => "::openusd::tf::Token",
sdf::ValueKind::AssetPath => "::openusd::sdf::AssetPath",
sdf::ValueKind::TimeCode => "::openusd::sdf::TimeCode",
sdf::ValueKind::PathExpression => "::openusd::sdf::PathExpression",
sdf::ValueKind::Vec2h => "::openusd::gf::Vec2h",
sdf::ValueKind::Vec2f => "::openusd::gf::Vec2f",
sdf::ValueKind::Vec2d => "::openusd::gf::Vec2d",
sdf::ValueKind::Vec2i => "::openusd::gf::Vec2i",
sdf::ValueKind::Vec3h => "::openusd::gf::Vec3h",
sdf::ValueKind::Vec3f => "::openusd::gf::Vec3f",
sdf::ValueKind::Vec3d => "::openusd::gf::Vec3d",
sdf::ValueKind::Vec3i => "::openusd::gf::Vec3i",
sdf::ValueKind::Vec4h => "::openusd::gf::Vec4h",
sdf::ValueKind::Vec4f => "::openusd::gf::Vec4f",
sdf::ValueKind::Vec4d => "::openusd::gf::Vec4d",
sdf::ValueKind::Vec4i => "::openusd::gf::Vec4i",
sdf::ValueKind::Quath => "::openusd::gf::Quath",
sdf::ValueKind::Quatf => "::openusd::gf::Quatf",
sdf::ValueKind::Quatd => "::openusd::gf::Quatd",
sdf::ValueKind::Matrix2d => "::openusd::gf::Mat2d",
sdf::ValueKind::Matrix3d => "::openusd::gf::Mat3d",
sdf::ValueKind::Matrix4d => "::openusd::gf::Matrix4d",
_ => return None,
})
}
#[cfg(test)]
mod tests {
use super::*;
use quote::ToTokens;
fn spelled(kind: sdf::ValueKind) -> Option<String> {
rust_type(kind).map(|ty| ty.to_token_stream().to_string().replace(' ', ""))
}
#[test]
fn every_attribute_type_maps() {
for type_name in sdf::ValueTypeName::all() {
let Some(kind) = type_name.kind() else { continue };
if kind == sdf::ValueKind::Opaque {
continue;
}
assert!(
rust_type(kind).is_some(),
"{} has no Rust type",
type_name.serialization_name()
);
}
assert_eq!(spelled(sdf::ValueKind::Float).as_deref(), Some("f32"));
assert_eq!(
spelled(sdf::ValueKind::Vec3fVec).as_deref(),
Some("::std::vec::Vec<::openusd::gf::Vec3f>")
);
assert_eq!(
spelled(sdf::ValueKind::TokenVec).as_deref(),
Some("::std::vec::Vec<::openusd::tf::Token>")
);
}
#[test]
fn roles_share_a_type() {
for spelling in ["float3", "point3f", "normal3f", "vector3f", "color3f"] {
let kind = sdf::ValueTypeName::find(spelling).and_then(|type_name| type_name.kind());
assert_eq!(
kind.and_then(spelled).as_deref(),
Some("::openusd::gf::Vec3f"),
"{spelling}"
);
}
}
#[test]
fn opaque_has_no_type() {
assert!(rust_type(sdf::ValueKind::Opaque).is_none());
}
}