use std::cmp::Ordering;
use std::fmt;
use std::iter;
use std::str::FromStr;
use conv::errors::NoError;
use serde::de::{Deserialize, Deserializer, IntoDeserializer};
use serde::ser::{Serialize, Serializer};
use super::json::Json;
#[must_use]
pub enum Quasi<T, S = Json> {
True(T),
Substitute(S),
}
impl<T, S> From<T> for Quasi<T, S> {
fn from(v: T) -> Self {
Quasi::True(v)
}
}
impl<T: Default, S> Default for Quasi<T, S> {
fn default() -> Self {
Quasi::True(Default::default())
}
}
impl<'de, T, S> Deserialize<'de> for Quasi<T, S>
where T: Deserialize<'de>,
S: Clone + Deserialize<'de> + IntoDeserializer<'de>
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
let source: S = Deserialize::deserialize(deserializer)?;
let source_de = IntoDeserializer::into_deserializer(source.clone());
Ok(match T::deserialize(source_de) {
Ok(v) => Quasi::True(v),
Err(_) => Quasi::Substitute(source),
})
}
}
impl<T: FromStr> FromStr for Quasi<T, String> {
type Err = NoError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match T::from_str(s) {
Ok(v) => Quasi::True(v),
Err(_) => Quasi::Substitute(s.to_owned()),
})
}
}
impl<T, S> Serialize for Quasi<T, S>
where T: Serialize,
S: Serialize
{
fn serialize<Ser>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error>
where Ser: Serializer
{
match *self {
Quasi::True(ref v) => Serialize::serialize(v, serializer),
Quasi::Substitute(ref v) => Serialize::serialize(v, serializer),
}
}
}
impl<T, S> Quasi<T, S> {
pub fn expect(self, msg: &str) -> T {
match self {
Quasi::True(v) => v,
Quasi::Substitute(_) => panic!("{}", msg),
}
}
pub fn get(&self) -> &T {
match *self {
Quasi::True(ref v) => v,
Quasi::Substitute(_) => panic!("Quasi::get on a substitute"),
}
}
pub fn get_mut(&mut self) -> &mut T {
match *self {
Quasi::True(ref mut v) => v,
Quasi::Substitute(_) => panic!("Quasi::get_mut on a substitute"),
}
}
pub fn unwrap(self) -> T {
match self {
Quasi::True(v) => v,
Quasi::Substitute(_) => panic!("Quasi::unwrap on a substitute"),
}
}
}
impl<T, S> Quasi<T, S> {
pub fn as_ref(&self) -> Option<&T> {
match *self {
Quasi::True(ref v) => Some(v),
Quasi::Substitute(_) => None,
}
}
pub fn as_mut(&mut self) -> Option<&mut T> {
match *self {
Quasi::True(ref mut v) => Some(v),
Quasi::Substitute(_) => None,
}
}
pub fn iter<'q>(&'q self) -> Box<Iterator<Item=&'q T> + 'q> {
match *self {
Quasi::True(ref v) => Box::new(iter::once(v)),
Quasi::Substitute(_) => Box::new(iter::empty()),
}
}
pub fn iter_mut<'q>(&'q mut self) -> Box<Iterator<Item=&'q mut T> + 'q> {
match *self {
Quasi::True(ref mut v) => Box::new(iter::once(v)),
Quasi::Substitute(_) => Box::new(iter::empty()),
}
}
pub fn unwrap_or(self, def: T) -> T {
match self {
Quasi::True(v) => v,
Quasi::Substitute(_) => def,
}
}
pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
match self {
Quasi::True(v) => v,
Quasi::Substitute(_) => f(),
}
}
}
impl<T: Default, S> Quasi<T, S> {
pub fn unwrap_or_default(self) -> T {
match self {
Quasi::True(v) => v,
Quasi::Substitute(_) => Default::default(),
}
}
}
impl<T, S> Quasi<T, S> {
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Quasi<U, S> {
match self {
Quasi::True(v) => Quasi::True(f(v)),
Quasi::Substitute(v) => Quasi::Substitute(v),
}
}
}
impl<T, S> Clone for Quasi<T, S>
where T: Clone, S: Clone
{
fn clone(&self) -> Self {
match *self {
Quasi::True(ref v) => Quasi::True(v.clone()),
Quasi::Substitute(ref v) => Quasi::Substitute(v.clone()),
}
}
}
impl<T, S> PartialEq for Quasi<T, S>
where T: PartialEq, S: PartialEq
{
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(&Quasi::True(ref v1), &Quasi::True(ref v2)) => v1 == v2,
(&Quasi::Substitute(ref v1), &Quasi::Substitute(ref v2)) => v1 == v2,
_ => false,
}
}
}
impl<T, S> PartialOrd for Quasi<T, S>
where T: PartialOrd, S: PartialOrd
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (self, other) {
(&Quasi::True(ref v1), &Quasi::True(ref v2)) => v1.partial_cmp(v2),
(&Quasi::Substitute(ref v1), &Quasi::Substitute(ref v2)) => v1.partial_cmp(v2),
_ => None,
}
}
}
impl<T, S> Into<Option<T>> for Quasi<T, S> {
fn into(self) -> Option<T> {
match self {
Quasi::True(v) => Some(v),
Quasi::Substitute(_) => None,
}
}
}
impl<T, S> Into<Result<T, S>> for Quasi<T, S> {
fn into(self) -> Result<T, S> {
match self {
Quasi::True(v) => Ok(v),
Quasi::Substitute(v) => Err(v),
}
}
}
impl<T, S> fmt::Debug for Quasi<T, S>
where T: fmt::Debug, S: fmt::Debug
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
Quasi::True(ref v) => write!(fmt, "Quasi::True({:?})", v),
Quasi::Substitute(ref v) => write!(fmt, "Quasi::Substitute({:?})", v),
}
}
}
impl<T, S> fmt::Display for Quasi<T, S>
where T: fmt::Display, S: fmt::Display
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", match *self {
Quasi::True(ref v) => v as &fmt::Display,
Quasi::Substitute(ref v) => v as &fmt::Display,
})
}
}