Skip to main content

codama_nodes/type_nodes/
pre_offset_type_node.rs

1use crate::{NestedTypeNode, NestedTypeNodeTrait, TypeNode, TypeNodeTrait, TypeNodeUnionTrait};
2use codama_errors::{CodamaError, CodamaResult};
3use codama_nodes_derive::nestable_type_node;
4use serde::{Deserialize, Serialize};
5
6#[nestable_type_node]
7pub struct PreOffsetTypeNode<T: TypeNodeUnionTrait> {
8    // Data.
9    pub offset: i32,
10    pub strategy: PreOffsetStrategy,
11
12    // Children.
13    #[serde(bound = "T: TypeNodeUnionTrait")]
14    pub r#type: Box<T>,
15}
16
17impl From<PreOffsetTypeNode<crate::TypeNode>> for crate::Node {
18    fn from(val: PreOffsetTypeNode<crate::TypeNode>) -> Self {
19        crate::Node::Type(val.into())
20    }
21}
22
23impl<T: TypeNodeTrait> From<PreOffsetTypeNode<NestedTypeNode<T>>> for PreOffsetTypeNode<TypeNode> {
24    fn from(node: PreOffsetTypeNode<NestedTypeNode<T>>) -> Self {
25        PreOffsetTypeNode {
26            strategy: node.strategy,
27            offset: node.offset,
28            r#type: Box::new(TypeNode::from(*node.r#type)),
29        }
30    }
31}
32
33impl<T: TypeNodeTrait> TryFrom<PreOffsetTypeNode<TypeNode>>
34    for PreOffsetTypeNode<NestedTypeNode<T>>
35{
36    type Error = CodamaError;
37    fn try_from(node: PreOffsetTypeNode<TypeNode>) -> CodamaResult<Self> {
38        Ok(PreOffsetTypeNode {
39            strategy: node.strategy,
40            offset: node.offset,
41            r#type: Box::new(NestedTypeNode::try_from(*node.r#type)?),
42        })
43    }
44}
45
46impl<T: TypeNodeUnionTrait> PreOffsetTypeNode<T> {
47    pub fn new<U>(r#type: U, strategy: PreOffsetStrategy, offset: i32) -> Self
48    where
49        U: Into<T>,
50    {
51        Self {
52            r#type: Box::new(r#type.into()),
53            strategy,
54            offset,
55        }
56    }
57
58    pub fn absolute<U>(r#type: U, offset: i32) -> Self
59    where
60        U: Into<T>,
61    {
62        Self::new(r#type, PreOffsetStrategy::Absolute, offset)
63    }
64
65    pub fn padded<U>(r#type: U, offset: i32) -> Self
66    where
67        U: Into<T>,
68    {
69        Self::new(r#type, PreOffsetStrategy::Padded, offset)
70    }
71
72    pub fn relative<U>(r#type: U, offset: i32) -> Self
73    where
74        U: Into<T>,
75    {
76        Self::new(r#type, PreOffsetStrategy::Relative, offset)
77    }
78}
79
80impl<T: TypeNodeTrait> NestedTypeNodeTrait<T> for PreOffsetTypeNode<NestedTypeNode<T>> {
81    type Mapped<U: TypeNodeTrait> = PreOffsetTypeNode<NestedTypeNode<U>>;
82
83    fn get_nested_type_node(&self) -> &T {
84        self.r#type.get_nested_type_node()
85    }
86
87    fn try_map_nested_type_node<U: TypeNodeTrait, F: FnOnce(T) -> CodamaResult<U>>(
88        self,
89        f: F,
90    ) -> CodamaResult<Self::Mapped<U>> {
91        Ok(PreOffsetTypeNode {
92            r#type: Box::new(self.r#type.try_map_nested_type_node(f)?),
93            strategy: self.strategy,
94            offset: self.offset,
95        })
96    }
97}
98
99#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
100#[serde(rename_all = "camelCase")]
101pub enum PreOffsetStrategy {
102    Absolute,
103    Padded,
104    Relative,
105}
106
107#[cfg(test)]
108mod tests {
109    use crate::{NestedTypeNode, NumberTypeNode, StringTypeNode, TypeNode, Utf8, U64};
110
111    use super::*;
112
113    #[test]
114    fn new_type_node() {
115        let node = PreOffsetTypeNode::<TypeNode>::new(
116            StringTypeNode::new(Utf8),
117            PreOffsetStrategy::Absolute,
118            -42,
119        );
120        assert_eq!(*node.r#type, TypeNode::String(StringTypeNode::new(Utf8)));
121        assert_eq!(node.strategy, PreOffsetStrategy::Absolute);
122        assert_eq!(node.offset, -42);
123    }
124
125    #[test]
126    fn new_nested_type_node() {
127        let node = PreOffsetTypeNode::<NestedTypeNode<StringTypeNode>>::new(
128            StringTypeNode::new(Utf8),
129            PreOffsetStrategy::Absolute,
130            -42,
131        );
132        assert_eq!(
133            *node.r#type,
134            NestedTypeNode::Value(StringTypeNode::new(Utf8))
135        );
136        assert_eq!(node.get_nested_type_node(), &StringTypeNode::new(Utf8));
137        assert_eq!(node.strategy, PreOffsetStrategy::Absolute);
138        assert_eq!(node.offset, -42);
139    }
140
141    #[test]
142    fn absolute() {
143        let node = PreOffsetTypeNode::<TypeNode>::absolute(StringTypeNode::new(Utf8), 0);
144        assert_eq!(*node.r#type, TypeNode::String(StringTypeNode::new(Utf8)));
145        assert_eq!(node.strategy, PreOffsetStrategy::Absolute);
146        assert_eq!(node.offset, 0);
147    }
148
149    #[test]
150    fn relative() {
151        let node = PreOffsetTypeNode::<TypeNode>::relative(StringTypeNode::new(Utf8), -4);
152        assert_eq!(*node.r#type, TypeNode::String(StringTypeNode::new(Utf8)));
153        assert_eq!(node.strategy, PreOffsetStrategy::Relative);
154        assert_eq!(node.offset, -4);
155    }
156
157    #[test]
158    fn padded() {
159        let node = PreOffsetTypeNode::<TypeNode>::padded(StringTypeNode::new(Utf8), 8);
160        assert_eq!(*node.r#type, TypeNode::String(StringTypeNode::new(Utf8)));
161        assert_eq!(node.strategy, PreOffsetStrategy::Padded);
162        assert_eq!(node.offset, 8);
163    }
164
165    #[test]
166    fn to_json() {
167        let node = PreOffsetTypeNode::<TypeNode>::padded(NumberTypeNode::le(U64), 4);
168        let json = serde_json::to_string(&node).unwrap();
169        assert_eq!(
170            json,
171            r#"{"kind":"preOffsetTypeNode","offset":4,"strategy":"padded","type":{"kind":"numberTypeNode","format":"u64","endian":"le"}}"#
172        );
173    }
174
175    #[test]
176    fn from_json() {
177        let json = r#"{"kind":"preOffsetTypeNode","offset":4,"strategy":"padded","type":{"kind":"numberTypeNode","format":"u64","endian":"le"}}"#;
178        let node: PreOffsetTypeNode<TypeNode> = serde_json::from_str(json).unwrap();
179        assert_eq!(
180            node,
181            PreOffsetTypeNode::<TypeNode>::padded(NumberTypeNode::le(U64), 4)
182        );
183    }
184}