#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#[cfg(not(feature = "std"))]
extern crate alloc;
use core::ops::Deref;
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[must_use = "this `Patch` may contain a value that should be used"]
pub enum Patch<T> {
Some(T),
Empty,
None,
}
impl<T: Copy> Copy for Patch<T> {}
impl<T> Patch<T> {
#[inline]
pub fn is_some(&self) -> bool {
matches!(self, Patch::Some(_))
}
#[inline]
pub fn is_empty(&self) -> bool {
matches!(self, Patch::Empty)
}
#[inline]
pub fn is_none(&self) -> bool {
matches!(self, Patch::None)
}
#[inline]
pub fn is_null(&self) -> bool {
self.is_none()
}
#[inline]
pub fn contains<U>(&self, x: &U) -> bool
where
T: PartialEq<U>,
{
matches!(self, Patch::Some(v) if v == x)
}
}
impl<T> Patch<T> {
#[inline]
pub fn as_ref(&self) -> Patch<&T> {
match *self {
Patch::Some(ref x) => Patch::Some(x),
Patch::Empty => Patch::Empty,
Patch::None => Patch::None,
}
}
#[inline]
pub fn as_mut(&mut self) -> Patch<&mut T> {
match *self {
Patch::Some(ref mut x) => Patch::Some(x),
Patch::Empty => Patch::Empty,
Patch::None => Patch::None,
}
}
}
impl<T: Deref> Patch<T> {
#[inline]
pub fn as_deref(&self) -> Patch<&<T as Deref>::Target> {
self.as_ref().map(|t| t.deref())
}
}
impl<T> Patch<T> {
#[inline]
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Patch<U> {
match self {
Patch::Some(x) => Patch::Some(f(x)),
Patch::Empty => Patch::Empty,
Patch::None => Patch::None,
}
}
#[inline]
pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
match self {
Patch::Some(x) => f(x),
Patch::Empty | Patch::None => default,
}
}
#[inline]
pub fn map_or_else<U, D, F>(self, default: D, f: F) -> U
where
D: FnOnce() -> U,
F: FnOnce(T) -> U,
{
match self {
Patch::Some(x) => f(x),
Patch::Empty | Patch::None => default(),
}
}
#[inline]
pub fn and_then<U, F>(self, f: F) -> Patch<U>
where
F: FnOnce(T) -> Patch<U>,
{
match self {
Patch::Some(x) => f(x),
Patch::Empty => Patch::Empty,
Patch::None => Patch::None,
}
}
#[inline]
pub fn filter<P>(self, predicate: P) -> Patch<T>
where
P: FnOnce(&T) -> bool,
{
match self {
Patch::Some(x) if predicate(&x) => Patch::Some(x),
Patch::Some(_) => Patch::None,
Patch::Empty => Patch::Empty,
Patch::None => Patch::None,
}
}
}
impl<T> Patch<T> {
#[inline]
pub fn expect(self, msg: &str) -> T {
match self {
Patch::Some(x) => x,
Patch::Empty => panic!("{msg}"),
Patch::None => panic!("{msg}"),
}
}
#[inline]
pub fn unwrap(self) -> T {
match self {
Patch::Some(x) => x,
Patch::Empty => panic!("called `Patch::unwrap()` on an `Empty` value"),
Patch::None => panic!("called `Patch::unwrap()` on a `None` value"),
}
}
#[inline]
pub fn unwrap_or(self, default: T) -> T {
match self {
Patch::Some(x) => x,
Patch::Empty | Patch::None => default,
}
}
#[inline]
pub fn unwrap_or_else<F>(self, f: F) -> T
where
F: FnOnce() -> T,
{
match self {
Patch::Some(x) => x,
Patch::Empty | Patch::None => f(),
}
}
}
impl<T: Default> Patch<T> {
#[inline]
pub fn unwrap_or_default(self) -> T {
self.unwrap_or(T::default())
}
}
impl<T> Patch<T> {
#[inline]
pub fn or(self, other: Patch<T>) -> Patch<T> {
match self {
Patch::Some(_) => self,
Patch::Empty | Patch::None => other,
}
}
#[inline]
pub fn or_else<F>(self, f: F) -> Patch<T>
where
F: FnOnce() -> Patch<T>,
{
match self {
Patch::Some(_) => self,
Patch::Empty | Patch::None => f(),
}
}
#[inline]
pub fn xor(self, other: Patch<T>) -> Patch<T> {
match (self, other) {
(Patch::Some(a), Patch::Empty | Patch::None) => Patch::Some(a),
(Patch::Empty | Patch::None, Patch::Some(b)) => Patch::Some(b),
(Patch::Empty, Patch::None) | (Patch::None, Patch::Empty) => Patch::Empty,
_ => Patch::None,
}
}
#[inline]
pub fn zip<U>(self, other: Patch<U>) -> Patch<(T, U)> {
match (self, other) {
(Patch::Some(a), Patch::Some(b)) => Patch::Some((a, b)),
(Patch::Empty, _) | (_, Patch::Empty) => Patch::Empty,
_ => Patch::None,
}
}
#[inline]
pub fn zip_with<U, R, F>(self, other: Patch<U>, f: F) -> Patch<R>
where
F: FnOnce(T, U) -> R,
{
self.zip(other).map(|(a, b)| f(a, b))
}
}
impl<T> Patch<T> {
#[inline]
pub fn insert(&mut self, value: T) -> &mut T {
*self = Patch::Some(value);
match self {
Patch::Some(v) => v,
_ => unreachable!(),
}
}
#[inline]
pub fn get_or_insert(&mut self, value: T) -> &mut T {
if !self.is_some() {
*self = Patch::Some(value);
}
match self {
Patch::Some(v) => v,
_ => unreachable!(),
}
}
#[inline]
pub fn get_or_insert_with<F>(&mut self, f: F) -> &mut T
where
F: FnOnce() -> T,
{
if !self.is_some() {
*self = Patch::Some(f());
}
match self {
Patch::Some(v) => v,
_ => unreachable!(),
}
}
#[inline]
pub fn take(&mut self) -> Patch<T> {
core::mem::replace(self, Patch::Empty)
}
#[inline]
pub fn replace(&mut self, value: T) -> Patch<T> {
core::mem::replace(self, Patch::Some(value))
}
}
impl<T: Default> Patch<T> {
#[inline]
pub fn get_or_insert_default(&mut self) -> &mut T {
self.get_or_insert_with(T::default)
}
}
impl<T: Clone> Patch<&T> {
#[inline]
pub fn cloned(self) -> Patch<T> {
self.map(|t| t.clone())
}
}
impl<T: Copy> Patch<&T> {
#[inline]
pub fn copied(self) -> Patch<T> {
self.map(|&t| t)
}
}
impl<T> Patch<T> {
#[inline]
pub fn into_option(self) -> Option<T> {
match self {
Patch::Some(v) => Some(v),
Patch::Empty | Patch::None => None,
}
}
}
impl<T> Default for Patch<T> {
#[inline]
fn default() -> Patch<T> {
Patch::Empty
}
}
impl<T> From<T> for Patch<T> {
#[inline]
fn from(value: T) -> Patch<T> {
Patch::Some(value)
}
}
impl<T> From<Option<T>> for Patch<T> {
#[inline]
fn from(opt: Option<T>) -> Patch<T> {
match opt {
Some(v) => Patch::Some(v),
None => Patch::None,
}
}
}
impl<T> From<Patch<T>> for Option<T> {
#[inline]
fn from(patch: Patch<T>) -> Option<T> {
patch.into_option()
}
}
impl<T> From<Option<Option<T>>> for Patch<T> {
#[inline]
fn from(value: Option<Option<T>>) -> Patch<T> {
match value {
None => Patch::Empty,
Some(None) => Patch::None,
Some(Some(v)) => Patch::Some(v),
}
}
}
impl<T> From<Patch<T>> for Option<Option<T>> {
#[inline]
fn from(patch: Patch<T>) -> Option<Option<T>> {
match patch {
Patch::Empty => None,
Patch::None => Some(None),
Patch::Some(v) => Some(Some(v)),
}
}
}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
mod serde_impl {
use super::Patch;
use core::fmt;
use core::marker::PhantomData;
use serde::de::{self, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
impl<'de, T> Deserialize<'de> for Patch<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct PatchVisitor<T>(PhantomData<T>);
impl<'de, T> Visitor<'de> for PatchVisitor<T>
where
T: Deserialize<'de>,
{
type Value = Patch<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("any value or null")
}
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Patch::None)
}
fn visit_unit<E>(self) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Patch::None)
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
T::deserialize(deserializer).map(Patch::Some)
}
}
deserializer.deserialize_option(PatchVisitor(PhantomData))
}
}
impl<T> Serialize for Patch<T>
where
T: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Patch::Some(v) => serializer.serialize_some(v),
Patch::Empty | Patch::None => serializer.serialize_none(),
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(not(feature = "std"))]
use alloc::string::String;
#[cfg(feature = "std")]
use std::string::String;
#[test]
fn test_queries() {
assert!(Patch::Some(42).is_some());
assert!(!Patch::<i32>::Empty.is_some());
assert!(!Patch::<i32>::None.is_some());
assert!(!Patch::Some(42).is_empty());
assert!(Patch::<i32>::Empty.is_empty());
assert!(!Patch::<i32>::None.is_empty());
assert!(!Patch::Some(42).is_none());
assert!(!Patch::<i32>::Empty.is_none());
assert!(Patch::<i32>::None.is_none());
assert!(Patch::<i32>::None.is_null());
}
#[test]
fn test_contains() {
assert!(Patch::Some(42).contains(&42));
assert!(!Patch::Some(42).contains(&0));
assert!(!Patch::<i32>::Empty.contains(&42));
assert!(!Patch::<i32>::None.contains(&42));
}
#[test]
fn test_as_ref_as_mut() {
let patch = Patch::Some(42);
assert_eq!(patch.as_ref(), Patch::Some(&42));
let mut patch = Patch::Some(42);
if let Patch::Some(v) = patch.as_mut() {
*v = 100;
}
assert_eq!(patch, Patch::Some(100));
}
#[test]
fn test_map() {
assert_eq!(Patch::Some(21).map(|x| x * 2), Patch::Some(42));
assert_eq!(Patch::<i32>::Empty.map(|x| x * 2), Patch::Empty);
assert_eq!(Patch::<i32>::None.map(|x| x * 2), Patch::None);
}
#[test]
fn test_map_or() {
assert_eq!(Patch::Some(21).map_or(0, |x| x * 2), 42);
assert_eq!(Patch::<i32>::Empty.map_or(0, |x| x * 2), 0);
assert_eq!(Patch::<i32>::None.map_or(0, |x| x * 2), 0);
}
#[test]
fn test_and_then() {
let double = |x: i32| Patch::Some(x * 2);
assert_eq!(Patch::Some(21).and_then(double), Patch::Some(42));
assert_eq!(Patch::<i32>::Empty.and_then(double), Patch::Empty);
assert_eq!(Patch::<i32>::None.and_then(double), Patch::None);
}
#[test]
fn test_filter() {
assert_eq!(Patch::Some(42).filter(|&x| x > 0), Patch::Some(42));
assert_eq!(Patch::Some(-1).filter(|&x| x > 0), Patch::None);
assert_eq!(Patch::<i32>::Empty.filter(|&x| x > 0), Patch::Empty);
}
#[test]
fn test_unwrap_variants() {
assert_eq!(Patch::Some(42).unwrap(), 42);
assert_eq!(Patch::Some(42).unwrap_or(0), 42);
assert_eq!(Patch::<i32>::Empty.unwrap_or(0), 0);
assert_eq!(Patch::<i32>::None.unwrap_or(0), 0);
assert_eq!(Patch::<i32>::Empty.unwrap_or_else(|| 100), 100);
assert_eq!(Patch::<i32>::Empty.unwrap_or_default(), 0);
}
#[test]
#[should_panic(expected = "called `Patch::unwrap()` on an `Empty` value")]
fn test_unwrap_empty_panics() {
Patch::<i32>::Empty.unwrap();
}
#[test]
#[should_panic(expected = "called `Patch::unwrap()` on a `None` value")]
fn test_unwrap_none_panics() {
Patch::<i32>::None.unwrap();
}
#[test]
fn test_or_combinators() {
assert_eq!(Patch::Some(1).or(Patch::Some(2)), Patch::Some(1));
assert_eq!(Patch::<i32>::Empty.or(Patch::Some(2)), Patch::Some(2));
assert_eq!(Patch::<i32>::None.or(Patch::Some(2)), Patch::Some(2));
assert_eq!(Patch::Some(1).or_else(|| Patch::Some(2)), Patch::Some(1));
assert_eq!(
Patch::<i32>::Empty.or_else(|| Patch::Some(2)),
Patch::Some(2)
);
}
#[test]
fn test_xor() {
assert_eq!(Patch::Some(1).xor(Patch::<i32>::Empty), Patch::Some(1));
assert_eq!(Patch::<i32>::Empty.xor(Patch::Some(2)), Patch::Some(2));
assert_eq!(Patch::<i32>::Empty.xor(Patch::<i32>::None), Patch::Empty);
assert_eq!(Patch::Some(1).xor(Patch::Some(2)), Patch::None);
assert_eq!(Patch::<i32>::Empty.xor(Patch::<i32>::Empty), Patch::None);
assert_eq!(Patch::<i32>::None.xor(Patch::<i32>::None), Patch::None);
}
#[test]
fn test_zip() {
assert_eq!(Patch::Some(1).zip(Patch::Some("a")), Patch::Some((1, "a")));
assert_eq!(Patch::Some(1).zip(Patch::<&str>::Empty), Patch::Empty);
assert_eq!(Patch::<i32>::None.zip(Patch::Some("a")), Patch::None);
}
#[test]
fn test_mutation_methods() {
let mut patch = Patch::<i32>::Empty;
assert_eq!(*patch.insert(42), 42);
assert_eq!(patch, Patch::Some(42));
let mut patch = Patch::<i32>::Empty;
assert_eq!(*patch.get_or_insert(42), 42);
let mut patch = Patch::Some(1);
assert_eq!(*patch.get_or_insert(42), 1);
let mut patch = Patch::Some(42);
let taken = patch.take();
assert_eq!(taken, Patch::Some(42));
assert_eq!(patch, Patch::Empty);
let mut patch = Patch::Some(42);
let old = patch.replace(100);
assert_eq!(old, Patch::Some(42));
assert_eq!(patch, Patch::Some(100));
}
#[test]
fn test_conversions() {
let patch: Patch<i32> = 42.into();
assert_eq!(patch, Patch::Some(42));
let patch: Patch<i32> = Some(42).into();
assert_eq!(patch, Patch::Some(42));
let patch: Patch<i32> = Option::<i32>::None.into();
assert_eq!(patch, Patch::None);
let opt: Option<i32> = Patch::Some(42).into();
assert_eq!(opt, Some(42));
let opt: Option<i32> = Patch::<i32>::Empty.into();
assert_eq!(opt, None);
let patch: Patch<i32> = Option::<Option<i32>>::None.into();
assert_eq!(patch, Patch::Empty);
let patch: Patch<i32> = Some(None).into();
assert_eq!(patch, Patch::None);
let patch: Patch<i32> = Some(Some(42)).into();
assert_eq!(patch, Patch::Some(42));
let opt: Option<Option<i32>> = Patch::<i32>::Empty.into();
assert_eq!(opt, None);
let opt: Option<Option<i32>> = Patch::<i32>::None.into();
assert_eq!(opt, Some(None));
let opt: Option<Option<i32>> = Patch::<i32>::Some(42).into();
assert_eq!(opt, Some(Some(42)));
}
#[test]
fn test_default() {
let patch: Patch<i32> = Patch::default();
assert_eq!(patch, Patch::Empty);
}
#[test]
fn test_clone_copy() {
let patch = Patch::Some(String::from("hello"));
let cloned = patch.clone();
assert_eq!(patch, cloned);
let patch = Patch::Some(42);
let copied = patch;
assert_eq!(patch, copied);
}
#[test]
fn test_cloned_copied() {
let value = 42;
let patch = Patch::Some(&value);
assert_eq!(patch.copied(), Patch::Some(42));
let s = String::from("hello");
let patch = Patch::Some(&s);
assert_eq!(patch.cloned(), Patch::Some(String::from("hello")));
}
#[test]
fn test_as_deref() {
let patch = Patch::Some(String::from("hello"));
assert_eq!(patch.as_deref(), Patch::Some("hello"));
let empty: Patch<String> = Patch::Empty;
assert_eq!(empty.as_deref(), Patch::Empty);
}
#[test]
fn test_ord() {
assert!(Patch::Some(1) < Patch::Some(2));
assert!(Patch::<i32>::Empty < Patch::<i32>::None);
assert!(Patch::Some(1) < Patch::<i32>::Empty);
}
#[test]
#[cfg(feature = "std")]
fn test_hash() {
use core::hash::{Hash, Hasher};
use std::collections::hash_map::DefaultHasher;
fn hash<T: Hash>(t: &T) -> u64 {
let mut s = DefaultHasher::new();
t.hash(&mut s);
s.finish()
}
assert_eq!(hash(&Patch::Some(42)), hash(&Patch::Some(42)));
assert_ne!(hash(&Patch::Some(42)), hash(&Patch::Some(0)));
assert_ne!(hash(&Patch::<i32>::Empty), hash(&Patch::<i32>::None));
}
}
#[cfg(all(test, feature = "serde"))]
mod serde_tests {
use super::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, PartialEq)]
struct TestStruct {
#[serde(default, skip_serializing_if = "Patch::is_empty")]
value: Patch<i32>,
}
#[test]
fn test_deserialize_some() {
let json = r#"{"value": 42}"#;
let s: TestStruct = serde_json::from_str(json).unwrap();
assert_eq!(s.value, Patch::Some(42));
}
#[test]
fn test_deserialize_null() {
let json = r#"{"value": null}"#;
let s: TestStruct = serde_json::from_str(json).unwrap();
assert_eq!(s.value, Patch::None);
}
#[test]
fn test_deserialize_missing() {
let json = r#"{}"#;
let s: TestStruct = serde_json::from_str(json).unwrap();
assert_eq!(s.value, Patch::Empty);
}
#[test]
fn test_serialize_some() {
let s = TestStruct {
value: Patch::Some(42),
};
let json = serde_json::to_string(&s).unwrap();
assert_eq!(json, r#"{"value":42}"#);
}
#[test]
fn test_serialize_none() {
let s = TestStruct { value: Patch::None };
let json = serde_json::to_string(&s).unwrap();
assert_eq!(json, r#"{"value":null}"#);
}
#[test]
fn test_serialize_empty() {
let s = TestStruct {
value: Patch::Empty,
};
let json = serde_json::to_string(&s).unwrap();
assert_eq!(json, r#"{}"#);
}
#[test]
fn test_roundtrip() {
let original = TestStruct {
value: Patch::Some(42),
};
let json = serde_json::to_string(&original).unwrap();
let parsed: TestStruct = serde_json::from_str(&json).unwrap();
assert_eq!(original, parsed);
}
}