1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use crate::{
    builder::Builder, errors::ErrorKind, slice_helpers::SliceWithStartOffset, Cursor, Offset,
    Result, UnionOffset,
};
use core::mem::MaybeUninit;

#[doc(hidden)]
pub trait Primitive {
    const ALIGNMENT: usize;
    const ALIGNMENT_MASK: usize = Self::ALIGNMENT - 1;
    const SIZE: usize;
}

/// Interface for getting a view into serialized data.
///
/// To get an owned variant use [`TryInto`] on the `Ref` type. Note that for
/// nested types with lots of sharing the owned variants can be much larger than
/// the serialized representation.
///
/// # Examples
///
/// ```no_run
/// use std::error::Error;
/// use planus::ReadAsRoot;
/// use planus_example::monster_generated::my_game::sample::{Monster, MonsterRef};
///
/// fn main() -> Result<(), Box<dyn Error>> {
///     let buf = std::fs::read("monster.bin")?;
///     let monster: MonsterRef<'_> = MonsterRef::read_as_root(&buf)?;
///     let monster_health = monster.hp()?;
///     let owned_monster: Monster = monster.try_into().expect("invalid monster");
///     Ok(())
/// }
pub trait ReadAsRoot<'a>: Sized {
    /// Takes a slice assumed to be of this type and returns a view into it.
    ///
    /// If the data is not valid for this type the field accessors will give
    /// errors or invalid values, but will still be memory safe.
    fn read_as_root(slice: &'a [u8]) -> Result<Self>;
}

/// Trait used by generated code to serialize primitive types.
pub trait WriteAs<P: Primitive> {
    #[doc(hidden)]
    type Prepared: WriteAsPrimitive<P>;
    #[doc(hidden)]
    fn prepare(&self, builder: &mut Builder) -> Self::Prepared;
}

/// Trait used by generated code to serialize primitive types with default values.
pub trait WriteAsDefault<P: Primitive, D: ?Sized> {
    #[doc(hidden)]
    type Prepared: WriteAsPrimitive<P>;
    #[doc(hidden)]
    fn prepare(&self, builder: &mut Builder, default: &D) -> Option<Self::Prepared>;
}

/// Trait used by generated code to serialize optional primitive types.
pub trait WriteAsOptional<P: Primitive> {
    #[doc(hidden)]
    type Prepared: WriteAsPrimitive<P>;
    #[doc(hidden)]
    fn prepare(&self, builder: &mut Builder) -> Option<Self::Prepared>;
}

/// Trait used by generated code to serialize offsets to already serialized data.
pub trait WriteAsOffset<T: ?Sized> {
    #[doc(hidden)]
    fn prepare(&self, builder: &mut Builder) -> Offset<T>;
}

/// Trait used by generated code to serialize offsets to unions.
pub trait WriteAsUnion<T: ?Sized> {
    #[doc(hidden)]
    fn prepare(&self, builder: &mut Builder) -> UnionOffset<T>;
}

/// Trait used by generated code to serialize offsets to optional unions.
pub trait WriteAsOptionalUnion<T: ?Sized> {
    #[doc(hidden)]
    fn prepare(&self, builder: &mut Builder) -> Option<UnionOffset<T>>;
}

#[doc(hidden)]
pub trait WriteAsPrimitive<P> {
    fn write<const N: usize>(&self, cursor: Cursor<'_, N>, buffer_position: u32);
}

#[doc(hidden)]
pub trait TableRead<'buf>: Sized {
    fn from_buffer(
        buffer: SliceWithStartOffset<'buf>,
        offset: usize,
    ) -> core::result::Result<Self, ErrorKind>;
}

#[doc(hidden)]
pub trait TableReadUnion<'buf>: Sized {
    fn from_buffer(
        buffer: SliceWithStartOffset<'buf>,
        offset: usize,
        tag: u8,
    ) -> core::result::Result<Self, ErrorKind>;
}

/// Trait used by generated code to read elements from vectors.
pub trait VectorRead<'buf> {
    #[doc(hidden)]
    const STRIDE: usize;
    #[doc(hidden)]
    unsafe fn from_buffer(buffer: SliceWithStartOffset<'buf>, offset: usize) -> Self;
}

/// This trait is a hack to get around the coherence restriction.
/// Ideally we would want to be able to do an `impl VectorRead<'buf> for planus::Result<MyType>`
/// in our generated code, however instead we do something like this:
///   impl<T: VectorReadInner<'buf>, E> VectorRead<'buf> for Result<T, E>
#[doc(hidden)]
pub trait VectorReadInner<'buf>: Sized {
    #[doc(hidden)]
    type Error: Sized;
    #[doc(hidden)]
    const STRIDE: usize;
    #[doc(hidden)]
    unsafe fn from_buffer(
        buffer: SliceWithStartOffset<'buf>,
        offset: usize,
    ) -> core::result::Result<Self, Self::Error>;
}

/// Trait used by generated code to write elements to vectors.
pub trait VectorWrite<P> {
    #[doc(hidden)]
    const STRIDE: usize;
    #[doc(hidden)]
    type Value: WriteAsPrimitive<P> + Sized;
    #[doc(hidden)]
    fn prepare(&self, builder: &mut Builder) -> Self::Value;
    #[doc(hidden)]
    unsafe fn write_values(
        values: &[Self::Value],
        bytes: *mut MaybeUninit<u8>,
        buffer_position: u32,
    );
}