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
146
147
148
149
150
//! This module contains traits that are implemented by the generated code for
//! structs and archive resources.
//!
//! flatdata's code generator translates a flatdata schema to Rust code. The
//! generated code contains all schema definitions embedded as strings, and for
//! each schema element it implements all needed methods and traits.
//!
//! ## Structs
//!
//! For a flatdata struct, let's say `SomeData`, there are three generated
//! types in Rust: `SomeData`, SomeDataRef` and SomeDataRefMut`. The former
//! type is used to to create the latter two. `SomeDataRef` is used to read
//! data from a serialized archive, `SomeDataRefMut` to write data to archive.
//!
//! ## Indexes and variadic types
//!
//! A `MultiVector` is a heterogeneous container which consists of indexed
//! items, each containing several elements of different types (cf.
//! [`MultiVector`]). For each multivector resource in a flatdata archive
//! the generator creates a type with the same name and a type with suffix
//! `Ref`. The former is used as template parameter of containers
//! `MultiVector` and `MultiArrayView`. They implement the traits `VariadicRef`
//! resp. `VariadicStruct`. Additionally, the multivector is indexed by
//! a struct which is automatically generated flatdata struct. It implements
//! the trait `Index` and `IndexRef`.
//!
//! [`MultiVector`]: struct.MultiVector.html

use std::fmt::Debug;

#[doc(hidden)]
pub use std::marker;

/// A factory trait used to bind lifetime to Ref implementations.
///
/// Vector/ArrayView-like classes cannot be directly implemented over the
/// structs since that binds lifetime too early. Instead this generic factory
/// and Higher-Rank-Trait-Bounds are used to emulate higher-kinded-generics.
pub trait Struct: Debug {
    /// Create a new struct
    ///
    /// # Safety
    /// If the struct is not self-contained (NoOverlap),
    /// and there is no directly subsequent structure in memory,
    /// then the resulting instance's data must not be accessed
    unsafe fn create_unchecked() -> Self;

    /// Size of an object of this type in bytes.
    const SIZE_IN_BYTES: usize;
    /// Whether this structs requires data of the next instance
    const IS_OVERLAPPING_WITH_NEXT: bool;
}

/// Marks structs that can be used stand-alone, e.g. no range
///
/// # Safety
///
/// Safe only if the struct does not any memory outside of its own memory range
/// E.g. @range annotations use the next struct's memory and must not implement this
pub unsafe trait NoOverlap {}
/// Marks structs that cannot be used stand-alone, e.g. no range
pub trait Overlap {}

/// A specialized Struct factory producing Index items.
/// Used primarily by the MultiVector/MultiArrayView.
pub trait IndexStruct: Struct {
    /// Provide getter for index
    fn range(&self) -> std::ops::Range<usize>;

    /// Provide setter for index
    fn set_index(&mut self, value: usize);
}

/// Index specifying a variadic type of `MultiArrayView`.
pub type TypeIndex = u8;

/// A type used as element of `MultiArrayView`.
///
/// Implemented by an enum type.
pub trait VariadicRef: Clone + Debug + PartialEq {
    /// Returns size in bytes of the current variant type.
    ///
    /// Since a variadic struct can contain types of different sized, this is a
    /// method based on the current value type.
    fn size_in_bytes(&self) -> usize;
}

/// A type used as element of 'MultiArrayView'.
///
/// Provides the index type that should be used in the container.
pub trait VariadicIndex {
    /// Index type
    type Index: IndexStruct;
}

/// A type used to create VariadicStructs.
///
/// Vector/ArrayView-like classes cannot be directly implemented over the
/// structs since that binds lifetime too early. Instead this generic factory
/// and Higher-Rank-Trait-Bounds are used to emulate higher-kinded-generics.
pub trait VariadicStruct<'a>: Clone {
    /// Reader type
    type Item: VariadicRef;

    /// Creates a reader for specific type of data.
    fn create(data: TypeIndex, _: &'a [u8]) -> Self::Item;

    /// Associated type used for building an item in `MultiVector` based on
    /// this variadic type.
    ///
    /// The builder is returned by
    /// [`MultiVector::grow`](struct.MultiVector.html#method.grow)
    /// method. It provides convenient methods `add_{variant_name}` for each
    /// enum variant.
    type ItemMut;

    /// Creates a builder for a list of VariadicRef.
    fn create_mut(data: &'a mut Vec<u8>) -> Self::ItemMut;
}

/// Shortcut trait for VariadicStructs that are able to produce references of
/// any given lifetime
///
/// Equivalent to ```for<'a> VariadicStruct<'a>'''
pub trait VariadicRefFactory: for<'a> VariadicStruct<'a> + VariadicIndex {}

impl<T> VariadicRefFactory for T
where
    T: for<'a> VariadicStruct<'a>,
    T: VariadicIndex,
{
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::test::{A, R};

    #[test]
    fn test_debug() {
        let a = A::new();
        let output = format!("{:?}", a);
        assert_eq!(output, "A { x: 0, y: 0, e: Value }");
    }

    #[test]
    fn test_range() {
        assert_eq!(<R as Struct>::IS_OVERLAPPING_WITH_NEXT, true);
    }
}