1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
//! A module holding the crate's public traits.
use std::{any::Any, collections::BTreeMap, fmt::Debug};
use downcast_rs::Downcast;
/**
This trait defines a way to merge two instances of the same type.
```
# use schema_analysis::{Schema, Coalesce, Aggregate, context::BooleanContext};
#
# fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut context_1: BooleanContext = Default::default();
context_1.aggregate(&true);
context_1.aggregate(&true);
let mut schema_1 = Schema::Boolean(context_1);
let mut context_2: BooleanContext = Default::default();
context_2.aggregate(&false);
let mut schema_2 = Schema::Boolean(context_2);
schema_1.coalesce(schema_2); // schema_2 is gone.
let mut context_merged: BooleanContext = Default::default();
context_merged.aggregate(&true);
context_merged.aggregate(&true);
context_merged.aggregate(&false);
let schema_merged = Schema::Boolean(context_merged);
assert_eq!(schema_1, schema_merged);
#
# Ok(())
# }
```
*/
pub trait Coalesce {
/// Merge `other` into `self`.
fn coalesce(&mut self, other: Self)
where
Self: Sized;
}
/// This trait allows the merging of a type with an arbitrary trait object.
///
/// If the merger is unsuccessful (they are not of the same type) the trait object is returned.
///
/// This trait has a blanket implementation on any [Sized] type implementing [Coalesce].
pub trait CoalesceAny: Coalesce {
/// Merge `other` into `self`. Trait object is returned if merging was unsuccessful.
fn coalesce_any(&mut self, other: Box<dyn Any>) -> Option<Box<dyn Any>>;
}
impl<T: Coalesce + 'static> CoalesceAny for T {
fn coalesce_any(&mut self, other: Box<dyn Any>) -> Option<Box<dyn Any>> {
let other: Self = match other.downcast() {
Ok(downcasted) => *downcasted,
Err(not_downcasted) => return Some(not_downcasted),
};
self.coalesce(other);
None
}
}
/// This trait defines an interface used for types that need to receive values one at a time to
/// record something about them.
///
/// V is ?[Sized] to allow for `Aggregator<str>`.
/// In the future a better borrowing API might be implemented.
pub trait Aggregate<V: ?Sized> {
/// Run the internal logic on value
fn aggregate(&mut self, value: &'_ V);
}
/// A trait used by [crate::context::Aggregators].
/// It's an experimental feature meant to allow library users to run arbitrary aggregation logic on
/// the input data.
#[dyn_clonable::clonable]
pub trait CoalescingAggregator<V: ?Sized>:
Aggregate<V> + CoalesceAny + Downcast + Debug + Clone + Send + Sync
{
}
/// This trait checks whether the shape of two objects is the same.
/// The goal is to determine whether two representations are equivalent.
///
/// Example: two schemas of the same type might be structurally equivalent even if some of the
/// internal metadata is different because they have been visited by different sets of examples.
/// Example: two schemas of different types might be structurally equivalent if they represent the
/// same shape of data.
///
/// Notes:
/// - sample-dependent metadata should be ignored.
/// - semantic information (like a regex pattern) should match.
/// - unreliable information (like an *inferred* regex) might be ignored.
///
/// This trait closely mirrors [PartialEq].
pub trait StructuralEq<Rhs: ?Sized = Self> {
/// Returns `true` if `self` and `other` share the same structure.
fn structural_eq(&self, other: &Rhs) -> bool;
/// Returns `true` if `self` and `other` DO NOT share the same structure.
fn structural_ne(&self, other: &Rhs) -> bool {
!self.structural_eq(other)
}
}
impl StructuralEq for String {
fn structural_eq(&self, other: &Self) -> bool {
self == other
}
}
impl<T: StructuralEq> StructuralEq for Vec<T> {
fn structural_eq(&self, other: &Self) -> bool {
self.iter().zip(other).all(|(s, o)| s.structural_eq(o))
}
}
impl<T: StructuralEq> StructuralEq for Option<T> {
fn structural_eq(&self, other: &Self) -> bool {
match (self, other) {
(Some(s), Some(o)) => s.structural_eq(o),
(Some(_), None) | (None, Some(_)) => false,
(None, None) => true,
}
}
}
impl<K: StructuralEq, V: StructuralEq> StructuralEq for BTreeMap<K, V> {
fn structural_eq(&self, other: &Self) -> bool {
self.len() == other.len()
&& self
.iter()
.zip(other)
.all(|((sk, sv), (ok, ov))| sk.structural_eq(ok) && sv.structural_eq(ov))
}
}