delta_struct/variant.rs
1//! The delta of a value that might have changed shape, and the failure that
2//! comes with it.
3//!
4//! A struct's delta always fits the value it is applied to: the fields are the
5//! fields, and nothing about them can disagree. An enum's cannot. Two values
6//! of the same enum may be in different variants, in which case there is no
7//! difference to describe — only a replacement — and a delta built for one
8//! variant may arrive at a value sitting in another.
9//!
10//! [`EnumDelta`] is the first half of that: one arm for "same variant, here is
11//! what changed inside it" and one for "different variant, here is the whole
12//! thing". [`Mismatch`] is the second: what [`Delta::apply_delta`] returns when
13//! the two disagree.
14//!
15//! [`Delta::apply_delta`]: crate::Delta::apply_delta
16
17use std::fmt;
18
19/// The delta of an enum: a change *within* a variant, or a change *of*
20/// variant.
21///
22/// `T` is the source enum and `D` its generated `{Self}Delta`, so deriving
23/// [`Delta`](crate::Delta) on `enum Shape` gives
24/// `Output = EnumDelta<Shape, ShapeDelta>`. The wrapper is a type in this
25/// crate rather than an arm of the generated enum so that [`Became`] cannot
26/// collide with a variant you wrote.
27///
28/// Note that [`Became`] carries the source value whole. There is nothing
29/// smaller it could carry — the receiver holds a different variant, so it
30/// shares none of the new one — which is also why serializing an enum's delta
31/// needs the enum itself to be serializable.
32///
33/// [`Became`]: EnumDelta::Became
34#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
35#[derive(Clone, Debug, PartialEq, Eq)]
36pub enum EnumDelta<T, D> {
37 /// The value moved to a different variant, so here it is in full.
38 Became(T),
39 /// The value stayed in its variant; this is what changed inside it.
40 Delta(D),
41}
42
43/// A delta that does not fit the value it was applied to.
44///
45/// Only enums can produce this — a delta built while the value was one variant
46/// arriving at a value that is now another — which means the two sides have
47/// already diverged. A struct's `apply_delta` never fails, and neither does
48/// one for an enum whose value is in the expected variant.
49///
50/// Nested deltas propagate the innermost mismatch rather than wrapping it, so
51/// the type and variant named here are the ones that actually disagreed, not
52/// the outermost thing being applied.
53#[derive(Clone, Copy, Debug, Eq, PartialEq)]
54pub struct Mismatch {
55 /// The enum whose delta did not fit, as written in its definition.
56 pub type_name: &'static str,
57 /// The variant the delta was computed for.
58 pub expected: &'static str,
59 /// The variant the value was actually in.
60 pub found: &'static str,
61}
62
63impl fmt::Display for Mismatch {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 write!(
66 f,
67 "delta does not fit: it was computed for {}::{}, but the value is {}::{}",
68 self.type_name, self.expected, self.type_name, self.found
69 )
70 }
71}
72
73impl std::error::Error for Mismatch {}