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}