Skip to main content

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