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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions