planus/traits/
mod.rs

1use core::mem::MaybeUninit;
2
3use crate::{
4    builder::Builder, errors::ErrorKind, slice_helpers::SliceWithStartOffset, Cursor, Offset,
5    Result, UnionOffset, UnionVectorOffset,
6};
7
8#[doc(hidden)]
9/// # Safety
10/// `ALIGNMENT` match the actual alignment requirements of the type. It most likely is a power of two.
11/// `SIZE` match the actual size of the type. For primitive types, that is core::mem::size_of::<Self>().
12pub unsafe trait Primitive {
13    const ALIGNMENT: usize;
14    const ALIGNMENT_MASK: usize = Self::ALIGNMENT - 1;
15    const SIZE: usize;
16}
17
18/// Interface for getting a view into serialized data.
19///
20/// To get an owned variant use [`TryInto`] on the `Ref` type. Note that for
21/// nested types with lots of sharing the owned variants can be much larger than
22/// the serialized representation.
23///
24/// # Examples
25///
26/// ```no_run
27/// use std::error::Error;
28/// use planus::ReadAsRoot;
29/// use planus_example::monster_generated::my_game::sample::{Monster, MonsterRef};
30///
31/// fn main() -> Result<(), Box<dyn Error>> {
32///     let buf = std::fs::read("monster.bin")?;
33///     let monster: MonsterRef<'_> = MonsterRef::read_as_root(&buf)?;
34///     let monster_health = monster.hp()?;
35///     let owned_monster: Monster = monster.try_into().expect("invalid monster");
36///     Ok(())
37/// }
38pub trait ReadAsRoot<'a>: Sized {
39    /// Takes a slice assumed to be of this type and returns a view into it.
40    ///
41    /// If the data is not valid for this type the field accessors will give
42    /// errors or invalid values, but will still be memory safe.
43    fn read_as_root(slice: &'a [u8]) -> Result<Self>;
44}
45
46/// Trait used by generated code to serialize primitive types.
47pub trait WriteAs<P: Primitive> {
48    #[doc(hidden)]
49    type Prepared: WriteAsPrimitive<P>;
50    #[doc(hidden)]
51    fn prepare(&self, builder: &mut Builder) -> Self::Prepared;
52}
53
54/// Trait used by generated code to serialize primitive types with default values.
55pub trait WriteAsDefault<P: Primitive, D: ?Sized> {
56    #[doc(hidden)]
57    type Prepared: WriteAsPrimitive<P>;
58    #[doc(hidden)]
59    fn prepare(&self, builder: &mut Builder, default: &D) -> Option<Self::Prepared>;
60}
61
62/// Trait used by generated code to serialize optional primitive types.
63pub trait WriteAsOptional<P: Primitive> {
64    #[doc(hidden)]
65    type Prepared: WriteAsPrimitive<P>;
66    #[doc(hidden)]
67    fn prepare(&self, builder: &mut Builder) -> Option<Self::Prepared>;
68}
69
70/// Trait used by generated code to serialize offsets to already serialized data.
71pub trait WriteAsOffset<T: ?Sized> {
72    #[doc(hidden)]
73    fn prepare(&self, builder: &mut Builder) -> Offset<T>;
74}
75
76/// Trait used by generated code to serialize offsets to unions.
77pub trait WriteAsUnion<T: ?Sized> {
78    #[doc(hidden)]
79    fn prepare(&self, builder: &mut Builder) -> UnionOffset<T>;
80}
81
82/// Trait used by generated code to serialize offsets to optional unions.
83pub trait WriteAsOptionalUnion<T: ?Sized> {
84    #[doc(hidden)]
85    fn prepare(&self, builder: &mut Builder) -> Option<UnionOffset<T>>;
86}
87
88/// Trait used by generated code to serialize offsets to unions.
89pub trait WriteAsUnionVector<T: ?Sized> {
90    #[doc(hidden)]
91    fn prepare(&self, builder: &mut Builder) -> UnionVectorOffset<T>;
92}
93
94/// Trait used by generated code to serialize offsets to union.
95pub trait WriteAsDefaultUnionVector<T: ?Sized> {
96    #[doc(hidden)]
97    fn prepare(&self, builder: &mut Builder) -> Option<UnionVectorOffset<T>>;
98}
99
100/// Trait used by generated code to serialize offsets to optional unions.
101pub trait WriteAsOptionalUnionVector<T: ?Sized> {
102    #[doc(hidden)]
103    fn prepare(&self, builder: &mut Builder) -> Option<UnionVectorOffset<T>>;
104}
105
106#[doc(hidden)]
107pub trait WriteAsPrimitive<P> {
108    fn write<const N: usize>(&self, cursor: Cursor<'_, N>, buffer_position: u32);
109}
110
111#[doc(hidden)]
112pub trait TableRead<'buf>: Sized {
113    fn from_buffer(
114        buffer: SliceWithStartOffset<'buf>,
115        offset: usize,
116    ) -> core::result::Result<Self, ErrorKind>;
117}
118
119#[doc(hidden)]
120pub trait TableReadUnion<'buf>: 'buf + Sized {
121    fn from_buffer(
122        buffer: SliceWithStartOffset<'buf>,
123        tag: u8,
124        offset: usize,
125    ) -> core::result::Result<Self, ErrorKind>;
126}
127
128#[doc(hidden)]
129pub trait TableReadUnionVector<'buf>: Sized {
130    fn from_buffer(
131        buffer: SliceWithStartOffset<'buf>,
132        tags_offset: usize,
133        values_offset: usize,
134    ) -> core::result::Result<Self, ErrorKind>;
135}
136
137/// Trait used by generated code to read elements from vectors.
138pub trait VectorRead<'buf>: 'buf {
139    #[doc(hidden)]
140    const STRIDE: usize;
141    #[doc(hidden)]
142    unsafe fn from_buffer(buffer: SliceWithStartOffset<'buf>, offset: usize) -> Self;
143}
144
145#[doc(hidden)]
146pub trait VectorReadUnion<'buf>: 'buf + Sized + TableReadUnion<'buf> {
147    const VECTOR_NAME: &'static str;
148    fn from_buffer(
149        buffer: SliceWithStartOffset<'buf>,
150        tag: u8,
151        offset: usize,
152    ) -> crate::Result<Self> {
153        <Self as TableReadUnion>::from_buffer(buffer, tag, offset)
154            .map_err(|e| e.with_error_location(Self::VECTOR_NAME, "get", buffer.offset_from_start))
155    }
156}
157
158/// This trait is a hack to get around the coherence restriction.
159/// Ideally we would want to be able to do an `impl VectorRead<'buf> for planus::Result<MyType>`
160/// in our generated code, however instead we do something like this:
161///   impl<T: VectorReadInner<'buf>, E> VectorRead<'buf> for Result<T, E>
162#[doc(hidden)]
163pub trait VectorReadInner<'buf>: 'buf + Sized {
164    #[doc(hidden)]
165    type Error: Sized;
166    #[doc(hidden)]
167    const STRIDE: usize;
168    #[doc(hidden)]
169    unsafe fn from_buffer(
170        buffer: SliceWithStartOffset<'buf>,
171        offset: usize,
172    ) -> core::result::Result<Self, Self::Error>;
173}
174
175/// Trait used by generated code to write elements to vectors.
176///
177/// # Safety
178/// The implementation of write_values should initialize the bytes as
179/// downstream code will assume so.
180pub unsafe trait VectorWrite<P> {
181    #[doc(hidden)]
182    const STRIDE: usize;
183    #[doc(hidden)]
184    type Value: WriteAsPrimitive<P> + Sized;
185    #[doc(hidden)]
186    fn prepare(&self, builder: &mut Builder) -> Self::Value;
187    #[doc(hidden)]
188    unsafe fn write_values(
189        values: &[Self::Value],
190        bytes: *mut MaybeUninit<u8>,
191        buffer_position: u32,
192    );
193}