xrpl/core/binarycodec/definitions/
mod.rs

1//! Functions for encoding objects into the XRP Ledger's
2//! canonical binary format and decoding them.
3
4pub mod types;
5
6use core::fmt::Display;
7
8pub use self::types::*;
9
10use crate::utils::ToBytes;
11use alloc::string::String;
12use alloc::string::ToString;
13use alloc::vec;
14use alloc::vec::Vec;
15use serde::{Deserialize, Serialize};
16
17pub const CODE_MIN_VALUE: i16 = 1;
18pub const CODE_MAX_VALUE: i16 = u8::MAX as i16;
19
20/// A container class for simultaneous storage of a field's
21/// type code and field code.
22///
23/// # Examples
24///
25/// ## Basic usage
26///
27/// ```
28/// use xrpl::core::binarycodec::definitions::FieldHeader;
29///
30/// let field_header = FieldHeader {
31///     type_code: -2,
32///     field_code: 0,
33/// };
34/// ```
35#[derive(Debug, Clone)]
36pub struct FieldHeader {
37    pub type_code: i16,
38    pub field_code: i16,
39}
40
41/// A collection of serialization information about
42/// a specific field type.
43///
44/// # Examples
45///
46/// ## Basic usage
47///
48/// ```
49/// use xrpl::core::binarycodec::definitions::FieldInfo;
50/// use xrpl::core::binarycodec::definitions::FieldHeader;
51/// use xrpl::core::binarycodec::definitions::FieldInstance;
52///
53/// let field_header: FieldHeader = FieldHeader {
54///     type_code: -2,
55///     field_code: 0,
56/// };
57///
58/// let field_info: FieldInfo = FieldInfo {
59///     nth: 0,
60///     is_vl_encoded: false,
61///     is_serialized: false,
62///     is_signing_field: false,
63///     r#type: "Unknown".to_string(),
64/// };
65///
66/// let field_instance: FieldInstance =
67///     FieldInstance::new(&field_info, "Generic", field_header);
68/// ```
69#[derive(Debug, Clone)]
70pub struct FieldInstance {
71    pub nth: i16,
72    pub is_vl_encoded: bool,
73    pub is_serialized: bool,
74    pub is_signing: bool,
75    pub associated_type: String,
76    pub name: String,
77    pub header: FieldHeader,
78    pub ordinal: i32,
79}
80
81///Model object for field info metadata from the
82/// "fields" section of definitions.json.
83///
84/// # Examples
85///
86/// ## Basic usage
87///
88/// ```
89/// use xrpl::core::binarycodec::definitions::FieldInfo;
90///
91/// let field_info = FieldInfo {
92///     nth: 0,
93///     is_vl_encoded: false,
94///     is_serialized: false,
95///     is_signing_field: false,
96///     r#type: "Unknown".to_string(),
97/// };
98/// ```
99#[derive(Debug, Serialize, Deserialize, Clone)]
100#[serde(rename_all = "camelCase")]
101pub struct FieldInfo {
102    /// The field code -- sort order position for
103    /// fields of the same type.
104    pub nth: i16,
105    /// Whether the serialized length of this
106    /// field varies.
107    #[serde(rename = "isVLEncoded")]
108    pub is_vl_encoded: bool,
109    /// If the field is presented in binary
110    /// serialized representation.
111    pub is_serialized: bool,
112    /// If the field should be included in signed
113    /// transactions.
114    pub is_signing_field: bool,
115    /// The name of this field's serialization type,
116    /// e.g. UInt32, AccountID, etc.
117    pub r#type: String,
118}
119
120impl FieldInstance {
121    /// Create a new FieldInstance.
122    pub fn new(field_info: &FieldInfo, field_name: &str, field_header: FieldHeader) -> Self {
123        FieldInstance {
124            nth: field_info.nth,
125            is_vl_encoded: field_info.is_vl_encoded,
126            is_serialized: field_info.is_serialized,
127            is_signing: field_info.is_signing_field,
128            name: field_name.to_string(),
129            ordinal: &(field_header.type_code as i32) << 16 | field_info.nth as i32,
130            header: field_header,
131            associated_type: field_info.r#type.to_string(),
132        }
133    }
134}
135
136impl Display for FieldHeader {
137    /// Convert the FieldHeader to a String.
138    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
139        write!(f, "{}_{}", self.type_code, self.field_code)
140    }
141}
142
143impl ToBytes for FieldHeader {
144    /// Convert the FieldHeader to a Vec<u8>.
145    fn to_bytes(&self) -> Vec<u8> {
146        let mut header_bytes = vec![];
147
148        if self.type_code < 16 {
149            if self.field_code < 16 {
150                let shift = (self.type_code << 4 | self.field_code) as u8;
151                header_bytes.extend_from_slice(&shift.to_be_bytes());
152            } else {
153                let shift = (self.type_code << 4) as u8;
154
155                header_bytes.extend_from_slice(&shift.to_be_bytes());
156                header_bytes.extend_from_slice(&(self.field_code as u8).to_be_bytes());
157            }
158        } else if self.field_code < 16 {
159            header_bytes.extend_from_slice(&(self.field_code as u8).to_be_bytes());
160            header_bytes.extend_from_slice(&(self.type_code as u8).to_be_bytes());
161        } else {
162            header_bytes.extend_from_slice(&[0]);
163            header_bytes.extend_from_slice(&(self.type_code as u8).to_be_bytes());
164            header_bytes.extend_from_slice(&(self.field_code as u8).to_be_bytes());
165        }
166
167        header_bytes
168    }
169}