Skip to content

Commit

Permalink
improvement(primitive-types): better json-schema, allow to build for …
Browse files Browse the repository at this point in the history
…serde_no_std/json-schema feature/targets combinations (#801)

* more std

* fixes of std and improvement of schema

* better alloc support
  • Loading branch information
dzmitry-lahoda authored Dec 5, 2023
1 parent 3a35610 commit 4da96ae
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 17 deletions.
2 changes: 2 additions & 0 deletions primitive-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ schemars = { version = ">=0.8.12", default-features = true, optional = true }

[dev-dependencies]
num-traits = "0.2"
serde_json = { version = "1.0", default-features = false }
jsonschema = { version = "0.17", default-features = false }

[features]
default = ["std"]
Expand Down
75 changes: 75 additions & 0 deletions primitive-types/src/json_schema.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use super::*;
#[cfg(not(feature = "std"))]
use alloc::{
borrow::ToOwned,
string::{String, ToString},
};

use schemars::{gen::SchemaGenerator, schema::Schema, JsonSchema};

impl JsonSchema for H160 {
fn schema_name() -> String {
"HexEncoded20Bytes".to_owned()
}

fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let mut schema = gen.subschema_for::<String>().into_object();
schema.metadata().description = Some("Hex encoded 20 bytes".to_string());
schema.string().pattern = Some("^0(x|X)[a-fA-F0-9]{40}$".to_string());
schema.into()
}
}

impl JsonSchema for U256 {
fn schema_name() -> String {
"U256String".to_string()
}

fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let mut schema = gen.subschema_for::<String>().into_object();
schema.metadata().description = Some("256-bit Unsigned Integer".to_string());
schema.string().pattern = Some("^(0|[1-9][0-9]{0,77})$".to_string());
schema.into()
}
}

#[cfg(test)]
#[cfg(any(feature = "serde", feature = "serde_no_std"))]
mod tests {
use crate::{H160, U256};
#[cfg(not(feature = "std"))]
use alloc::string::String;
use jsonschema::Draft;
use schemars::JsonSchema;

#[test]
fn hex_encoded_20_bytes() {
let schema = H160::json_schema(&mut schemars::gen::SchemaGenerator::default());
let schema_json = serde_json::to_value(&schema).unwrap();
let schema = jsonschema::JSONSchema::options()
.with_draft(Draft::Draft7)
.compile(&schema_json)
.unwrap();
let value = serde_json::to_value("0x55086adeca661185c437d92b9818e6eda6d0d047").unwrap();
assert!(schema.validate(&value).is_ok());
let value = serde_json::to_value("0X0E9C8DA9FD4BDD3281879D9E328D8D74D02558CC").unwrap();
assert!(schema.validate(&value).is_ok());

let value = serde_json::to_value("42").unwrap();
assert!(schema.validate(&value).is_err());
}

#[test]
fn u256() {
let schema = U256::json_schema(&mut schemars::gen::SchemaGenerator::default());
let schema_json = serde_json::to_value(&schema).unwrap();
let schema = jsonschema::JSONSchema::options()
.with_draft(Draft::Draft7)
.compile(&schema_json)
.unwrap();
let addr = serde_json::to_value("42").unwrap();
assert!(schema.validate(&addr).is_ok());
let addr = serde_json::to_value(['1'; 79].into_iter().collect::<String>()).unwrap();
assert!(schema.validate(&addr).is_err());
}
}
23 changes: 6 additions & 17 deletions primitive-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,14 @@

#![cfg_attr(not(feature = "std"), no_std)]

// serde_no_std leads to alloc via impl, json-schema without std requires alloc
#[cfg(all(not(feature = "std"), any(feature = "serde_no_std", feature = "json-schema")))]
extern crate alloc;

#[cfg(feature = "fp-conversion")]
mod fp_conversion;
#[cfg(feature = "json-schema")]
mod json_schema;

use core::convert::TryFrom;
use fixed_hash::{construct_fixed_hash, impl_fixed_hash_conversions};
Expand Down Expand Up @@ -105,23 +111,6 @@ mod serde {
impl_fixed_hash_serde!(H768, 96);
}

// true that no need std, but need to do no_std alloc than, so simplified for now
// also no macro, but easy to create
#[cfg(all(feature = "std", feature = "json-schema"))]
mod json_schema {
use super::*;

impl schemars::JsonSchema for H160 {
fn schema_name() -> String {
"0xPrefixedHexString".to_string()
}

fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
String::json_schema(gen)
}
}
}

#[cfg(feature = "impl-codec")]
mod codec {
use super::*;
Expand Down

0 comments on commit 4da96ae

Please sign in to comment.