use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub enum Loaded<T> {
#[default]
NotLoaded,
Some(T),
}
impl<T> Loaded<T> {
pub fn is_loaded(&self) -> bool {
matches!(self, Self::Some(_))
}
pub fn as_option(&self) -> Option<&T> {
match self {
Self::Some(v) => Some(v),
Self::NotLoaded => None,
}
}
pub fn into_option(self) -> Option<T> {
match self {
Self::Some(v) => Some(v),
Self::NotLoaded => None,
}
}
pub fn unwrap(self) -> T {
match self {
Self::Some(v) => v,
Self::NotLoaded => panic!("called Loaded::unwrap() on a NotLoaded value"),
}
}
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Loaded<U> {
match self {
Self::Some(v) => Loaded::Some(f(v)),
Self::NotLoaded => Loaded::NotLoaded,
}
}
}
impl<T: Serialize> Serialize for Loaded<T> {
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
match self {
Self::Some(v) => v.serialize(s),
Self::NotLoaded => s.serialize_none(),
}
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Loaded<T> {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
Option::<T>::deserialize(d).map(|opt| match opt {
Some(v) => Self::Some(v),
None => Self::NotLoaded,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_is_not_loaded() {
let l: Loaded<Vec<i32>> = Loaded::default();
assert!(!l.is_loaded());
assert!(l.as_option().is_none());
}
#[test]
fn some_is_loaded() {
let l = Loaded::Some(vec![1, 2, 3]);
assert!(l.is_loaded());
assert_eq!(l.as_option().unwrap().len(), 3);
}
#[test]
fn map_transforms_value() {
let l = Loaded::Some(vec![1_i32, 2, 3]);
let l2 = l.map(|v| v.len());
assert_eq!(l2, Loaded::Some(3));
}
#[test]
fn into_option() {
let l: Loaded<i32> = Loaded::NotLoaded;
assert_eq!(l.into_option(), None);
assert_eq!(Loaded::Some(42_i32).into_option(), Some(42));
}
#[test]
fn serialize_not_loaded_as_null() {
let l: Loaded<i32> = Loaded::NotLoaded;
let s = serde_json::to_string(&l).unwrap();
assert_eq!(s, "null");
}
#[test]
fn serialize_some() {
let l = Loaded::Some(vec![1_i32, 2]);
let s = serde_json::to_string(&l).unwrap();
assert_eq!(s, "[1,2]");
}
}