Skip to content

as_object on Schema? #36

@6293

Description

@6293

I am not sure this is a good idea though.Perhaps we can impl JsonSchemaExt on Schema instead of SchemaObject, with the newly introduced method as_object:

trait JsonSchemaExt {
    fn is_true(&self) -> bool;
    fn effective_type(&mut self) -> InternalJsonSchemaType;
    fn as_object(&mut self) -> Option<&mut SchemaObject>;
}

impl JsonSchemaExt for Schema {
    fn is_true(&self) -> bool {
        matches!(self, Schema::Bool(true))
    }

    fn effective_type(&mut self) -> InternalJsonSchemaType {
        match self {
            Schema::Object(obj) => {
                if let Some(ref ty) = obj.instance_type {
                    match ty {
                        SingleOrVec::Single(ty) => JsonSchemaType::from(**ty).into(),
                        SingleOrVec::Vec(tys) => InternalJsonSchemaType::Multiple(
                            tys.iter().copied().map(JsonSchemaType::from).collect(),
                        ),
                    }
                } else if let Some(ref constant) = obj.const_value {
                    serde_value_to_own(constant).into()
                } else if !obj.object().properties.is_empty() {
                    JsonSchemaType::Object.into()
                } else if let Some(ref mut any_of) = obj.subschemas().any_of {
                    InternalJsonSchemaType::Multiple(
                        any_of
                            .iter_mut()
                            .flat_map(|a| Self::effective_type(a).explode())
                            .collect::<BTreeSet<_>>()
                            .into_iter()
                            .collect(),
                    )
                } else if obj.subschemas().not.as_ref().map_or(false, |x| x.is_true()) {
                    InternalJsonSchemaType::Never
                } else {
                    InternalJsonSchemaType::Any
                }
            }
            Schema::Bool(true) => InternalJsonSchemaType::Any,
            Schema::Bool(false) => InternalJsonSchemaType::Never,
        }
    }

    fn as_object(&mut self) -> Option<&mut SchemaObject> {
        match self {
            Schema::Object(obj) => Some(obj),
            _ => None,
        }
    }
}

A main advantage here is that we can get rid of cloning Schema just for obtaining &mut SchemaObject, as done in some places. e.g.

.map_or(true, |x| x.clone().into_object().is_true());

A drawback would be increased lines of code. We would rewrite diff_properties as below:

fn diff_properties(
        &mut self,
        json_path: &str,
        lhs: &mut Schema,
        rhs: &mut Schema,
    ) -> Result<(), Error> {
        let lhs_props: BTreeSet<_> = lhs
            .as_object()
            .map(|obj| obj.object().properties.keys().cloned().collect())
            .unwrap_or_default();
        let rhs_props: BTreeSet<_> = rhs
            .as_object()
            .map(|obj| obj.object().properties.keys().cloned().collect())
            .unwrap_or_default();

        let lhs_additional_properties = lhs
            .as_object()
            .and_then(|obj| obj.object().additional_properties.as_ref())
            .map_or(true, |x| x.is_true());

        for removed in lhs_props.difference(&rhs_props) {
            (self.cb)(Change {
                path: json_path.to_owned(),
                change: ChangeKind::PropertyRemove {
                    lhs_additional_properties,
                    removed: removed.clone(),
                },
            });
        }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions