hpl_toolkit/schema/
schema_value.rs

1use super::{schema::Schema, traits::ToSchema};
2use anchor_lang::prelude::*;
3use std::{io::Read, str::FromStr};
4
5#[cfg(feature = "compression")]
6use crate::compression::ToNode;
7use crate::{errors::HplToolkitError, utils::VecMap};
8#[cfg(feature = "compression")]
9use anchor_lang::solana_program::keccak;
10
11#[cfg_attr(feature = "debug", derive(Debug))]
12#[cfg_attr(feature = "compression", derive(ToNode))]
13#[derive(AnchorDeserialize, AnchorSerialize, Clone, PartialEq)]
14pub enum Number {
15    U64(u64),
16    I64(i64),
17    F64(f64),
18}
19
20impl ToString for Number {
21    fn to_string(&self) -> String {
22        match self {
23            Self::U64(data) => data.to_string(),
24            Self::I64(data) => data.to_string(),
25            Self::F64(data) => data.to_string(),
26        }
27    }
28}
29
30impl Into<serde_json::Number> for Number {
31    fn into(self) -> serde_json::Number {
32        match self {
33            Self::U64(value) => serde_json::Number::from(value),
34            Self::I64(value) => serde_json::Number::from(value),
35            Self::F64(value) => serde_json::Number::from_f64(value).unwrap(),
36        }
37    }
38}
39
40impl From<serde_json::Number> for Number {
41    fn from(number: serde_json::Number) -> Self {
42        if let Some(number) = number.as_u64() {
43            Self::U64(number)
44        } else if let Some(number) = number.as_i64() {
45            Self::I64(number)
46        } else if let Some(number) = number.as_f64() {
47            Self::F64(number)
48        } else {
49            panic!("Serde Number cannot be converted to Number")
50        }
51    }
52}
53
54#[cfg_attr(feature = "debug", derive(Debug))]
55#[cfg_attr(feature = "compression", derive(ToNode))]
56#[cfg_attr(feature = "idl-build", derive(hpl_toolkit_derive_gen_idl::GenIdl))]
57#[derive(Clone, PartialEq)]
58pub enum SchemaValue {
59    Null,
60    Bool(bool),
61    Number(Number),
62    String(String),
63    Array(Vec<Self>),
64    Object(VecMap<String, Self>),
65    Pubkey(Pubkey),
66    VecMap(VecMap<Self, Self>),
67    Enum(String, Box<Self>),
68    Schema(Schema),
69}
70// #[cfg(feature = "idl-build")]
71// impl anchor_lang::idl::build::IdlBuild for SchemaValue {
72//     fn get_full_path() -> String {
73//         format!("{0}::{1}", "hpl_toolkit::schema_value", "SchemaValue",)
74//     }
75// }
76impl ToSchema for SchemaValue {
77    fn schema() -> Schema {
78        // unknown schema
79        Schema::Null
80    }
81
82    fn schema_value(&self) -> Self {
83        self.clone()
84    }
85}
86
87impl SchemaValue {
88    pub fn validate(&mut self, schema: &Schema) -> bool {
89        match schema {
90            Schema::Null => matches!(self, Self::Null),
91            Schema::Bool => matches!(self, Self::Bool(_)),
92            Schema::Number => matches!(self, Self::Number(_)),
93            Schema::String => matches!(self, Self::String(_)),
94            Schema::Array(schema) => match self {
95                Self::Array(arr) => arr.iter_mut().all(|value| value.validate(schema)),
96                _ => false,
97            },
98            Schema::Object(schema) => match self {
99                Self::Object(obj) => schema.iter().all(|(key, schema)| {
100                    if let Some(value) = obj.get_mut(key) {
101                        return value.validate(schema);
102                    } else if matches!(schema, Schema::Option(_)) {
103                        return true;
104                    } else if matches!(schema, Schema::Null) {
105                        obj.insert(key.to_owned(), Self::Null);
106                        return true;
107                    }
108                    false
109                }),
110                _ => false,
111            },
112            Schema::Pubkey => matches!(self, Self::Pubkey(_)),
113            Schema::Option(schema) => self.validate(&Schema::Null) || self.validate(schema),
114            Schema::VecMap(_k, v) => match self {
115                Self::VecMap(map) => map.iter_mut().all(|(_, value)| value.validate(v)),
116                _ => false,
117            },
118            Schema::Enum(variants) => match self {
119                Self::Enum(variant_kind, variant_value) => variants
120                    .iter()
121                    .find(|variant| {
122                        return variant.0.eq(variant_kind) && variant_value.validate(&variant.1);
123                    })
124                    .is_some(),
125                _ => false,
126            },
127            Schema::Any => true,
128        }
129    }
130
131    pub fn size(&self) -> usize {
132        match self {
133            Self::Null => 1,
134            Self::Bool(_) => 2,
135            Self::Number(_) => 1 + 8,
136            Self::String(string) => 1 + string.as_bytes().len(),
137            Self::Array(vec) => {
138                let mut size = 1;
139                for schema in vec {
140                    size += schema.size()
141                }
142                size
143            }
144            Self::Object(map) => {
145                let mut size = 1;
146                for (key, value) in map.iter() {
147                    size += key.as_bytes().len();
148                    size += value.size();
149                }
150                size
151            }
152            Self::Pubkey(_) => 1 + 32,
153            Self::VecMap(map) => {
154                let mut size = 1;
155                for (key, value) in map.iter() {
156                    size += key.size();
157                    size += value.size();
158                }
159                size
160            }
161            Self::Enum(kind, value) => 1 + kind.as_bytes().len() + value.size(),
162            Self::Schema(schema) => 1 + schema.size(),
163        }
164    }
165
166    pub fn size_for_borsh(&self) -> usize {
167        match self.try_to_vec() {
168            Ok(vec) => vec.len(),
169            Err(_) => 0,
170        }
171    }
172}
173
174impl ToString for SchemaValue {
175    fn to_string(&self) -> String {
176        let mut schema_value_str = String::new();
177        match self {
178            Self::Null => schema_value_str.push_str("null"),
179            Self::Bool(data) => schema_value_str.push_str(data.to_string().as_str()),
180            Self::Number(data) => schema_value_str.push_str(data.to_string().as_str()),
181            Self::String(data) => schema_value_str.push_str(format!("\"{}\"", data).as_str()),
182            Self::Array(data) => {
183                schema_value_str.push_str("[ ");
184                data.iter().for_each(|value| {
185                    schema_value_str.push_str(format!("{}, ", value.to_string()).as_str());
186                });
187                schema_value_str.push_str("]");
188            }
189            Self::Object(data) => {
190                schema_value_str.push_str("{ ");
191                data.iter().for_each(|(key, value)| {
192                    schema_value_str.push_str(format!("{}: {}, ", key, value.to_string()).as_str());
193                });
194                schema_value_str.push_str("}");
195            }
196            Self::Pubkey(data) => schema_value_str.push_str(data.to_string().as_str()),
197            Self::VecMap(data) => {
198                schema_value_str.push_str("Map { ");
199                data.iter().for_each(|(key, value)| {
200                    schema_value_str
201                        .push_str(format!("{}: {}, ", key.to_string(), value.to_string()).as_str());
202                });
203                schema_value_str.push_str("}");
204            }
205            Self::Enum(kind, value) => {
206                schema_value_str.push_str(&format!("Enum {{ {}: {} }}", kind, value.to_string()))
207            }
208            Self::Schema(schema) => {
209                schema_value_str.push_str(&format!("Schema {}", schema.to_string()))
210            }
211        };
212        schema_value_str
213    }
214}
215
216impl AnchorSerialize for SchemaValue {
217    #[inline]
218    fn serialize<W: std::io::prelude::Write>(&self, writer: &mut W) -> std::io::Result<()> {
219        match self {
220            Self::Null => 0u8.serialize(writer),
221            Self::Bool(value) => {
222                1u8.serialize(writer)?;
223                value.serialize(writer)
224            }
225            Self::Number(value) => {
226                2u8.serialize(writer)?;
227                value.serialize(writer)
228            }
229            Self::String(value) => {
230                3u8.serialize(writer)?;
231                value.serialize(writer)
232            }
233            Self::Array(value) => {
234                4u8.serialize(writer)?;
235                value.serialize(writer)
236            }
237            Self::Object(value) => {
238                5u8.serialize(writer)?;
239                value.serialize(writer)
240            }
241            Self::Pubkey(value) => {
242                6u8.serialize(writer)?;
243                value.serialize(writer)
244            }
245            Self::VecMap(value) => {
246                7u8.serialize(writer)?;
247                value.serialize(writer)
248            }
249            Self::Enum(kind, value) => {
250                8u8.serialize(writer)?;
251                kind.serialize(writer)?;
252                value.serialize(writer)
253            }
254            Self::Schema(schema) => {
255                9u8.serialize(writer)?;
256                schema.serialize(writer)
257            }
258        }
259    }
260}
261
262impl AnchorDeserialize for SchemaValue {
263    #[inline]
264    fn deserialize_reader<R: std::io::prelude::Read>(reader: &mut R) -> std::io::Result<Self> {
265        #[cfg(feature = "log")]
266        crate::logger::debug!("Processing SchemaValue");
267        let mut buf: [u8; 1] = [0; 1];
268        let limit = reader.read(&mut buf)?;
269        if limit != 1 {
270            #[cfg(feature = "log")]
271            crate::logger::debug!("limit: {}, Buf: {:?}", limit, buf);
272            return Err(std::io::Error::new(
273                std::io::ErrorKind::InvalidInput,
274                "Unexpected length of input",
275            ));
276        }
277
278        #[cfg(feature = "log")]
279        crate::logger::debug!("SchemaValue Processing buf: {:?}", buf);
280        let result = match buf[0] {
281            0 => Ok(Self::Null),
282            1 => bool::deserialize_reader(reader).and_then(|v| Ok(Self::Bool(v))),
283            2 => Number::deserialize_reader(reader).and_then(|v| Ok(Self::Number(v))),
284            3 => String::deserialize_reader(reader).and_then(|v| Ok(Self::String(v))),
285            4 => Vec::deserialize_reader(reader).and_then(|v| Ok(Self::Array(v))),
286            5 => VecMap::deserialize_reader(reader).and_then(|v| Ok(Self::Object(v))),
287            6 => Pubkey::deserialize_reader(reader).and_then(|v| Ok(Self::Pubkey(v))),
288            7 => VecMap::deserialize_reader(reader).and_then(|v| Ok(Self::VecMap(v))),
289            8 => Ok(Self::Enum(
290                String::deserialize_reader(reader)?,
291                Box::new(Self::deserialize_reader(reader)?),
292            )),
293            9 => Schema::deserialize_reader(reader).and_then(|v| Ok(Self::Schema(v))),
294            _ => {
295                let msg = format!(
296                    "Invalid Option representation: {}. The first byte must be 0 till 6",
297                    buf[0]
298                );
299                Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, msg))
300            }
301        };
302
303        if result.is_err() {
304            let mut vec = Vec::<u8>::new();
305            reader.read_to_end(&mut vec)?;
306            #[cfg(feature = "log")]
307            crate::logger::error!(
308                "SchemaValue Failed at buf: {:?}, Bytes remaining: {:?}",
309                buf,
310                vec
311            );
312        }
313
314        result
315    }
316}
317const PUBKEY_PREFIX: &'static str = "pubkey:";
318const VEC_MAP_PREFIX: &'static str = "_is_a_vec_map_hc";
319impl Into<serde_json::Value> for SchemaValue {
320    fn into(self) -> serde_json::Value {
321        match self {
322            Self::Null => serde_json::Value::Null,
323            Self::Bool(value) => serde_json::Value::Bool(value),
324            Self::Number(value) => serde_json::Value::Number(value.into()),
325            Self::String(value) => serde_json::Value::String(value),
326            Self::Array(value) => {
327                serde_json::Value::Array(value.into_iter().map(|i| i.into()).collect())
328            }
329            Self::Object(value) => {
330                serde_json::Value::Object(value.into_iter().map(|(k, v)| (k, v.into())).collect())
331            }
332            Self::Pubkey(value) => {
333                let string = format!("{}{}", PUBKEY_PREFIX, value.to_string());
334                serde_json::Value::String(string)
335            }
336            Self::VecMap(value) => {
337                let mut vec = value
338                    .into_iter()
339                    .map(|(k, v)| serde_json::Value::Array(vec![k.into(), v.into()]))
340                    .collect::<Vec<_>>();
341
342                // insert prefix in 0 index
343                vec.insert(0, serde_json::Value::String(VEC_MAP_PREFIX.to_string()));
344
345                serde_json::Value::Array(vec)
346            }
347            Self::Enum(kind, value) => {
348                let mut obj = serde_json::Map::<String, serde_json::Value>::new();
349                obj.insert(String::from("__kind"), kind.into());
350
351                let schema_value = value.as_ref().to_owned();
352                obj.insert(String::from("params"), schema_value.into());
353
354                serde_json::Value::Object(obj)
355            }
356            Self::Schema(schema) => schema.pack(),
357        }
358    }
359}
360
361impl From<serde_json::Value> for SchemaValue {
362    fn from(value: serde_json::Value) -> Self {
363        if let Some(schema) = Schema::try_unpack(&value) {
364            return Self::Schema(schema);
365        }
366        match value {
367            serde_json::Value::Null => Self::Null,
368            serde_json::Value::Bool(value) => Self::Bool(value),
369            serde_json::Value::Number(value) => Self::Number(value.into()),
370            serde_json::Value::String(value) => {
371                if value.starts_with(PUBKEY_PREFIX) && value.len() == (PUBKEY_PREFIX.len() + 32) {
372                    let pubkey = Pubkey::from_str(value.split_at(PUBKEY_PREFIX.len()).1).unwrap();
373                    return Self::Pubkey(pubkey);
374                }
375                Self::String(value)
376            }
377            serde_json::Value::Array(value) => {
378                if let Some(serde_json::Value::String(prefix)) = value.get(0) {
379                    if *prefix == VEC_MAP_PREFIX.to_string() {
380                        let mut map = VecMap::new();
381                        for i in 1..value.len() {
382                            if let serde_json::Value::Array(vec) = &value[i] {
383                                if vec.len() == 2 {
384                                    map.insert(vec[0].to_owned().into(), vec[1].to_owned().into());
385                                }
386                            }
387                        }
388                        return Self::VecMap(map);
389                    }
390                }
391                Self::Array(value.into_iter().map(|i| i.into()).collect())
392            }
393            serde_json::Value::Object(value) => {
394                if let Some(kind) = value.get("__kind") {
395                    if let serde_json::Value::String(kind) = kind {
396                        let params = if let Some(params) = value.get("params") {
397                            params.to_owned().into()
398                        } else {
399                            Self::Null
400                        };
401
402                        return Self::Enum(kind.to_owned(), Box::new(params));
403                    }
404                }
405                Self::Object(value.into_iter().map(|(k, v)| (k, v.into())).collect())
406            }
407        }
408    }
409}
410
411#[cfg_attr(feature = "debug", derive(Debug))]
412#[cfg_attr(feature = "compression", derive(ToNode))]
413#[derive(Clone, PartialEq)]
414pub struct SchemaValueContainer {
415    parsed: Option<SchemaValue>,
416    raw: Option<Vec<u8>>,
417}
418
419#[cfg(feature = "idl-build")]
420use anchor_lang::idl::types::*;
421#[cfg(feature = "idl-build")]
422impl anchor_lang::idl::build::IdlBuild for SchemaValueContainer {
423    fn get_full_path() -> String {
424        format!(
425            "{0}::{1}",
426            "hpl_toolkit::schema_value", "SchemaValueContainer",
427        )
428    }
429
430    fn create_type() -> Option<IdlTypeDef> {
431        Some(IdlTypeDef {
432            name: "SchemaValueContainer".to_string(),
433            docs: vec![],
434            serialization: IdlSerialization::Borsh,
435            repr: None,
436            generics: vec![],
437            ty: IdlTypeDefTy::Struct {
438                fields: Some(IdlDefinedFields::Named(vec![IdlField {
439                    name: "raw".to_string(),
440                    ty: IdlType::Vec(Box::new(IdlType::U8)),
441                    docs: vec![],
442                }])),
443            },
444        })
445    }
446
447    fn insert_types(_types: &mut std::collections::BTreeMap<String, IdlTypeDef>) {
448        _types.insert(
449            "SchemaValue".to_string(),
450            SchemaValue::create_type().unwrap(),
451        );
452        _types.insert("Number".to_string(), super::Number::create_type().unwrap());
453    }
454}
455impl ToSchema for SchemaValueContainer {
456    fn schema() -> Schema {
457        SchemaValue::schema()
458    }
459    fn schema_value(&self) -> SchemaValue {
460        if let Some(schema) = &self.parsed {
461            return schema.clone();
462        } else if let Some(bytes) = &self.raw {
463            if let Ok(schema) = SchemaValue::deserialize(&mut &bytes[..]) {
464                return schema;
465            }
466        }
467        SchemaValue::Null
468    }
469}
470impl AnchorDeserialize for SchemaValueContainer {
471    fn deserialize_reader<R: std::io::prelude::Read>(reader: &mut R) -> std::io::Result<Self> {
472        let buffer = Vec::<u8>::deserialize_reader(reader)?;
473        Ok(Self {
474            parsed: None,
475            raw: Some(buffer),
476        })
477    }
478}
479impl AnchorSerialize for SchemaValueContainer {
480    fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
481        if let Some(bytes) = &self.raw {
482            bytes.serialize(writer)?;
483        } else if let Some(schema) = &self.parsed {
484            let bytes = schema.try_to_vec()?;
485            bytes.serialize(writer)?;
486        } else {
487            return Err(std::io::Error::from(std::io::ErrorKind::InvalidData));
488        };
489        Ok(())
490    }
491}
492
493impl SchemaValueContainer {
494    pub fn size(&self) -> usize {
495        if let Some(bytes) = &self.raw {
496            return bytes.len() + 4;
497        } else if let Some(schema) = &self.parsed {
498            return schema.size() + 4;
499        }
500
501        0
502    }
503    pub fn new(schema: SchemaValue) -> Self {
504        Self {
505            raw: None,
506            parsed: Some(schema),
507        }
508    }
509
510    pub fn new_from_bytes(bytes: Vec<u8>) -> Self {
511        Self {
512            raw: Some(bytes),
513            parsed: None,
514        }
515    }
516
517    pub fn parse(&mut self) -> Result<()> {
518        if self.parsed.is_none() {
519            if self.raw.is_none() {
520                return Err(HplToolkitError::SchemaValueContainerEmpty.into());
521            }
522            self.parsed = Some(SchemaValue::deserialize(
523                &mut &self.raw.take().unwrap()[..],
524            )?)
525        }
526        Ok(())
527    }
528    pub fn get_inner(&mut self) -> Result<&SchemaValue> {
529        self.parse()?;
530        Ok(self.parsed.as_ref().unwrap())
531    }
532
533    pub fn get_inner_mut(&mut self) -> Result<&mut SchemaValue> {
534        self.parse()?;
535        Ok(self.parsed.as_mut().unwrap())
536    }
537}