use std::collections::BTreeSet;
use super::{Direction, OperationDeclaration, OperationDefinition, OperationPolicy, ReplaySafety, Visibility};
use crate::catalog::{self, Catalog, Member, Node, Projection, Visitor};
use crate::{Error, Identifier, Result};
#[derive(Clone, Copy, Debug)]
pub struct Entry {
pub id: &'static str,
pub description: &'static str,
pub policy: OperationPolicy,
pub visibility: Visibility,
pub replay: ReplaySafety,
pub fingerprint: fn() -> Result<crate::Fingerprint>,
}
pub struct Declarations;
pub struct Callees;
impl PartialEq for Entry {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
&& self.description == other.description
&& self.policy == other.policy
&& self.visibility == other.visibility
&& self.replay == other.replay
&& (self.fingerprint)().ok() == (other.fingerprint)().ok()
}
}
impl Eq for Entry {}
impl Entry {
pub const fn of<O: OperationDeclaration + ?Sized>() -> Self {
Self {
id: O::ID,
description: O::DESCRIPTION,
policy: O::POLICY,
visibility: O::VISIBILITY,
replay: O::REPLAY,
fingerprint: fingerprint::<O>,
}
}
pub fn definition(&self) -> Result<OperationDefinition> {
let definition = self.declared()?;
definition.validate()?;
Ok(definition)
}
pub(super) fn declared(&self) -> Result<OperationDefinition> {
let id = Identifier::new(self.id)?;
let definition = OperationDefinition {
id,
description: self.description.to_owned(),
policy: self.policy,
visibility: self.visibility,
replay: self.replay,
fingerprint: (self.fingerprint)()?,
};
Ok(definition)
}
}
impl Visitor for Declarations {
type Entry = Entry;
}
impl<M: OperationDeclaration> Member<M> for Declarations {
const ENTRY: Entry = Entry::of::<M>();
}
impl Declarations {
pub fn of<C: Catalog<Self>>() -> Result<Vec<OperationDefinition>> {
Self::from_projection(&C::ENTRIES)
}
pub fn from_entries(entries: &[Entry]) -> Result<Vec<OperationDefinition>> {
let mut names = BTreeSet::new();
let mut definitions = Vec::with_capacity(entries.len());
for declaration in entries {
append(declaration, &mut names, &mut definitions)?;
}
Ok(definitions)
}
pub fn from_tree(entries: &[Node<Entry>]) -> Result<Vec<OperationDefinition>> {
let mut names = BTreeSet::new();
let mut definitions = Vec::with_capacity(catalog::count(entries));
catalog::try_for_each(entries, |declaration| append(declaration, &mut names, &mut definitions))?;
Ok(definitions)
}
pub fn from_projection<P: Projection<Entry>>(entries: &P) -> Result<Vec<OperationDefinition>> {
let mut names = BTreeSet::new();
let mut definitions = Vec::with_capacity(P::LEN);
entries.try_for_each(|declaration| append(declaration, &mut names, &mut definitions))?;
Ok(definitions)
}
}
impl Visitor for Callees {
type Entry = &'static [super::WireDeclaration];
}
impl<M: OperationDeclaration> Member<M> for Callees {
const ENTRY: Self::Entry = M::OPERATIONS;
}
fn payload<T: crate::Portable>() -> Result<crate::Fingerprint> {
let schema = crate::schema::graph::Schema::from_declaration(T::DEFINITION, &crate::config::SchemaSettings::default())
.map_err(|error| crate::MessageError::new(error.to_string()))?;
let root = schema.root().map_err(|error| crate::MessageError::new(error.to_string()))?;
crate::schema::identity::fingerprint(root, T::CODEC).map_err(|error| crate::MessageError::new(error.to_string()).into())
}
fn fingerprint<O: OperationDeclaration + ?Sized>() -> Result<crate::Fingerprint> {
let input = if O::Input::STREAMED { Some(payload::<<O::Input as super::Direction>::Item>()?) } else { None };
let output = if O::Output::STREAMED { Some(payload::<<O::Output as super::Direction>::Item>()?) } else { None };
Ok(crate::schema::identity::operation(O::ID, payload::<O::Request>()?, payload::<O::Response>()?, input, output))
}
fn append(declaration: &Entry, names: &mut BTreeSet<Identifier>, definitions: &mut Vec<OperationDefinition>) -> Result<()> {
let definition = declaration.definition()?;
if !names.insert(definition.id.clone()) {
return Err(Error::DuplicateOperation { id: declaration.id.to_owned() });
}
definitions.push(definition);
Ok(())
}