Skip to content
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

feat: use enum values as keys for map #231

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion schemars/src/json_schema_impls/indexmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ use crate::JsonSchema;
use indexmap::{IndexMap, IndexSet};
use std::collections::{HashMap, HashSet};

forward_impl!((<K, V: JsonSchema, H> JsonSchema for IndexMap<K, V, H>) => HashMap<K, V, H>);
forward_impl!((<K: JsonSchema, V: JsonSchema, H> JsonSchema for IndexMap<K, V, H>) => HashMap<K, V, H>);
forward_impl!((<T: JsonSchema, H> JsonSchema for IndexSet<T, H>) => HashSet<T, H>);
36 changes: 34 additions & 2 deletions schemars/src/json_schema_impls/maps.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use crate::gen::SchemaGenerator;
use crate::schema::*;
use crate::JsonSchema;
use crate::{Map, Set};

macro_rules! map_impl {
($($desc:tt)+) => {
impl $($desc)+
where
K: JsonSchema,
V: JsonSchema,
{
no_ref_schema!();
Expand All @@ -15,11 +17,41 @@ macro_rules! map_impl {
}

fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let subschema = gen.subschema_for::<V>();
let k_subschema = gen.subschema_for::<K>();
let v_subschema = gen.subschema_for::<V>();
// if the map's key is a reference to another schema, and that schema is an
// enum, our final schema should require that the map has key values
// that are one of the enum values
if let Some(Schema::Object(schema_object)) = gen.dereference(&k_subschema) {
let mut schemas: Vec<Schema> = vec![];
if let Some(values) = &schema_object.enum_values {
for value in values {
// enum values all have quotes around them, so remove them
let str_value = &value.to_string();
let value = format!("{}", &str_value[1..str_value.len()-1]);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This definitely feels a bit hacky, I'm open to suggestions.


let schema = SchemaObject {
instance_type: Some(InstanceType::Object.into()),
object: Some(Box::new(ObjectValidation {
required: Set::from([value.clone()]),
properties: Map::from([(value, v_subschema.clone())]),
..Default::default()
})),
..Default::default()
};
schemas.push(schema.into());
}
let mut schema = SchemaObject::default();
schema.subschemas().one_of = Some(schemas);
return schema.into();
}
}
// if the key's schema is not a reference, or if the dereferenced key is not an enum,
// we can only enforce map values and not the map keys
SchemaObject {
instance_type: Some(InstanceType::Object.into()),
object: Some(Box::new(ObjectValidation {
additional_properties: Some(Box::new(subschema)),
additional_properties: Some(Box::new(v_subschema)),
..Default::default()
})),
..Default::default()
Expand Down