openusd/sdf/mod.rs
1//! Scene description foundations.
2//!
3//! This module contains common data types used by parsers.
4//! Roughly this correspond to C++ SDF module <https://openusd.org/dev/api/sdf_page_front.html>
5
6use std::{borrow::Cow, collections::HashMap, fmt::Debug};
7
8use anyhow::Result;
9use bytemuck::{Pod, Zeroable};
10use strum::{Display, EnumCount, FromRepr};
11
12mod path;
13pub mod schema;
14mod value;
15
16pub use path::{path, Path};
17pub use value::Value;
18
19/// An enum that specifies the type of an object.
20/// Objects are entities that have fields and are addressable by path.
21#[repr(u32)]
22#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, FromRepr, EnumCount, Display)]
23pub enum SpecType {
24 // The unknown type has a value of 0 so that SdfSpecType() is unknown.
25 #[default]
26 Unknown = 0,
27
28 // Real concrete types
29 Attribute = 1,
30 Connection = 2,
31 Expression = 3,
32 Mapper = 4,
33 MapperArg = 5,
34 Prim = 6,
35 PseudoRoot = 7,
36 Relationship = 8,
37 RelationshipTarget = 9,
38 Variant = 10,
39 VariantSet = 11,
40}
41
42#[repr(i32)]
43#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromRepr)]
44pub enum Specifier {
45 Def,
46 Over,
47 Class,
48}
49
50/// An enum that defines permission levels.
51///
52/// Permissions control which layers may refer to or express
53/// opinions about a prim. Opinions expressed about a prim, or
54/// relationships to that prim, by layers that are not allowed
55/// permission to access the prim will be ignored.
56#[repr(i32)]
57#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromRepr)]
58pub enum Permission {
59 Public,
60 Private,
61}
62
63/// An enum that identifies variability types for attributes.
64/// Variability indicates whether the attribute may vary over time and
65/// value coordinates, and if its value comes through authoring or
66/// or from its owner.
67#[repr(i32)]
68#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromRepr)]
69pub enum Variability {
70 Varying,
71 Uniform,
72}
73
74/// Represents a time offset and scale between layers.
75#[repr(C)]
76#[derive(Debug, Clone, Copy, Pod, Zeroable)]
77pub struct LayerOffset {
78 /// Time offset.
79 pub offset: f64,
80 /// Scale factor.
81 pub scale: f64,
82}
83
84impl Default for LayerOffset {
85 fn default() -> Self {
86 Self {
87 offset: 0.0,
88 scale: 1.0,
89 }
90 }
91}
92
93impl LayerOffset {
94 #[inline]
95 pub fn new(offset: f64, scale: f64) -> Self {
96 Self { offset, scale }
97 }
98
99 #[inline]
100 pub fn is_valid(&self) -> bool {
101 self.offset.is_finite() && self.scale.is_finite()
102 }
103}
104
105/// Represents a payload and all its meta data.
106///
107/// A payload represents a prim reference to an external layer. A payload
108/// is similar to a prim reference (see SdfReference) with the major
109/// difference that payloads are explicitly loaded by the user.
110///
111/// Unloaded payloads represent a boundary that lazy composition and
112/// system behaviors will not traverse across, providing a user-visible
113/// way to manage the working set of the scene.
114#[derive(Debug, Default, Clone)]
115pub struct Payload {
116 /// The asset path to the external layer.
117 pub asset_path: String,
118 /// The root prim path to the referenced prim in the external layer.
119 pub prim_path: Path,
120 /// The layer offset to transform time.
121 pub layer_offset: Option<LayerOffset>,
122}
123
124/// Represents a reference and all its meta data.
125///
126/// A reference is expressed on a prim in a given layer and it identifies a
127/// prim in a layer stack. All opinions in the namespace hierarchy
128/// under the referenced prim will be composed with the opinions in the
129/// namespace hierarchy under the referencing prim.
130#[derive(Debug, Default, Clone)]
131pub struct Reference {
132 /// The asset path to the external layer.
133 pub asset_path: String,
134 /// The path to the referenced prim in the external layer.
135 pub prim_path: Path,
136 /// The layer offset to transform time.
137 pub layer_offset: LayerOffset,
138 /// The custom data associated with the reference.
139 pub custom_data: HashMap<String, Value>,
140}
141
142/// Value type representing a list-edit operation.
143///
144/// `ListOp`` is a value type representing an operation that edits a list.
145/// It may add or remove items, reorder them, or replace the list entirely.
146#[derive(Default, Debug, Clone)]
147pub struct ListOp<T: Default + Clone> {
148 pub explicit: bool,
149 pub explicit_items: Vec<T>,
150 pub added_items: Vec<T>,
151 pub prepended_items: Vec<T>,
152 pub appended_items: Vec<T>,
153 pub deleted_items: Vec<T>,
154 pub ordered_items: Vec<T>,
155}
156
157pub type IntListOp = ListOp<i32>;
158pub type UintListOp = ListOp<u32>;
159
160pub type Int64ListOp = ListOp<i64>;
161pub type Uint64ListOp = ListOp<u64>;
162
163pub type StringListOp = ListOp<String>;
164pub type TokenListOp = ListOp<String>;
165pub type PathListOp = ListOp<Path>;
166pub type ReferenceListOp = ListOp<Reference>;
167pub type PayloadListOp = ListOp<Payload>;
168
169pub type TimeSampleMap = Vec<(f64, Value)>;
170
171/// Interface to access scene description data similar to `SdfAbstractData` in C++ version of USD.
172///
173/// `AbstractData` is an anonymous container that owns scene description values.
174///
175/// For now holds read-only portion of the API.
176pub trait AbstractData {
177 /// Returns `true` if this data has a spec for the given path.
178 fn has_spec(&self, path: &Path) -> bool;
179
180 /// Returns `true` if this data has a field for the given path.
181 fn has_field(&self, path: &Path, field: &str) -> bool;
182
183 /// Returns the type of the spec at the given path.
184 fn spec_type(&self, path: &Path) -> Option<SpecType>;
185
186 /// Returns the underlying value for the given path.
187 ///
188 /// # Return
189 /// Returns a [Value] enum that wraps possible field's values.
190 ///
191 /// The value can be either owned or borrowed depending on internals.
192 /// In the binary format, the data is typically compressed and/or encoded,
193 /// so memory allocation is required to store unpacked result, so
194 /// owned values are typically be expected.
195 ///
196 /// With test parsers, there is a data copy already stored, so
197 /// a borrowed value will be returned to avoid unnecessary copies.
198 fn get(&mut self, path: &Path, field: &str) -> Result<Cow<Value>>;
199
200 /// Returns the names of the fields for the given path.
201 fn list(&self, path: &Path) -> Option<Vec<String>>;
202}
203
204#[derive(Debug)]
205pub struct Spec {
206 /// Specifies the type of an object.
207 pub ty: SpecType,
208 /// Spec properties.
209 pub fields: HashMap<String, Value>,
210}
211
212impl Spec {
213 /// Create a new empty spec of the give type.
214 pub fn new(ty: SpecType) -> Self {
215 Self {
216 ty,
217 fields: Default::default(),
218 }
219 }
220
221 /// Add a new field to the spec.
222 #[inline]
223 pub fn add(&mut self, key: impl Into<&'static str>, value: impl Into<Value>) {
224 self.fields.insert(key.into().to_owned(), value.into());
225 }
226}