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}