1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_USD_USD_OBJECT_H
25 #define PXR_USD_USD_OBJECT_H
26 
27 /// \file usd/object.h
28 
29 #include "pxr/pxr.h"
30 #include "pxr/usd/usd/api.h"
31 #include "pxr/usd/usd/common.h"
32 #include "pxr/usd/usd/primData.h"
33 #include "pxr/usd/usd/stage.h"
34 
35 #include "pxr/usd/sdf/abstractData.h"
36 #include "pxr/usd/sdf/path.h"
37 
38 #include <type_traits>
39 
40 PXR_NAMESPACE_OPEN_SCOPE
41 
42 
43 TF_DECLARE_WEAK_PTRS(UsdStage);
44 
45 /// \enum UsdObjType
46 ///
47 /// Enum values to represent the various Usd object types.
48 ///
49 enum UsdObjType
50 {
51     // Value order matters in this enum.
52     UsdTypeObject,
53     UsdTypePrim,
54     UsdTypeProperty,
55     UsdTypeAttribute,
56     UsdTypeRelationship,
57 
58     Usd_NumObjTypes
59 };
60 
61 
62 namespace _Detail {
63 
64 // A metafunction that takes a UsdObject class like UsdObject, UsdPrim,
65 // UsdProperty, etc, and gives its corresponding UsdObjType, e.g. UsdTypeObject,
66 // UsdTypePrim, UsdTypeProperty, etc.  Usage: GetObjType<UsdPrim>::Value.
67 template <UsdObjType Type>
68 struct Const { static const UsdObjType Value = Type; };
69 template <class T> struct GetObjType {
70     static_assert(std::is_base_of<UsdObject, T>::value,
71                   "Type T must be a subclass of UsdObject.");
72 };
73 template <> struct GetObjType<UsdObject> : Const<UsdTypeObject> {};
74 template <> struct GetObjType<UsdPrim> : Const<UsdTypePrim> {};
75 template <> struct GetObjType<UsdProperty> : Const<UsdTypeProperty> {};
76 template <> struct GetObjType<UsdAttribute> : Const<UsdTypeAttribute> {};
77 template <> struct GetObjType<UsdRelationship> : Const<UsdTypeRelationship> {};
78 
79 } // _Detail
80 
81 /// Return true if \a subType is the same as or a subtype of \a baseType, false
82 /// otherwise.
83 inline bool
84 UsdIsSubtype(UsdObjType baseType, UsdObjType subType) {
85     return (baseType == UsdTypeObject) || (baseType == subType) ||
86         (baseType == UsdTypeProperty && subType > UsdTypeProperty);
87 }
88 
89 /// Return true if \a from is convertible to \a to, false otherwise.  Equivalent
90 /// to UsdIsSubtype(to, from).
91 inline bool
92 UsdIsConvertible(UsdObjType from, UsdObjType to) {
93     return UsdIsSubtype(to, from);
94 }
95 
96 /// Return true if \a type is a concrete object type, namely one of Prim,
97 /// Attribute, or Relationship.
98 inline bool
99 UsdIsConcrete(UsdObjType type) {
100     return type == UsdTypePrim   ||
101         type == UsdTypeAttribute ||
102         type == UsdTypeRelationship;
103 }
104 
105 /// \class UsdObject
106 ///
107 /// Base class for Usd scenegraph objects, providing common API.
108 ///
109 /// The commonality between the three types of scenegraph objects in Usd
110 /// (\ref UsdPrim, \ref UsdAttribute, \ref UsdRelationship) is that they can
111 /// all have metadata.  Other objects in the API (\ref UsdReferences,
112 /// \ref UsdVariantSets, etc.) simply \em are kinds of metadata.
113 ///
114 /// UsdObject's API primarily provides schema for interacting with the metadata
115 /// common to all the scenegraph objects, as well as generic access to metadata.
116 ///
117 /// section Usd_UsdObject_Lifetime Lifetime Management and Object Validity
118 ///
119 /// Every derived class of UsdObject supports explicit detection of object
120 /// validity through an \em explicit-bool operator, so client code should always
121 /// be able use objects safely, even across edits to the owning UsdStage.
122 /// UsdObject classes also perform some level of validity checking upon every
123 /// use, in order to facilitate debugging of unsafe code, although we reserve
124 /// the right to activate that behavior only in debug builds, if it becomes
125 /// compelling to do so for performance reasons.  This per-use checking will
126 /// cause a fatal error upon failing the inline validity check, with an error
127 /// message describing the namespace location of the dereferenced object on its
128 /// owning UsdStage.
129 ///
130 class UsdObject {
131 public:
132     /// Default constructor produces an invalid object.
133     UsdObject() : _type(UsdTypeObject) {}
134 
135     // --------------------------------------------------------------------- //
136     /// \name Structural and Integrity Info about the Object itself
137     /// @{
138     // --------------------------------------------------------------------- //
139 
140     /// Return true if this is a valid object, false otherwise.
141     bool IsValid() const {
142         if (!UsdIsConcrete(_type) || !_prim)
143             return false;
144         if (_type == UsdTypePrim)
145             return true;
146         SdfSpecType specType = _GetDefiningSpecType();
147         return (_type == UsdTypeAttribute &&
148                 specType == SdfSpecTypeAttribute) ||
149             (_type == UsdTypeRelationship &&
150              specType == SdfSpecTypeRelationship);
151     }
152 
153     /// Returns \c true if this object is valid, \c false otherwise.
154     explicit operator bool() const {
155         return IsValid();
156     }
157 
158 public:
159 
160     /// Equality comparison.  Return true if \a lhs and \a rhs represent the
161     /// same UsdObject, false otherwise.
162     friend bool operator==(const UsdObject &lhs, const UsdObject &rhs) {
163         return lhs._type == rhs._type &&
164             lhs._prim == rhs._prim &&
165             lhs._proxyPrimPath == rhs._proxyPrimPath &&
166             lhs._propName == rhs._propName;
167     }
168 
169     /// Inequality comparison. Return false if \a lhs and \a rhs represent the
170     /// same UsdObject, true otherwise.
171     friend bool operator!=(const UsdObject &lhs, const UsdObject &rhs) {
172         return !(lhs == rhs);
173     }
174 
175     /// Less-than operator. Returns true if \a lhs < \a rhs.
176     ///
177     /// This simply compares the paths of the objects.
178     friend bool operator<(const UsdObject &lhs, const UsdObject &rhs) {
179         return lhs.GetPath() < rhs.GetPath();
180     }
181 
182     // hash_value overload for std/boost hash.
183     USD_API
184     friend size_t hash_value(const UsdObject &obj);
185 
186     /// Return the stage that owns the object, and to whose state and lifetime
187     /// this object's validity is tied.
188     USD_API
189     UsdStageWeakPtr GetStage() const;
190 
191     /// Return the complete scene path to this object on its UsdStage,
192     /// which may (UsdPrim) or may not (all other subclasses) return a
193     /// cached result
194     SdfPath GetPath() const {
195         // Allow getting expired object paths.
196         if (!_proxyPrimPath.IsEmpty()) {
197             return _type == UsdTypePrim ?
198                 _proxyPrimPath : _proxyPrimPath.AppendProperty(_propName);
199         }
200         else if (Usd_PrimDataConstPtr p = get_pointer(_prim)) {
201             return _type == UsdTypePrim ?
202                 p->GetPath() : p->GetPath().AppendProperty(_propName);
203         }
204         return SdfPath();
205     }
206 
207     /// Return this object's path if this object is a prim, otherwise this
208     /// object's nearest owning prim's path.  Equivalent to GetPrim().GetPath().
209     const SdfPath &GetPrimPath() const {
210         // Allow getting expired object paths.
211         if (!_proxyPrimPath.IsEmpty()) {
212             return _proxyPrimPath;
213         }
214         else if (Usd_PrimDataConstPtr p = get_pointer(_prim)) {
215             return p->GetPath();
216         }
217         return SdfPath::EmptyPath();
218     }
219 
220     /// Return this object if it is a prim, otherwise return this object's
221     /// nearest owning prim.
222     inline UsdPrim GetPrim() const;
223 
224     /// Return the full name of this object, i.e. the last component of its
225     /// SdfPath in namespace.
226     ///
227     /// This is equivalent to, but generally cheaper than,
228     /// GetPath().GetNameToken()
229     const TfToken &GetName() const {
230         return _type == UsdTypePrim ? GetPrimPath().GetNameToken() : _propName;
231     }
232 
233     /// Convert this UsdObject to another object type \p T if possible.  Return
234     /// an invalid \p T instance if this object's dynamic type is not
235     /// convertible to \p T or if this object is invalid.
236     template <class T>
237     T As() const {
238         // compile-time type assertion provided by invoking Is<T>().
239         return Is<T>() ? T(_type, _prim, _proxyPrimPath, _propName) : T();
240     }
241 
242     /// Return true if this object is convertible to \p T.  This is equivalent
243     /// to but cheaper than:
244     /// \code
245     /// bool(obj.As<T>())
246     /// \endcode
247     template <class T>
248     bool Is() const {
249         static_assert(std::is_base_of<UsdObject, T>::value,
250                       "Provided type T must derive from or be UsdObject");
251         return UsdIsConvertible(_type, _Detail::GetObjType<T>::Value);
252     }
253 
254     /// Return a string that provides a brief summary description of the
255     /// object.  This method, along with IsValid()/bool_operator,
256     /// is always safe to call on a possibly-expired object, and the
257     /// description will specify whether the object is valid or expired,
258     /// along with a few other bits of data.
259     USD_API
260     std::string GetDescription() const;
261 
262     // --------------------------------------------------------------------- //
263     /// @}
264     // --------------------------------------------------------------------- //
265 
266 
267     // --------------------------------------------------------------------- //
268     /// \name Generic Metadata Access
269     /// @{
270     // --------------------------------------------------------------------- //
271 
272     /// Resolve the requested metadatum named \p key into \p value,
273     /// returning true on success.
274     ///
275     /// \return false if \p key was not resolvable, or if \p value's
276     /// type \c T differed from that of the resolved metadatum.
277     ///
278     /// \note For any composition-related metadata, as enumerated in
279     /// GetAllMetadata(), this method will return only the strongest
280     /// opinion found, not applying the composition rules used by Pcp
281     /// to process the data.  For more processed/composed views of
282     /// composition data, please refer to the specific interface classes,
283     /// such as UsdReferences, UsdInherits, UsdVariantSets, etc.
284     ///
285     /// \sa \ref Usd_OM_Metadata
286     template<typename T>
287     bool GetMetadata(const TfToken& key, T* value) const;
288     /// \overload
289     ///
290     /// Type-erased access
291     USD_API
292     bool GetMetadata(const TfToken& key, VtValue* value) const;
293 
294     /// Set metadatum \p key's value to \p value.
295     ///
296     /// \return false if \p value's type does not match the schema type
297     /// for \p key.
298     ///
299     /// \sa \ref Usd_OM_Metadata
300     template<typename T>
301     bool SetMetadata(const TfToken& key, const T& value) const;
302     /// \overload
303     USD_API
304     bool SetMetadata(const TfToken& key, const VtValue& value) const;
305 
306     /// Clears the authored \a key's value at the current EditTarget,
307     /// returning false on error.
308     ///
309     /// If no value is present, this method is a no-op and returns true. It is
310     /// considered an error to call ClearMetadata when no spec is present for
311     /// this UsdObject, i.e. if the object has no presence in the
312     /// current UsdEditTarget.
313     ///
314     /// \sa \ref Usd_OM_Metadata
315     USD_API
316     bool ClearMetadata(const TfToken& key) const;
317 
318     /// Returns true if the \a key has a meaningful value, that is, if
319     /// GetMetadata() will provide a value, either because it was authored
320     /// or because a prim's metadata fallback will be provided.
321     USD_API
322     bool HasMetadata(const TfToken& key) const;
323 
324     /// Returns true if the \a key has an authored value, false if no
325     /// value was authored or the only value available is a prim's metadata
326     /// fallback.
327     USD_API
328     bool HasAuthoredMetadata(const TfToken& key) const;
329 
330     /// Resolve the requested dictionary sub-element \p keyPath of
331     /// dictionary-valued metadatum named \p key into \p value,
332     /// returning true on success.
333     ///
334     /// If you know you neeed just a small number of elements from a dictionary,
335     /// accessing them element-wise using this method can be much less
336     /// expensive than fetching the entire dictionary with GetMetadata(key).
337     ///
338     /// \return false if \p key was not resolvable, or if \p value's
339     /// type \c T differed from that of the resolved metadatum.
340     ///
341     /// The \p keyPath is a ':'-separated path addressing an element
342     /// in subdictionaries.
343     ///
344     /// \sa \ref Usd_Dictionary_Type
345     template <class T>
346     bool GetMetadataByDictKey(
347         const TfToken& key, const TfToken &keyPath, T *value) const;
348     /// \overload
349     USD_API
350     bool GetMetadataByDictKey(
351         const TfToken& key, const TfToken &keyPath, VtValue *value) const;
352 
353     /// Author \p value to the field identified by \p key and \p keyPath
354     /// at the current EditTarget.  The \p keyPath is a ':'-separated path
355     /// identifying a value in subdictionaries stored in the metadata field at
356     /// \p key.  Return true if the value is authored successfully, false
357     /// otherwise.
358     ///
359     /// \sa \ref Usd_Dictionary_Type
360     template<typename T>
361     bool SetMetadataByDictKey(
362         const TfToken& key, const TfToken &keyPath, const T& value) const;
363     /// \overload
364     USD_API
365     bool SetMetadataByDictKey(
366         const TfToken& key, const TfToken &keyPath, const VtValue& value) const;
367 
368     /// Clear any authored value identified by \p key and \p keyPath
369     /// at the current EditTarget.  The \p keyPath is a ':'-separated path
370     /// identifying a path in subdictionaries stored in the metadata field at
371     /// \p key.  Return true if the value is cleared successfully, false
372     /// otherwise.
373     ///
374     /// \sa \ref Usd_Dictionary_Type
375     USD_API
376     bool ClearMetadataByDictKey(
377         const TfToken& key, const TfToken& keyPath) const;
378 
379     /// Return true if there exists any authored or fallback opinion for
380     /// \p key and \p keyPath.  The \p keyPath is a ':'-separated path
381     /// identifying a value in subdictionaries stored in the metadata field at
382     /// \p key.
383     ///
384     /// \sa \ref Usd_Dictionary_Type
385     USD_API
386     bool HasMetadataDictKey(
387         const TfToken& key, const TfToken &keyPath) const;
388 
389     /// Return true if there exists any authored opinion (excluding
390     /// fallbacks) for \p key and \p keyPath.  The \p keyPath is a ':'-separated
391     /// path identifying a value in subdictionaries stored in the metadata field
392     /// at \p key.
393     ///
394     /// \sa \ref Usd_Dictionary_Type
395     USD_API
396     bool HasAuthoredMetadataDictKey(
397         const TfToken& key, const TfToken &keyPath) const;
398 
399     /// Resolve and return all metadata (including both authored and
400     /// fallback values) on this object, sorted lexicographically.
401     ///
402     /// \note This method does not return field keys for composition arcs,
403     /// such as references, inherits, payloads, sublayers, variants, or
404     /// primChildren, nor does it return the default value or timeSamples.
405     USD_API
406     UsdMetadataValueMap GetAllMetadata() const;
407 
408     /// Resolve and return all user-authored metadata on this object,
409     /// sorted lexicographically.
410     ///
411     /// \note This method does not return field keys for composition arcs,
412     /// such as references, inherits, payloads, sublayers, variants, or
413     /// primChildren, nor does it return the default value or timeSamples.
414     USD_API
415     UsdMetadataValueMap GetAllAuthoredMetadata() const;
416 
417     // --------------------------------------------------------------------- //
418     /// @}
419     // --------------------------------------------------------------------- //
420 
421     // --------------------------------------------------------------------- //
422     /// \name Core metadata fields
423     /// @{
424     // --------------------------------------------------------------------- //
425 
426     /// Gets the value of the 'hidden' metadata field, false if not
427     /// authored.
428     ///
429     /// When an object is marked as hidden, it is an indicator to clients who
430     /// generically display objects (such as GUI widgets) that this object
431     /// should not be included, unless explicitly asked for.  Although this
432     /// is just a hint and thus up to each application to interpret, we
433     /// use it primarily as a way of simplifying hierarchy displays, by
434     /// hiding \em only the representation of the object itself, \em not its
435     /// subtree, instead "pulling up" everything below it one level in the
436     /// hierarchical nesting.
437     ///
438     /// Note again that this is a hint for UI only - it should not be
439     /// interpreted by any renderer as making a prim invisible to drawing.
440     USD_API
441     bool IsHidden() const;
442 
443     /// Sets the value of the 'hidden' metadata field. See IsHidden()
444     /// for details.
445     USD_API
446     bool SetHidden(bool hidden) const;
447 
448     /// Clears the opinion for "Hidden" at the current EditTarget.
449     USD_API
450     bool ClearHidden() const;
451 
452     /// Returns true if hidden was explicitly authored and GetMetadata()
453     /// will return a meaningful value for Hidden.
454     ///
455     /// Note that IsHidden returns a fallback value (false) when hidden is not
456     /// authored.
457     USD_API
458     bool HasAuthoredHidden() const;
459 
460     /// Return this object's composed customData dictionary.
461     ///
462     /// CustomData is "custom metadata", a place for applications and users
463     /// to put uniform data that is entirely dynamic and subject to no schema
464     /// known to Usd.  Unlike metadata like 'hidden', 'displayName' etc,
465     /// which must be declared in code or a data file that is considered part
466     /// of one's Usd distribution (e.g. a plugInfo.json file) to be used,
467     /// customData keys and the datatypes of their corresponding values are
468     /// ad hoc.  No validation will ever be performed that values for the
469     /// same key in different layers are of the same type - strongest simply
470     /// wins.
471     ///
472     /// Dictionaries like customData are composed element-wise, and are
473     /// nestable.
474     ///
475     /// There is no means to query a customData field's valuetype other
476     /// than fetching the value and interrogating it.
477     /// \sa GetCustomDataByKey()
478     USD_API
479     VtDictionary GetCustomData() const;
480 
481     /// Return the element identified by \p keyPath in this object's
482     /// composed customData dictionary.  The \p keyPath is a ':'-separated path
483     /// identifying a value in subdictionaries.  This is in general more
484     /// efficient than composing the entire customData dictionary and then
485     /// pulling out one sub-element.
486     USD_API
487     VtValue GetCustomDataByKey(const TfToken &keyPath) const;
488 
489     /// Author this object's customData dictionary to \p customData at
490     /// the current EditTarget.
491     USD_API
492     void SetCustomData(const VtDictionary &customData) const;
493 
494     /// Author the element identified by \p keyPath in this object's
495     /// customData dictionary at the current EditTarget.  The \p keyPath is a
496     /// ':'-separated path identifying a value in subdictionaries.
497     USD_API
498     void SetCustomDataByKey(const TfToken &keyPath, const VtValue &value) const;
499 
500     /// Clear the authored opinion for this object's customData
501     /// dictionary at the current EditTarget.  Do nothing if there is no such
502     /// authored opinion.
503     USD_API
504     void ClearCustomData() const;
505 
506     /// Clear the authored opinion identified by \p keyPath in this
507     /// object's customData dictionary at the current EditTarget.  The \p
508     /// keyPath is a ':'-separated path identifying a value in subdictionaries.
509     /// Do nothing if there is no such authored opinion.
510     USD_API
511     void ClearCustomDataByKey(const TfToken &keyPath) const;
512 
513     /// Return true if there are any authored or fallback opinions for
514     /// this object's customData dictionary, false otherwise.
515     USD_API
516     bool HasCustomData() const;
517 
518     /// Return true if there are any authored or fallback opinions for
519     /// the element identified by \p keyPath in this object's customData
520     /// dictionary, false otherwise.  The \p keyPath is a ':'-separated path
521     /// identifying a value in subdictionaries.
522     USD_API
523     bool HasCustomDataKey(const TfToken &keyPath) const;
524 
525     /// Return true if there are any authored opinions (excluding
526     /// fallback) for this object's customData dictionary, false otherwise.
527     USD_API
528     bool HasAuthoredCustomData() const;
529 
530     /// Return true if there are any authored opinions (excluding
531     /// fallback) for the element identified by \p keyPath in this object's
532     /// customData dictionary, false otherwise.  The \p keyPath is a
533     /// ':'-separated path identifying a value in subdictionaries.
534     USD_API
535     bool HasAuthoredCustomDataKey(const TfToken &keyPath) const;
536 
537     /// Return this object's composed assetInfo dictionary.
538     ///
539     /// The asset info dictionary is used to annotate objects representing the
540     /// root-prims of assets (generally organized as models) with various
541     /// data related to asset management. For example, asset name, root layer
542     /// identifier, asset version etc.
543     ///
544     /// The elements of this dictionary are composed element-wise, and are
545     /// nestable.
546     ///
547     /// There is no means to query an assetInfo field's valuetype other
548     /// than fetching the value and interrogating it.
549     /// \sa GetAssetInfoByKey()
550     USD_API
551     VtDictionary GetAssetInfo() const;
552 
553     /// Return the element identified by \p keyPath in this object's
554     /// composed assetInfo dictionary.  The \p keyPath is a ':'-separated path
555     /// identifying a value in subdictionaries.  This is in general more
556     /// efficient than composing the entire assetInfo dictionary than
557     /// pulling out one sub-element.
558     USD_API
559     VtValue GetAssetInfoByKey(const TfToken &keyPath) const;
560 
561     /// Author this object's assetInfo dictionary to \p assetInfo at
562     /// the current EditTarget.
563     USD_API
564     void SetAssetInfo(const VtDictionary &customData) const;
565 
566     /// Author the element identified by \p keyPath in this object's
567     /// assetInfo dictionary at the current EditTarget.  The \p keyPath is a
568     /// ':'-separated path identifying a value in subdictionaries.
569     USD_API
570     void SetAssetInfoByKey(const TfToken &keyPath, const VtValue &value) const;
571 
572     /// Clear the authored opinion for this object's assetInfo
573     /// dictionary at the current EditTarget.  Do nothing if there is no such
574     /// authored opinion.
575     USD_API
576     void ClearAssetInfo() const;
577 
578     /// Clear the authored opinion identified by \p keyPath in this
579     /// object's assetInfo dictionary at the current EditTarget.  The \p
580     /// keyPath is a ':'-separated path identifying a value in subdictionaries.
581     /// Do nothing if there is no such authored opinion.
582     USD_API
583     void ClearAssetInfoByKey(const TfToken &keyPath) const;
584 
585     /// Return true if there are any authored or fallback opinions for
586     /// this object's assetInfo dictionary, false otherwise.
587     USD_API
588     bool HasAssetInfo() const;
589 
590     /// Return true if there are any authored or fallback opinions for
591     /// the element identified by \p keyPath in this object's assetInfo
592     /// dictionary, false otherwise.  The \p keyPath is a ':'-separated path
593     /// identifying a value in subdictionaries.
594     USD_API
595     bool HasAssetInfoKey(const TfToken &keyPath) const;
596 
597     /// Return true if there are any authored opinions (excluding
598     /// fallback) for this object's assetInfo dictionary, false otherwise.
599     USD_API
600     bool HasAuthoredAssetInfo() const;
601 
602     /// Return true if there are any authored opinions (excluding
603     /// fallback) for the element identified by \p keyPath in this object's
604     /// assetInfo dictionary, false otherwise.  The \p keyPath is a
605     /// ':'-separated path identifying a value in subdictionaries.
606     USD_API
607     bool HasAuthoredAssetInfoKey(const TfToken &keyPath) const;
608 
609     /// Return this object's documentation (metadata).  This returns the
610     /// empty string if no documentation has been set.
611     /// \sa SetDocumentation()
612     USD_API
613     std::string GetDocumentation() const;
614 
615     /// Sets this object's documentation (metadata).  Returns true on success.
616     USD_API
617     bool SetDocumentation(const std::string& doc) const;
618 
619     /// Clears this object's documentation (metadata) in the current EditTarget
620     /// (only).  Returns true on success.
621     USD_API
622     bool ClearDocumentation() const;
623 
624     /// Returns true if documentation was explicitly authored and GetMetadata()
625     /// will return a meaningful value for documentation.
626     USD_API
627     bool HasAuthoredDocumentation() const;
628 
629     // --------------------------------------------------------------------- //
630     /// @}
631     // --------------------------------------------------------------------- //
632 
633     // XXX: This method can and probably should move to UsdProperty
634     static char GetNamespaceDelimiter()
635         { return SdfPathTokens->namespaceDelimiter.GetText()[0]; }
636 
637 private:
638     template <class T>
639     bool _GetMetadataImpl(const TfToken& key,
640                           T* value,
641                           const TfToken &keyPath=TfToken()) const;
642 
643     bool _GetMetadataImpl(const TfToken& key,
644                           VtValue* value,
645                           const TfToken &keyPath=TfToken()) const;
646 
647     template <class T>
648     bool _SetMetadataImpl(const TfToken& key,
649                           const T& value,
650                           const TfToken &keyPath=TfToken()) const;
651 
652     bool _SetMetadataImpl(const TfToken& key,
653                           const VtValue& value,
654                           const TfToken &keyPath=TfToken()) const;
655 
656 protected:
657     template <class Derived> struct _Null {};
658 
659     // Private constructor for null dervied types.
660     template <class Derived>
661     explicit UsdObject(_Null<Derived>)
662         : _type(_Detail::GetObjType<Derived>::Value) {}
663 
664     // Private constructor for UsdPrim.
665     UsdObject(const Usd_PrimDataHandle &prim,
666               const SdfPath &proxyPrimPath)
667         : _type(UsdTypePrim)
668         , _prim(prim)
669         , _proxyPrimPath(proxyPrimPath)
670     {
671         TF_VERIFY(!_prim || _prim->GetPath() != _proxyPrimPath);
672     }
673 
674     // Private constructor for UsdAttribute/UsdRelationship.
675     UsdObject(UsdObjType objType,
676               const Usd_PrimDataHandle &prim,
677               const SdfPath &proxyPrimPath,
678               const TfToken &propName)
679         : _type(objType)
680         , _prim(prim)
681         , _proxyPrimPath(proxyPrimPath)
682         , _propName(propName)
683     {
684         TF_VERIFY(!_prim || _prim->GetPath() != _proxyPrimPath);
685     }
686 
687     // Return the stage this object belongs to.
688     UsdStage *_GetStage() const { return _prim->GetStage(); }
689 
690     // Return this object's defining spec type.
691     USD_API
692     SdfSpecType _GetDefiningSpecType() const;
693 
694     // Helper for subclasses: return held prim data.
695     const Usd_PrimDataHandle &_Prim() const { return _prim; }
696 
697     // Helper for subclasses: return held property name.
698     const TfToken &_PropName() const { return _propName; }
699 
700     // Helper for subclasses: return held proxy prim path.
701     const SdfPath &_ProxyPrimPath() const { return _proxyPrimPath; }
702 
703 private:
704     // Helper for the above helper, and also for GetDescription()
705     std::string _GetObjectDescription(const std::string &preface) const;
706 
707     friend class UsdStage;
708 
709     friend UsdObjType Usd_GetObjType(const UsdObject &obj) {
710         return obj._type;
711     }
712 
713     UsdObjType _type;
714     Usd_PrimDataHandle _prim;
715     SdfPath _proxyPrimPath;
716     TfToken _propName;
717 
718 };
719 
720 template<typename T>
721 inline
722 bool
723 UsdObject::GetMetadata(const TfToken& key, T* value) const
724 {
725     return _GetMetadataImpl(key, value);
726 }
727 
728 template<typename T>
729 inline
730 bool
731 UsdObject::SetMetadata(const TfToken& key, const T& value) const
732 {
733     return _SetMetadataImpl(key, value);
734 }
735 
736 template <typename T>
737 inline
738 bool
739 UsdObject::GetMetadataByDictKey(const TfToken& key,
740                                 const TfToken &keyPath,
741                                 T *value) const
742 {
743     return _GetMetadataImpl(key, value, keyPath);
744 }
745 
746 template <typename T>
747 inline
748 bool
749 UsdObject::SetMetadataByDictKey(const TfToken& key,
750                                 const TfToken &keyPath,
751                                 const T& value) const
752 {
753     return _SetMetadataImpl(key, value, keyPath);
754 }
755 
756 template <class T>
757 bool
758 UsdObject::_GetMetadataImpl(const TfToken& key,
759                             T* value,
760                             const TfToken &keyPath) const
761 {
762     return _GetStage()->_GetMetadata(
763         *this, key, keyPath, /*useFallbacks=*/true, value);
764 }
765 
766 template <class T>
767 bool
768 UsdObject::_SetMetadataImpl(const TfToken& key,
769                             const T& value,
770                             const TfToken &keyPath) const
771 {
772     return _GetStage()->_SetMetadata(*this, key, keyPath, value);
773 }
774 
775 PXR_NAMESPACE_CLOSE_SCOPE
776 
777 #endif //PXR_USD_USD_OBJECT_H
778