Skip to main content

TypeRegistry

Struct TypeRegistry 

Source
pub struct TypeRegistry { /* private fields */ }
Expand description

A runtime mapping of ShapeId to RegistryEntry.

Backed by a HashMap<ShapeId<'static>, RegistryEntry>. Construct via TypeRegistry::builder for the most common pattern, or TypeRegistry::new/Default::default for an empty registry.

Use TypeRegistry::compose to merge two registries; entries in the argument registry override entries with the same shape ID in self.

§Cross-lifetime lookup

Internal storage is keyed by ShapeId<'static> (codegen-emitted shapes always have static lifetime). The public schema_for / entry_for methods accept &ShapeId<'_> of any lifetime; lookup is by fully qualified name via ShapeId’s Borrow<str> impl. The companion *_fqn methods take &str directly — handy after extracting a __type field from a wire-format JSON document.

Implementations§

Source§

impl TypeRegistry

Source

pub fn new() -> Self

Create an empty registry.

Source

pub fn builder() -> TypeRegistryBuilder

Start building a registry. See TypeRegistryBuilder.

Source

pub fn schema_for(&self, id: &ShapeId<'_>) -> Option<&'static Schema<'static>>

Look up the static schema for id, or None if not registered.

Accepts a ShapeId of any lifetime — lookup is by fully qualified name. ShapeId<'static> (codegen-emitted) and a runtime-built ShapeId<'_> with the same FQN resolve to the same entry.

Source

pub fn schema_for_fqn(&self, fqn: &str) -> Option<&'static Schema<'static>>

Look up the static schema for the given fully qualified name (e.g. "smithy.example#Bird").

Use this when you already have the FQN as a string slice — for instance, after extracting a __type discriminator from a JSON document.

§Example
use aws_smithy_schema::prelude;
use aws_smithy_schema::registry::TypeRegistry;
use aws_smithy_schema::serde::{SerdeError, ShapeDeserializer};
use aws_smithy_types::type_erasure::TypeErasedBox;

fn deserialize_string(d: &mut dyn ShapeDeserializer) -> Result<TypeErasedBox, SerdeError> {
    Ok(TypeErasedBox::new(d.read_string(&prelude::STRING)?))
}

let registry = TypeRegistry::builder()
    .insert_shape(&prelude::STRING, deserialize_string)
    .build();

// FQN extracted at runtime — for instance from a wire-format
// `__type` field — looks up against the static registry.
assert!(registry.schema_for_fqn("smithy.api#String").is_some());
assert!(registry.schema_for_fqn("smithy.api#Boolean").is_none());
Source

pub fn entry_for(&self, id: &ShapeId<'_>) -> Option<&RegistryEntry>

Look up the entry (schema + deserialize fn) for id, or None if not registered.

Accepts a ShapeId of any lifetime; see Self::schema_for.

Source

pub fn entry_for_fqn(&self, fqn: &str) -> Option<&RegistryEntry>

Look up the entry for the given fully qualified name. See Self::schema_for_fqn.

Source

pub fn entry_for_error_code(&self, wire_code: &str) -> Option<&RegistryEntry>

Look up the entry for an error shape by its wire error code (e.g. "NotFound"), rather than by fully qualified name.

Error responses identify the error by a bare code on the wire — the <Code> element for restXml, the __type discriminator for the JSON protocols, the x-amzn-query-error header for awsQueryCompatible — not by a fully qualified ShapeId. This resolves such a code to its entry so a schema-serde error path can reify an error by the identifier it actually receives off the wire.

wire_code is sanitized first (a leading namespace# prefix and a trailing :url suffix are stripped), so a bare name, a fully qualified name, or a URL-suffixed code all resolve correctly. Matching is by the registered shape’s name; per-operation and per-service error sets are small, so a linear scan is sufficient and needs no extra generated index.

Returns None if no registered shape’s name matches the code.

Source

pub fn deserialize_document( &self, document: &DiscriminatedDocument, ) -> Result<TypeErasedBox, SerdeError>

Deserialize the given document into the shape pointed to by its discriminator.

Returns Err(SerdeError::InvalidInput { .. }) if the document has no discriminator, and Err(SerdeError::UnknownMember { .. }) if the discriminator does not match a registered shape.

On success, the returned [TypeErasedBox] carries an instance of the concrete data type that the registered DeserializeFn produces. Callers downcast via [TypeErasedBox::downcast].

The document’s lifetime is independent of the registry’s storage — runtime-parsed documents (e.g. with a __type discriminator borrowed from input bytes) resolve against the 'static-keyed registry via FQN matching.

§Example
use aws_smithy_schema::prelude;
use aws_smithy_schema::registry::TypeRegistry;
use aws_smithy_schema::serde::{SerdeError, ShapeDeserializer};
use aws_smithy_types::{DiscriminatedDocument, Document};
use aws_smithy_types::type_erasure::TypeErasedBox;

fn deserialize_string(d: &mut dyn ShapeDeserializer) -> Result<TypeErasedBox, SerdeError> {
    Ok(TypeErasedBox::new(d.read_string(&prelude::STRING)?))
}

let registry = TypeRegistry::builder()
    .insert_shape(&prelude::STRING, deserialize_string)
    .build();

// Build a discriminated document. In practice this typically comes
// from `JsonDeserializer::read_discriminated_document` after a
// wire-format `__type` lift.
let doc = DiscriminatedDocument::new(Document::String("hi".to_string()))
    .with_discriminator("smithy.api#String");

let typed = registry.deserialize_document(&doc).unwrap();
let value = typed.downcast::<String>().unwrap();
assert_eq!(*value, "hi");
Source

pub fn compose(self, other: TypeRegistry) -> TypeRegistry

Combine self and other into a new registry containing the union of their entries.

On shape ID collision, entries from other override entries in self. This matches the typical use case where the caller wants extension-package entries to take precedence over base-package entries.

Source

pub fn or<'a>(&'a self, fallback: &'a TypeRegistry) -> ComposedRegistry<'a>

Borrow self and fallback into a ComposedRegistry whose lookups consult self first and fall back to fallback.

Unlike compose, this neither consumes nor copies either registry — both are borrowed in place, so two &'static registries (the typical case for codegen-emitted statics) can be layered per call with no allocation.

The precedence — self wins over fallback on a colliding lookup — is what makes this useful for operation-scoped error resolution: layer an operation’s own error registry over the service-wide one so the operation’s modeled errors take priority before widening to the rest of the service closure.

Source

pub fn iter(&self) -> Iter<'_> ⓘ

Iterate the registry’s (ShapeId, RegistryEntry) pairs. Iteration order is unspecified.

Source

pub fn len(&self) -> usize

Number of registered entries.

Source

pub fn is_empty(&self) -> bool

true iff the registry has no entries.

Trait Implementations§

Source§

impl Debug for TypeRegistry

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for TypeRegistry

Source§

fn default() -> TypeRegistry

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<Unshared, Shared> IntoShared<Shared> for Unshared
where Shared: FromUnshared<Unshared>,

§

fn into_shared(self) -> Shared

Creates a shared type from an unshared type.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more