#![allow(dead_code)]
#[cfg(feature = "serdejson")]
use serde::ser::{Serialize, Serializer};
#[cfg(feature = "serdejson")]
use serde::de::{Deserializer, Deserialize, DeserializeOwned};
#[cfg(feature = "serdejson")]
use serde::de::Error as SerdeError;
use std::mem;
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub enum Nullable<T> {
Null,
Present(T),
}
impl<T> Nullable<T> {
#[inline]
pub fn is_present(&self) -> bool {
match *self {
Nullable::Present(_) => true,
Nullable::Null => false,
}
}
#[inline]
pub fn is_null(&self) -> bool {
!self.is_present()
}
#[inline]
pub fn as_ref(&self) -> Nullable<&T> {
match *self {
Nullable::Present(ref x) => Nullable::Present(x),
Nullable::Null => Nullable::Null,
}
}
#[inline]
pub fn as_mut(&mut self) -> Nullable<&mut T> {
match *self {
Nullable::Present(ref mut x) => Nullable::Present(x),
Nullable::Null => Nullable::Null,
}
}
#[inline]
pub fn expect(self, msg: &str) -> T {
match self {
Nullable::Present(val) => val,
Nullable::Null => expect_failed(msg),
}
}
#[inline]
pub fn unwrap(self) -> T {
match self {
Nullable::Present(val) => val,
Nullable::Null => panic!("called `Nullable::unwrap()` on a `Nullable::Null` value"),
}
}
#[inline]
pub fn unwrap_or(self, def: T) -> T {
match self {
Nullable::Present(x) => x,
Nullable::Null => def,
}
}
#[inline]
pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
match self {
Nullable::Present(x) => x,
Nullable::Null => f(),
}
}
#[inline]
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Nullable<U> {
match self {
Nullable::Present(x) => Nullable::Present(f(x)),
Nullable::Null => Nullable::Null,
}
}
#[inline]
pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
match self {
Nullable::Present(t) => f(t),
Nullable::Null => default,
}
}
#[inline]
pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
match self {
Nullable::Present(t) => f(t),
Nullable::Null => default(),
}
}
#[inline]
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
match self {
Nullable::Present(v) => Ok(v),
Nullable::Null => Err(err),
}
}
#[inline]
pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
match self {
Nullable::Present(v) => Ok(v),
Nullable::Null => Err(err()),
}
}
#[inline]
pub fn and<U>(self, optb: Nullable<U>) -> Nullable<U> {
match self {
Nullable::Present(_) => optb,
Nullable::Null => Nullable::Null,
}
}
#[inline]
pub fn and_then<U, F: FnOnce(T) -> Nullable<U>>(self, f: F) -> Nullable<U> {
match self {
Nullable::Present(x) => f(x),
Nullable::Null => Nullable::Null,
}
}
#[inline]
pub fn or(self, optb: Nullable<T>) -> Nullable<T> {
match self {
Nullable::Present(_) => self,
Nullable::Null => optb,
}
}
#[inline]
pub fn or_else<F: FnOnce() -> Nullable<T>>(self, f: F) -> Nullable<T> {
match self {
Nullable::Present(_) => self,
Nullable::Null => f(),
}
}
#[inline]
pub fn take(&mut self) -> Nullable<T> {
mem::replace(self, Nullable::Null)
}
}
impl<'a, T: Clone> Nullable<&'a T> {
pub fn cloned(self) -> Nullable<T> {
self.map(|t| t.clone())
}
}
impl<T: Default> Nullable<T> {
#[inline]
pub fn unwrap_or_default(self) -> T {
match self {
Nullable::Present(x) => x,
Nullable::Null => Default::default(),
}
}
}
#[inline(never)]
#[cold]
fn expect_failed(msg: &str) -> ! {
panic!("{}", msg)
}
impl<T> Default for Nullable<T> {
#[inline]
fn default() -> Nullable<T> {
Nullable::Null
}
}
impl<T> From<T> for Nullable<T> {
fn from(val: T) -> Nullable<T> {
Nullable::Present(val)
}
}
#[cfg(feature = "serdejson")]
impl<T> Serialize for Nullable<T>
where
T: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
Nullable::Present(ref inner) => serializer.serialize_some(&inner),
Nullable::Null => serializer.serialize_none(),
}
}
}
#[cfg(feature = "serdejson")]
impl<'de, T> Deserialize<'de> for Nullable<T>
where
T: DeserializeOwned,
{
fn deserialize<D>(deserializer: D) -> Result<Nullable<T>, D::Error>
where
D: Deserializer<'de>,
{
let presence: Result<::serde_json::Value, _> =
::serde::Deserialize::deserialize(deserializer);
match presence {
Ok(::serde_json::Value::Null) => Ok(Nullable::Null),
Ok(some_value) => {
::serde_json::from_value(some_value)
.map(Nullable::Present)
.map_err(SerdeError::custom)
}
Err(x) => Err(x),
}
}
}
pub fn default_optional_nullable<T>() -> Option<Nullable<T>> {
None
}
#[cfg(feature = "serdejson")]
pub fn deserialize_optional_nullable<'de, D, T>(
deserializer: D,
) -> Result<Option<Nullable<T>>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
{
Option::<T>::deserialize(deserializer).map(|val| match val {
Some(inner) => Some(Nullable::Present(inner)),
None => Some(Nullable::Null),
})
}
#[cfg(test)]
#[cfg(feature = "serdejson")]
mod serde_tests {
use super::*;
#[derive(Clone, Debug, Deserialize, Serialize)]
struct NullableStringStruct {
item: Nullable<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
struct OptionalNullableStringStruct {
#[serde(deserialize_with = "deserialize_optional_nullable")]
#[serde(default = "default_optional_nullable")]
#[serde(skip_serializing_if = "Option::is_none")]
item: Option<Nullable<String>>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
struct NullableObjectStruct {
item: Nullable<NullableStringStruct>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
struct OptionalNullableObjectStruct {
item: Option<Nullable<NullableStringStruct>>,
}
macro_rules! round_trip {
($type:ty, $string:expr) => {
println!("Original: {:?}", $string);
let json: ::serde_json::Value =
::serde_json::from_str($string).expect("Deserialization to JSON Value failed");
println!("JSON Value: {:?}", json);
let thing: $type =
::serde_json::from_value(json.clone()).expect("Deserialization to struct failed");
println!("Struct: {:?}", thing);
let json_redux: ::serde_json::Value =
::serde_json::to_value(thing.clone())
.expect("Reserialization to JSON Value failed");
println!("JSON Redux: {:?}", json_redux);
let string_redux =
::serde_json::to_string(&thing).expect("Reserialziation to JSON String failed");
println!("String Redux: {:?}", string_redux);
assert_eq!(
$string,
string_redux,
"Original did not match after round trip"
);
}
}
#[test]
fn missing_optionalnullable_value() {
let string = "{}";
round_trip!(OptionalNullableStringStruct, string);
}
#[test]
fn null_optionalnullable_value() {
let string = "{\"item\":null}";
round_trip!(OptionalNullableStringStruct, string);
}
#[test]
fn string_optionalnullable_value() {
let string = "{\"item\":\"abc\"}";
round_trip!(OptionalNullableStringStruct, string);
}
#[test]
fn object_optionalnullable_value() {
let string = "{\"item\":{\"item\":\"abc\"}}";
round_trip!(OptionalNullableObjectStruct, string);
}
#[test]
#[should_panic]
fn missing_nullable_value() {
let string = "{}";
round_trip!(NullableStringStruct, string);
}
#[test]
fn null_nullable_value() {
let string = "{\"item\":null}";
round_trip!(NullableStringStruct, string);
}
#[test]
fn string_nullable_value() {
let string = "{\"item\":\"abc\"}";
round_trip!(NullableStringStruct, string);
}
#[test]
fn object_nullable_value() {
let string = "{\"item\":{\"item\":\"abc\"}}";
round_trip!(NullableObjectStruct, string);
}
}