pub use vyre_foundation::soundness::{
validate_dynamic_pipeline, validate_dynamic_primitive, validate_pipeline, validate_primitive,
DynamicPrimitiveSoundness, DynamicSoundnessViolation, PrecisionContract, PrimitiveSoundness,
Soundness, SoundnessTagged, SoundnessViolation,
};
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DataflowEvidence<T> {
pub value: T,
pub soundness: Soundness,
}
impl<T> DataflowEvidence<T> {
#[inline]
#[must_use]
pub const fn new(value: T, soundness: Soundness) -> Self {
Self { value, soundness }
}
#[inline]
pub fn map<U>(self, transform: impl FnOnce(T) -> U) -> DataflowEvidence<U> {
DataflowEvidence {
value: transform(self.value),
soundness: self.soundness,
}
}
#[inline]
#[must_use]
pub fn as_ref(&self) -> DataflowEvidence<&T> {
DataflowEvidence {
value: &self.value,
soundness: self.soundness,
}
}
}
impl<T: PartialOrd> PartialOrd for DataflowEvidence<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match soundness_rank(self.soundness).cmp(&soundness_rank(other.soundness)) {
std::cmp::Ordering::Equal => self.value.partial_cmp(&other.value),
ord => Some(ord),
}
}
}
impl<T: Ord> Ord for DataflowEvidence<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match soundness_rank(self.soundness).cmp(&soundness_rank(other.soundness)) {
std::cmp::Ordering::Equal => self.value.cmp(&other.value),
ord => ord,
}
}
}
#[inline]
const fn soundness_rank(s: Soundness) -> u8 {
match s {
Soundness::MustUnder => 0,
Soundness::Exact => 1,
Soundness::MayOver => 2,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn map_identity_exact() {
let ev = DataflowEvidence::new(42, Soundness::Exact);
assert_eq!(ev.clone().map(|x| x), ev);
}
#[test]
fn map_identity_may_over() {
let ev = DataflowEvidence::new(String::from("hello"), Soundness::MayOver);
assert_eq!(ev.clone().map(|x| x), ev);
}
#[test]
fn map_identity_must_under() {
let ev = DataflowEvidence::new(vec![1, 2, 3], Soundness::MustUnder);
assert_eq!(ev.clone().map(|x| x), ev);
}
#[test]
fn map_composition_exact() {
let ev = DataflowEvidence::new(5, Soundness::Exact);
let f = |x: i32| x * 2;
let g = |x: i32| x + 3;
let left = ev.clone().map(f).map(g);
let right = ev.map(|x| g(f(x)));
assert_eq!(left, right);
}
#[test]
fn map_composition_may_over() {
let ev = DataflowEvidence::new(10, Soundness::MayOver);
let f = |x: i32| x - 1;
let g = |x: i32| x * x;
let left = ev.clone().map(f).map(g);
let right = ev.map(|x| g(f(x)));
assert_eq!(left, right);
}
#[test]
fn map_composition_must_under() {
let ev = DataflowEvidence::new(7u64, Soundness::MustUnder);
let f = |x: u64| x.wrapping_add(1);
let g = |x: u64| x >> 2;
let left = ev.clone().map(f).map(g);
let right = ev.map(|x| g(f(x)));
assert_eq!(left, right);
}
#[test]
fn map_preserves_soundness_exact() {
let ev = DataflowEvidence::new(1, Soundness::Exact);
let mapped = ev.map(|x| x.to_string());
assert_eq!(mapped.soundness, Soundness::Exact);
}
#[test]
fn map_preserves_soundness_may_over() {
let ev = DataflowEvidence::new(1, Soundness::MayOver);
let mapped = ev.map(|x| x.to_string());
assert_eq!(mapped.soundness, Soundness::MayOver);
}
#[test]
fn map_preserves_soundness_must_under() {
let ev = DataflowEvidence::new(1, Soundness::MustUnder);
let mapped = ev.map(|x| x.to_string());
assert_eq!(mapped.soundness, Soundness::MustUnder);
}
#[test]
fn map_changes_value_type() {
let ev = DataflowEvidence::new(123, Soundness::Exact);
let mapped: DataflowEvidence<String> = ev.map(|x| x.to_string());
assert_eq!(mapped.value, "123");
}
#[test]
fn map_on_reference_type() {
let ev = DataflowEvidence::new(vec![1, 2, 3], Soundness::Exact);
let mapped = ev.map(|mut v| {
v.push(4);
v
});
assert_eq!(mapped.value, vec![1, 2, 3, 4]);
}
#[test]
fn map_chain_three_functions() {
let ev = DataflowEvidence::new(2, Soundness::Exact);
let result = ev.map(|x| x + 1).map(|x| x * 2).map(|x| x - 1);
assert_eq!(result.value, 5); assert_eq!(result.soundness, Soundness::Exact);
}
#[test]
fn as_ref_exact_preserves_soundness() {
let ev = DataflowEvidence::new(42, Soundness::Exact);
let borrowed = ev.as_ref();
assert_eq!(borrowed.soundness, Soundness::Exact);
}
#[test]
fn as_ref_may_over_preserves_soundness() {
let ev = DataflowEvidence::new(42, Soundness::MayOver);
let borrowed = ev.as_ref();
assert_eq!(borrowed.soundness, Soundness::MayOver);
}
#[test]
fn as_ref_must_under_preserves_soundness() {
let ev = DataflowEvidence::new(42, Soundness::MustUnder);
let borrowed = ev.as_ref();
assert_eq!(borrowed.soundness, Soundness::MustUnder);
}
#[test]
fn as_ref_exact_value_matches() {
let ev = DataflowEvidence::new(String::from("test"), Soundness::Exact);
let borrowed = ev.as_ref();
assert_eq!(*borrowed.value, "test");
}
#[test]
fn as_ref_may_over_value_matches() {
let ev = DataflowEvidence::new(vec![7, 8, 9], Soundness::MayOver);
let borrowed = ev.as_ref();
assert_eq!(borrowed.value, &vec![7, 8, 9]);
}
#[test]
fn as_ref_must_under_value_matches() {
let ev = DataflowEvidence::new(std::f64::consts::PI, Soundness::MustUnder);
let borrowed = ev.as_ref();
assert_eq!(*borrowed.value, std::f64::consts::PI);
}
#[test]
fn as_ref_does_not_consume_original() {
let ev = DataflowEvidence::new(100, Soundness::Exact);
let _borrowed = ev.as_ref();
assert_eq!(ev.value, 100); }
#[test]
fn as_ref_twice_same_result() {
let ev = DataflowEvidence::new('a', Soundness::MayOver);
let b1 = ev.as_ref();
let b2 = ev.as_ref();
assert_eq!(b1.value, b2.value);
assert_eq!(b1.soundness, b2.soundness);
}
#[test]
fn as_ref_then_map() {
let ev = DataflowEvidence::new(5, Soundness::Exact);
let borrowed = ev.as_ref();
let mapped = borrowed.map(|&x| x * 3);
assert_eq!(mapped.value, 15);
assert_eq!(mapped.soundness, Soundness::Exact);
}
#[test]
fn eq_same_value_same_soundness_exact() {
let a = DataflowEvidence::new(42, Soundness::Exact);
let b = DataflowEvidence::new(42, Soundness::Exact);
assert_eq!(a, b);
}
#[test]
fn eq_same_value_same_soundness_may_over() {
let a = DataflowEvidence::new(42, Soundness::MayOver);
let b = DataflowEvidence::new(42, Soundness::MayOver);
assert_eq!(a, b);
}
#[test]
fn eq_same_value_same_soundness_must_under() {
let a = DataflowEvidence::new(42, Soundness::MustUnder);
let b = DataflowEvidence::new(42, Soundness::MustUnder);
assert_eq!(a, b);
}
#[test]
fn ne_same_value_different_soundness() {
let a = DataflowEvidence::new(42, Soundness::Exact);
let b = DataflowEvidence::new(42, Soundness::MayOver);
assert_ne!(a, b);
}
#[test]
fn ne_different_value_same_soundness() {
let a = DataflowEvidence::new(42, Soundness::Exact);
let b = DataflowEvidence::new(43, Soundness::Exact);
assert_ne!(a, b);
}
#[test]
fn ne_different_value_different_soundness() {
let a = DataflowEvidence::new(42, Soundness::Exact);
let b = DataflowEvidence::new(43, Soundness::MayOver);
assert_ne!(a, b);
}
#[test]
fn eq_reflected() {
let a = DataflowEvidence::new("x", Soundness::Exact);
let b = DataflowEvidence::new("x", Soundness::Exact);
assert!(a == b && b == a);
}
#[test]
fn eq_transitive() {
let a = DataflowEvidence::new(1, Soundness::MayOver);
let b = DataflowEvidence::new(1, Soundness::MayOver);
let c = DataflowEvidence::new(1, Soundness::MayOver);
assert!(a == b && b == c && a == c);
}
#[test]
fn ordering_must_under_less_than_exact() {
let a = DataflowEvidence::new(100, Soundness::MustUnder);
let b = DataflowEvidence::new(1, Soundness::Exact);
assert!(a < b);
}
#[test]
fn ordering_exact_less_than_may_over() {
let a = DataflowEvidence::new(100, Soundness::Exact);
let b = DataflowEvidence::new(1, Soundness::MayOver);
assert!(a < b);
}
#[test]
fn ordering_must_under_less_than_may_over() {
let a = DataflowEvidence::new(1000, Soundness::MustUnder);
let b = DataflowEvidence::new(0, Soundness::MayOver);
assert!(a < b);
}
#[test]
fn ordering_same_soundness_by_value() {
let a = DataflowEvidence::new(10, Soundness::Exact);
let b = DataflowEvidence::new(20, Soundness::Exact);
assert!(a < b);
assert!(b > a);
}
#[test]
fn ordering_equal_elements() {
let a = DataflowEvidence::new(5, Soundness::Exact);
let b = DataflowEvidence::new(5, Soundness::Exact);
assert_eq!(a.cmp(&b), std::cmp::Ordering::Equal);
}
#[test]
fn ordering_total_order_all_variants() {
let vals = vec![
DataflowEvidence::new(1, Soundness::MustUnder),
DataflowEvidence::new(2, Soundness::MustUnder),
DataflowEvidence::new(1, Soundness::Exact),
DataflowEvidence::new(2, Soundness::Exact),
DataflowEvidence::new(1, Soundness::MayOver),
DataflowEvidence::new(2, Soundness::MayOver),
];
for i in 0..vals.len() {
for j in 0..vals.len() {
let ord = vals[i].cmp(&vals[j]);
let reverse = vals[j].cmp(&vals[i]);
assert_eq!(ord.reverse(), reverse);
}
}
}
#[test]
fn ordering_sorts_correctly() {
let mut vals = vec![
DataflowEvidence::new(2, Soundness::MayOver),
DataflowEvidence::new(1, Soundness::Exact),
DataflowEvidence::new(3, Soundness::MustUnder),
];
vals.sort();
assert_eq!(vals[0].soundness, Soundness::MustUnder);
assert_eq!(vals[0].value, 3);
assert_eq!(vals[1].soundness, Soundness::Exact);
assert_eq!(vals[1].value, 1);
assert_eq!(vals[2].soundness, Soundness::MayOver);
assert_eq!(vals[2].value, 2);
}
#[test]
fn clone_produces_equal_value() {
let a = DataflowEvidence::new(42i32, Soundness::Exact);
let b = a.clone();
assert_eq!(a, b);
}
#[test]
fn debug_format_includes_value_and_soundness() {
let ev = DataflowEvidence::new(99, Soundness::Exact);
let s = format!("{:?}", ev);
assert!(s.contains("99"));
assert!(s.contains("Exact"));
}
#[test]
fn new_constructor_sets_fields() {
let ev = DataflowEvidence::new("payload", Soundness::MayOver);
assert_eq!(ev.value, "payload");
assert_eq!(ev.soundness, Soundness::MayOver);
}
}