Crate shapely

Source
Expand description

§shapely

experimental free of syn crates.io documentation MIT/Apache-2.0 licensed

shapely provides runtime reflection for Rust.

Any type that implements Shapely trait returns a Shape, which describes:

  • The memory layout of the type
  • Its innards: struct fields, underlying type for newtypes, etc.
  • How to drop it in place

The Partial type is able to allocate (or work from a &mut MaybeUninit<T>) any Shapely type, and gradually initialize its fields — until the fully-built value is moved out of the partial.

It comes with a derive macro that uses unsynn for speed of compilation.

§Ecosystem

The main shapely crate re-exports symbols from:

  • shapely-core, which defines the main Shapely trait and the Shape struct
  • shapely-derive, which implements the Shapely derive attribute as a fast/light proc macro powered by unsynn

shapely supports deserialization from multiple data formats through dedicated crates:

Additionally:

§Implementing Your Own Deserializer

To implement a custom deserializer for a new format, you’ll need to work with the following key components from shapely:

§Key Types

  • Partial: The central type for building shapely values incrementally
  • Shape: Describes the memory layout and structure of a type
  • Innards: Represents the internal structure (Scalar, Struct, etc.)
  • Scalar: Represents primitive types like String, u64, etc.

§Implementation Pattern

  1. Create a function that takes a &mut Partial and your format’s input (string, bytes, etc.)
  2. Examine the shape of the partial using Partial::shape
  3. Handle different shapes based on Shape::innards:

When in doubt, refer to the shapely-json implementation — it’s the most featureful.

§Example Implementation Skeleton

use shapely_core::{Partial, Innards, Scalar, FieldError, Shape};
use std::convert::From;

#[derive(Debug)]
pub enum MyFormatError {
    UnsupportedType,
    UnsupportedShape,
    FieldError(FieldError),
}

impl From<FieldError> for MyFormatError {
    fn from(err: FieldError) -> Self {
        MyFormatError::FieldError(err)
    }
}

pub fn from_my_format(partial: &mut Partial, input: &[u8]) -> Result<(), MyFormatError> {
    let shape_desc = partial.shape();
    let shape = shape_desc.get();

    match &shape.innards {
        Innards::Scalar(scalar) => {
            let slot = partial.scalar_slot().expect("Scalar slot");
            // Parse scalar value from input and fill slot
            match scalar {
                Scalar::String => slot.fill("/* parsed string */".to_string()),
                Scalar::U64 => slot.fill(0u64),
                // Handle other scalar types
                _ => return Err(MyFormatError::UnsupportedType),
            }
        },
        Innards::Struct { .. } => {
            // Parse struct fields from input
            for (field_name, field_value) in [("field1", "value1"), ("field2", "value2")].iter() {
                let slot = partial.slot_by_name(field_name)?;

                // Create a partial for the field and fill it recursively
                let mut partial_field = Partial::alloc(slot.shape());
                // Recursively deserialize field_value into partial_field
                // ...
                slot.fill_from_partial(partial_field);
            }
        },
        // Handle other shapes as needed
        _ => return Err(MyFormatError::UnsupportedShape),
    }

    Ok(())
}

For more detailed examples, examine the implementation of existing deserializers like shapely-json or shapely-msgpack.

§Funding

Thanks to Namespace for providing fast GitHub Actions workers:

§License

Licensed under either of:

at your option.

Modules§

mini_typeid
vendored straight from https://github.com/dtolnay/typeid — which is dual-licensed under MIT and Apache-2.0.

Structs§

ArraySlot
A helper struct to fill up arrays — note that it is designed for Vec<T> rather than fixed-size arrays or slices, so it’s a bit of a misnomer at the moment.
Bytes
A wrapper around Vec<u8> for binary data
Field
Describes a field in a struct or tuple
FieldFlags
Flags that can be applied to fields to modify their behavior
HashMapIter
An iterator over key-value pairs in a HashMap
HashMapSlot
Provides insert, length check, and iteration over a type-erased hashmap
InitSet64
A bit array to keep track of which fields were initialized, up to 64 fields
ListVTable
Virtual table for a list-like type (like Vec<T>, but also HashSet<T>, etc.)
MapIterVTable
VTable for an iterator over a map
MapVTable
Virtual table for a Map<String, T>
NameOpts
Options for formatting the name of a type
Partial
A partially-initialized shape.
Shape
Schema for reflection of a type
ShapeDesc
A function that returns a shape. There should only be one of these per concrete type in a
Slot
Allows writing into a struct field.
Variant
Describes a variant of an enum

Enums§

EnumRepr
All possible representations for Rust enums
FieldError
Errors encountered when calling field_by_index or field_by_name
InitMark
InitMark is used to track the initialization state of a single field within an InitSet64. It is part of a system used to progressively initialize structs, where each field’s initialization status is represented by a bit in a 64-bit set.
Innards
The shape of a schema: is it more map-shaped, array-shaped, scalar-shaped?
Origin
Origin of the partial — did we allocate it? Or is it borrowed?
Scalar
A scalar type in Rust, representing a single value.
ScalarContents
Represents the contents of a scalar value with a lifetime. This allows safe access to the actual values stored in memory.
VariantError
All possible errors when getting a variant by index or by name
VariantKind
Represents the different kinds of variants that can exist in a Rust enum

Traits§

Shapely
Allows querying the Shape of a type, which in turn lets us inspect any fields, build a value of this type progressively, etc.

Type Aliases§

DropFn
A function that drops a value at a specific memory address
NameFn
A function that formats the name of a type.
SetToDefaultFn
A function that sets a value to its default at a specific memory address

Derive Macros§

Shapely
Derive the [shapely_core::Shapely] trait for structs, tuple structs, and enums.