-
Notifications
You must be signed in to change notification settings - Fork 178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add schemars
to ZeroVec
#4792
base: main
Are you sure you want to change the base?
add schemars
to ZeroVec
#4792
Conversation
fn json_schema(gen: &mut SchemaGenerator) -> Schema { | ||
// Instead of generating a subschema for T, we generate a schema representing the byte array | ||
let byte_schema = gen.subschema_for::<Vec<u8>>(); | ||
|
||
SchemaObject { | ||
instance_type: Some(InstanceType::Object.into()), | ||
object: Some(Box::new({ | ||
let mut object_validation = schemars::schema::ObjectValidation::default(); | ||
object_validation | ||
.properties | ||
.insert("data".to_string(), byte_schema); | ||
object_validation | ||
.properties | ||
.insert("error".to_string(), gen.subschema_for::<ZeroVecError>()); | ||
object_validation.required.insert("data".to_string()); | ||
object_validation | ||
})), | ||
..Default::default() | ||
} | ||
.into() | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ maintainers I am not certain if this is the right way to move forward
@@ -37,6 +38,7 @@ serde = { version = "1.0", default-features = false, features = ["alloc"], optio | |||
# and all 0.7 versions, but not further. | |||
yoke = { version = ">=0.6.0, <0.8.0", path = "../yoke", optional = true } | |||
twox-hash = { version = "1.6", default-features = false, optional = true } | |||
schemars = "0.8.16" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: this must be an optional dependency
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, and please add it to the top-level Cargo.toml (ideally wait until #4844 is merged)
@@ -5,6 +5,19 @@ | |||
use core::any; | |||
use core::fmt; | |||
|
|||
use crate::__zerovec_internal_reexport::boxed::Box; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: just alloc::boxed::Box
|
||
fn json_schema(gen: &mut SchemaGenerator) -> Schema { | ||
// Instead of generating a subschema for T, we generate a schema representing the byte array | ||
let byte_schema = gen.subschema_for::<Vec<u8>>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: why? ZeroSlice is logically an array of items
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, ZeroVec and ZeroSlice should both become arrays of T.
Maybe they can resolve to the same JsonSchema
impl.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, expected interaction should be as array not bytes. Lets fallback to implementing as arrays of T.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for looking into this!
nested_numbers: VarZeroVec<'data, ZeroSlice<u32>>, | ||
} | ||
|
||
#[test] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: use insta to help generate test cases and check-in the JSON Schema output.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, will look into it 👍
|
||
fn json_schema(gen: &mut SchemaGenerator) -> Schema { | ||
// Instead of generating a subschema for T, we generate a schema representing the byte array | ||
let byte_schema = gen.subschema_for::<Vec<u8>>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, ZeroVec and ZeroSlice should both become arrays of T.
Maybe they can resolve to the same JsonSchema
impl.
let schema = gen.into_root_schema_for::<DataStruct>(); | ||
let schema_json = | ||
serde_json::to_string_pretty(&schema).expect("Failed to serialize schema"); | ||
println!("{}", schema_json); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Please include the generated JSON.
|
||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||
#[derive(JsonSchema)] | ||
pub struct DataStruct<'data> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: for in-file unit tests, make one test for each of these. For example,
#[test]
fn test_schema_zerovec_u32() {
let gen = SchemaGenerator::default();
let schema = gen.into_root_schema_for::<ZeroVec<u32>>();
// ...
}
As suggested below, use insta for the more complex tests.
"properties": {
"chars": {
"$ref": "#/definitions/ZeroVec<Character>"
},
"nested_numbers": {
"$ref": "#/definitions/VarZeroVec<ZeroSlice<uint32>>"
},
"nums": {
"$ref": "#/definitions/ZeroVec<uint32>"
},
"strs": {
"$ref": "#/definitions/VarZeroVec<String>"
}
}, While technically correct, I think I would expect these to be inlined at the call site rather than being stuffed into the definitions section. I imagine the definitions section being useful when you have deeply nested structs or a struct that gets used multiple times, but these vecs should just be vecs. Is this configurable in the JsonSchema generator, or is it a result of the JsonSchema trait impl? |
In other words, I think my expectation for the JSON Schema of your sample struct would be {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "DataStruct",
"type": "object",
"required": [
"chars",
"nested_numbers",
"nums",
"strs"
],
"properties": {
"chars": {
"type": "array",
"items": {
"type": "string",
"maxLength": 1,
"minLength": 1
}
},
"nested_numbers": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
}
},
"nums": {
"type": "array",
"items": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"strs": {
"type": "array",
"items": {
"type": "string"
}
}
}
} |
@sffc Found something in the docs and in thier codebase: What does docs mentions: What does code mentions: Under I could give setting
Yes indeed, myself not a fan of very big schemas. Having schemas too big basically defies the purpose. |
New JSON, I was able to generate with setting {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "DataStruct",
"type": "object",
"required": [
"chars",
"nested_numbers",
"nums",
"strs"
],
"properties": {
"chars": {
"type": "array",
"items": {
"type": "string",
"maxLength": 1,
"minLength": 1
}
},
"nested_numbers": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
}
},
"nums": {
"$ref": "#/definitions/ZeroVec<uint32>"
},
"strs": {
"type": "array",
"items": {
"type": "string"
}
}
}
} Which one should we go for? |
Update the JSON, if all looks good, I think we are in position to write for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please address the open feedbacks.
@@ -24,6 +24,7 @@ all-features = true | |||
|
|||
[dependencies] | |||
zerofrom = { workspace = true } | |||
serde_json = "1.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Issue: Use the { workspace = true }
version of the dependency.
@@ -37,6 +38,7 @@ serde = { version = "1.0", default-features = false, features = ["alloc"], optio | |||
# and all 0.7 versions, but not further. | |||
yoke = { version = ">=0.6.0, <0.8.0", path = "../yoke", optional = true } | |||
twox-hash = { version = "1.6", default-features = false, optional = true } | |||
schemars = "0.8.16" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, and please add it to the top-level Cargo.toml (ideally wait until #4844 is merged)
@@ -33,6 +46,27 @@ impl fmt::Display for ZeroVecError { | |||
} | |||
} | |||
} | |||
impl JsonSchema for ZeroVecError { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Issue: I don't think you should need this impl. It should go away when you fix the ZeroSlice impl.
This PR intends to add
schemars
support toZeroVec
. Implemented JsonSchema for following:Added a basic test, just to check the generation. The JSON generated from the test:
Marking this part of #2118, as it may require more work.
Implement JsonSchema: