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