actrpc-core 0.1.0

Core types and traits for ActRPC.
Documentation
use crate::descriptor::types::{FieldDescriptor, ParamsDescriptor, ValueDescriptor};

pub trait Accepts<Rhs = Self> {
    fn accepts(&self, actual: &Rhs) -> bool;
}

impl<T> Accepts for Option<T>
where
    T: Accepts,
{
    fn accepts(&self, actual: &Self) -> bool {
        match (self, actual) {
            (None, None) => true,
            (Some(expected), Some(actual)) => expected.accepts(actual),
            _ => false,
        }
    }
}

impl Accepts for ValueDescriptor {
    fn accepts(&self, actual: &Self) -> bool {
        match (self, actual) {
            (ValueDescriptor::Any, _) => true,

            (ValueDescriptor::Primitive(expected), ValueDescriptor::Primitive(actual)) => {
                expected == actual
            }

            (ValueDescriptor::Array(expected), ValueDescriptor::Array(actual)) => {
                expected.accepts(actual)
            }

            (ValueDescriptor::Map(expected), ValueDescriptor::Map(actual)) => {
                expected.accepts(actual)
            }

            (ValueDescriptor::Object(expected), ValueDescriptor::Object(actual)) => {
                fields_accept(&expected.fields, &actual.fields)
            }

            _ => false,
        }
    }
}

impl Accepts for ParamsDescriptor {
    fn accepts(&self, actual: &Self) -> bool {
        match (self, actual) {
            (ParamsDescriptor::Value(ValueDescriptor::Any), _) => true,

            (ParamsDescriptor::Value(expected), ParamsDescriptor::Value(actual)) => {
                expected.accepts(actual)
            }

            (ParamsDescriptor::Object(expected), ParamsDescriptor::Object(actual)) => {
                fields_accept(&expected.required_fields, &actual.required_fields)
                    && fields_accept(&expected.optional_fields, &actual.optional_fields)
            }

            _ => false,
        }
    }
}

fn fields_accept(expected: &[FieldDescriptor], actual: &[FieldDescriptor]) -> bool {
    if expected.len() != actual.len() {
        return false;
    }

    expected.iter().all(|expected_field| {
        actual.iter().any(|actual_field| {
            expected_field.name == actual_field.name && expected_field.ty.accepts(&actual_field.ty)
        })
    })
}