mod date;
mod datetime;
pub(crate) mod ser;
use std::cmp::Ordering;
use std::{borrow::Cow, fmt};
use kstring::KString;
use kstring::KStringCow;
use kstring::KStringRef;
use crate::model::value::{DisplayCow, State};
use crate::model::{Value, ValueView};
pub use date::*;
pub use datetime::*;
pub use ser::to_scalar;
#[derive(Clone, serde::Serialize, serde::Deserialize)]
#[serde(transparent)]
#[repr(transparent)]
pub struct ScalarCow<'s>(ScalarCowEnum<'s>);
pub type Scalar = ScalarCow<'static>;
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
#[serde(untagged)]
enum ScalarCowEnum<'s> {
Integer(i64),
Float(f64),
Bool(bool),
DateTime(DateTime),
Date(Date),
Str(KStringCow<'s>),
}
impl<'s> ScalarCow<'s> {
pub fn new<T: Into<Self>>(value: T) -> Self {
value.into()
}
pub fn into_owned(self) -> Scalar {
match self.0 {
ScalarCowEnum::Integer(x) => Scalar::new(x),
ScalarCowEnum::Float(x) => Scalar::new(x),
ScalarCowEnum::Bool(x) => Scalar::new(x),
ScalarCowEnum::DateTime(x) => Scalar::new(x),
ScalarCowEnum::Date(x) => Scalar::new(x),
ScalarCowEnum::Str(x) => Scalar::new(x.into_owned()),
}
}
pub fn as_ref<'r: 's>(&'r self) -> ScalarCow<'r> {
match self.0 {
ScalarCowEnum::Integer(x) => ScalarCow::new(x),
ScalarCowEnum::Float(x) => ScalarCow::new(x),
ScalarCowEnum::Bool(x) => ScalarCow::new(x),
ScalarCowEnum::DateTime(x) => ScalarCow::new(x),
ScalarCowEnum::Date(x) => ScalarCow::new(x),
ScalarCowEnum::Str(ref x) => ScalarCow::new(x.as_ref()),
}
}
pub fn as_view<'r: 's>(&'r self) -> &'s dyn ValueView {
match self.0 {
ScalarCowEnum::Integer(ref x) => x,
ScalarCowEnum::Float(ref x) => x,
ScalarCowEnum::Bool(ref x) => x,
ScalarCowEnum::DateTime(ref x) => x,
ScalarCowEnum::Date(ref x) => x,
ScalarCowEnum::Str(ref x) => x,
}
}
pub fn into_string(self) -> KString {
match self.0 {
ScalarCowEnum::Integer(x) => x.to_string().into(),
ScalarCowEnum::Float(x) => x.to_string().into(),
ScalarCowEnum::Bool(x) => x.to_string().into(),
ScalarCowEnum::DateTime(x) => x.to_string().into(),
ScalarCowEnum::Date(x) => x.to_string().into(),
ScalarCowEnum::Str(x) => x.into_owned(),
}
}
pub fn to_integer(&self) -> Option<i64> {
match self.0 {
ScalarCowEnum::Integer(ref x) => Some(*x),
ScalarCowEnum::Str(ref x) => x.parse::<i64>().ok(),
_ => None,
}
}
pub fn to_float(&self) -> Option<f64> {
match self.0 {
ScalarCowEnum::Integer(ref x) => Some(*x as f64),
ScalarCowEnum::Float(ref x) => Some(*x),
ScalarCowEnum::Str(ref x) => x.parse::<f64>().ok(),
_ => None,
}
}
pub fn to_bool(&self) -> Option<bool> {
match self.0 {
ScalarCowEnum::Bool(ref x) => Some(*x),
_ => None,
}
}
pub fn to_date_time(&self) -> Option<DateTime> {
match self.0 {
ScalarCowEnum::DateTime(ref x) => Some(*x),
ScalarCowEnum::Str(ref x) => DateTime::from_str(x.as_str()),
_ => None,
}
}
pub fn to_date(&self) -> Option<Date> {
match self.0 {
ScalarCowEnum::DateTime(ref x) => Some(x.date()),
ScalarCowEnum::Date(ref x) => Some(*x),
ScalarCowEnum::Str(ref x) => Date::from_str(x.as_str()),
_ => None,
}
}
pub fn into_cow_str(self) -> Cow<'s, str> {
match self {
Self(ScalarCowEnum::Str(x)) => x.into_cow_str(),
other => other.into_string().into_cow_str(),
}
}
}
impl<'s> fmt::Debug for ScalarCow<'s> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl<'s> ValueView for ScalarCow<'s> {
fn as_debug(&self) -> &dyn fmt::Debug {
self
}
fn render(&self) -> DisplayCow<'_> {
self.as_view().render()
}
fn source(&self) -> DisplayCow<'_> {
self.as_view().source()
}
fn type_name(&self) -> &'static str {
self.as_view().type_name()
}
fn query_state(&self, state: State) -> bool {
self.as_view().query_state(state)
}
fn to_kstr(&self) -> KStringCow<'_> {
self.as_view().to_kstr()
}
fn to_value(&self) -> Value {
self.as_view().to_value()
}
fn as_scalar(&self) -> Option<ScalarCow<'_>> {
Some(self.as_ref())
}
}
impl<'s> PartialEq<ScalarCow<'s>> for ScalarCow<'s> {
fn eq(&self, other: &Self) -> bool {
scalar_eq(self, other)
}
}
impl<'s> PartialOrd<ScalarCow<'s>> for ScalarCow<'s> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
scalar_cmp(self, other)
}
}
impl ValueView for i64 {
fn as_debug(&self) -> &dyn fmt::Debug {
self
}
fn render(&self) -> DisplayCow<'_> {
DisplayCow::Borrowed(self)
}
fn source(&self) -> DisplayCow<'_> {
DisplayCow::Borrowed(self)
}
fn type_name(&self) -> &'static str {
"whole number"
}
fn query_state(&self, state: State) -> bool {
match state {
State::Truthy => true,
State::DefaultValue => false,
State::Empty => false,
State::Blank => false,
}
}
fn to_kstr(&self) -> KStringCow<'_> {
self.render().to_string().into()
}
fn to_value(&self) -> Value {
Value::scalar(*self)
}
fn as_scalar(&self) -> Option<ScalarCow<'_>> {
Some(ScalarCow::new(*self))
}
}
impl<'s> From<i64> for ScalarCow<'s> {
fn from(s: i64) -> Self {
ScalarCow {
0: ScalarCowEnum::Integer(s),
}
}
}
impl<'s> PartialEq<i64> for ScalarCow<'s> {
fn eq(&self, other: &i64) -> bool {
let other = (*other).into();
scalar_eq(self, &other)
}
}
impl<'s> PartialOrd<i64> for ScalarCow<'s> {
fn partial_cmp(&self, other: &i64) -> Option<Ordering> {
let other = (*other).into();
scalar_cmp(self, &other)
}
}
macro_rules! impl_copyable {
($user: ty, $internal: ty) => {
impl ValueView for $user {
fn as_debug(&self) -> &dyn fmt::Debug {
self
}
fn render(&self) -> DisplayCow<'_> {
DisplayCow::Borrowed(self)
}
fn source(&self) -> DisplayCow<'_> {
DisplayCow::Borrowed(self)
}
fn type_name(&self) -> &'static str {
<$internal>::from(*self).type_name()
}
fn query_state(&self, state: State) -> bool {
<$internal>::from(*self).query_state(state)
}
fn to_kstr(&self) -> KStringCow<'_> {
self.render().to_string().into()
}
fn to_value(&self) -> Value {
<$internal>::from(*self).to_value()
}
fn as_scalar(&self) -> Option<ScalarCow<'_>> {
Some(ScalarCow::new(<$internal>::from(*self)))
}
}
impl<'s> From<$user> for ScalarCow<'s> {
fn from(s: $user) -> Self {
ScalarCow::from(<$internal>::from(s))
}
}
impl<'s> PartialEq<$user> for ScalarCow<'s> {
fn eq(&self, other: &$user) -> bool {
let other = <$internal>::from(*other).into();
scalar_eq(self, &other)
}
}
impl<'s> PartialOrd<$user> for ScalarCow<'s> {
fn partial_cmp(&self, other: &$user) -> Option<Ordering> {
let other = <$internal>::from(*other).into();
scalar_cmp(self, &other)
}
}
};
}
impl_copyable!(u8, i64);
impl_copyable!(i8, i64);
impl_copyable!(u16, i64);
impl_copyable!(i16, i64);
impl_copyable!(u32, i64);
impl_copyable!(i32, i64);
impl ValueView for f64 {
fn as_debug(&self) -> &dyn fmt::Debug {
self
}
fn render(&self) -> DisplayCow<'_> {
DisplayCow::Borrowed(self)
}
fn source(&self) -> DisplayCow<'_> {
DisplayCow::Borrowed(self)
}
fn type_name(&self) -> &'static str {
"fractional number"
}
fn query_state(&self, state: State) -> bool {
match state {
State::Truthy => true,
State::DefaultValue => false,
State::Empty => false,
State::Blank => false,
}
}
fn to_kstr(&self) -> KStringCow<'_> {
self.render().to_string().into()
}
fn to_value(&self) -> Value {
Value::scalar(*self)
}
fn as_scalar(&self) -> Option<ScalarCow<'_>> {
Some(ScalarCow::new(*self))
}
}
impl<'s> From<f64> for ScalarCow<'s> {
fn from(s: f64) -> Self {
ScalarCow {
0: ScalarCowEnum::Float(s),
}
}
}
impl<'s> PartialEq<f64> for ScalarCow<'s> {
fn eq(&self, other: &f64) -> bool {
let other = (*other).into();
scalar_eq(self, &other)
}
}
impl<'s> PartialOrd<f64> for ScalarCow<'s> {
fn partial_cmp(&self, other: &f64) -> Option<Ordering> {
let other = (*other).into();
scalar_cmp(self, &other)
}
}
impl_copyable!(f32, f64);
impl ValueView for bool {
fn as_debug(&self) -> &dyn fmt::Debug {
self
}
fn render(&self) -> DisplayCow<'_> {
DisplayCow::Borrowed(self)
}
fn source(&self) -> DisplayCow<'_> {
DisplayCow::Borrowed(self)
}
fn type_name(&self) -> &'static str {
"boolean"
}
fn query_state(&self, state: State) -> bool {
match state {
State::Truthy => *self,
State::DefaultValue => !self,
State::Empty => false,
State::Blank => !self,
}
}
fn to_kstr(&self) -> KStringCow<'_> {
self.render().to_string().into()
}
fn to_value(&self) -> Value {
Value::scalar(*self)
}
fn as_scalar(&self) -> Option<ScalarCow<'_>> {
Some(ScalarCow::new(*self))
}
}
impl<'s> From<bool> for ScalarCow<'s> {
fn from(s: bool) -> Self {
ScalarCow {
0: ScalarCowEnum::Bool(s),
}
}
}
impl<'s> PartialEq<bool> for ScalarCow<'s> {
fn eq(&self, other: &bool) -> bool {
let other = (*other).into();
scalar_eq(self, &other)
}
}
impl<'s> PartialOrd<bool> for ScalarCow<'s> {
fn partial_cmp(&self, other: &bool) -> Option<Ordering> {
let other = (*other).into();
scalar_cmp(self, &other)
}
}
impl ValueView for DateTime {
fn as_debug(&self) -> &dyn fmt::Debug {
self
}
fn render(&self) -> DisplayCow<'_> {
DisplayCow::Borrowed(self)
}
fn source(&self) -> DisplayCow<'_> {
DisplayCow::Borrowed(self)
}
fn type_name(&self) -> &'static str {
"date time"
}
fn query_state(&self, state: State) -> bool {
match state {
State::Truthy => true,
State::DefaultValue => false,
State::Empty => false,
State::Blank => false,
}
}
fn to_kstr(&self) -> KStringCow<'_> {
self.render().to_string().into()
}
fn to_value(&self) -> Value {
Value::scalar(*self)
}
fn as_scalar(&self) -> Option<ScalarCow<'_>> {
Some(ScalarCow::new(*self))
}
}
impl<'s> From<DateTime> for ScalarCow<'s> {
fn from(s: DateTime) -> Self {
ScalarCow {
0: ScalarCowEnum::DateTime(s),
}
}
}
impl<'s> PartialEq<DateTime> for ScalarCow<'s> {
fn eq(&self, other: &DateTime) -> bool {
let other = (*other).into();
scalar_eq(self, &other)
}
}
impl<'s> PartialOrd<DateTime> for ScalarCow<'s> {
fn partial_cmp(&self, other: &DateTime) -> Option<Ordering> {
let other = (*other).into();
scalar_cmp(self, &other)
}
}
impl ValueView for Date {
fn as_debug(&self) -> &dyn fmt::Debug {
self
}
fn render(&self) -> DisplayCow<'_> {
DisplayCow::Borrowed(self)
}
fn source(&self) -> DisplayCow<'_> {
DisplayCow::Borrowed(self)
}
fn type_name(&self) -> &'static str {
"date"
}
fn query_state(&self, state: State) -> bool {
match state {
State::Truthy => true,
State::DefaultValue => false,
State::Empty => false,
State::Blank => false,
}
}
fn to_kstr(&self) -> KStringCow<'_> {
self.render().to_string().into()
}
fn to_value(&self) -> Value {
Value::scalar(*self)
}
fn as_scalar(&self) -> Option<ScalarCow<'_>> {
Some(ScalarCow::new(*self))
}
}
impl<'s> From<Date> for ScalarCow<'s> {
fn from(s: Date) -> Self {
ScalarCow {
0: ScalarCowEnum::Date(s),
}
}
}
impl<'s> PartialEq<Date> for ScalarCow<'s> {
fn eq(&self, other: &Date) -> bool {
let other = (*other).into();
scalar_eq(self, &other)
}
}
impl<'s> PartialOrd<Date> for ScalarCow<'s> {
fn partial_cmp(&self, other: &Date) -> Option<Ordering> {
let other = (*other).into();
scalar_cmp(self, &other)
}
}
impl<'s> ValueView for &'s str {
fn as_debug(&self) -> &dyn fmt::Debug {
self
}
fn render(&self) -> DisplayCow<'_> {
DisplayCow::Borrowed(self)
}
fn source(&self) -> DisplayCow<'_> {
DisplayCow::Owned(Box::new(StrSource { s: self }))
}
fn type_name(&self) -> &'static str {
"string"
}
fn query_state(&self, state: State) -> bool {
match state {
State::Truthy => true,
State::DefaultValue => self.is_empty(),
State::Empty => self.is_empty(),
State::Blank => self.trim().is_empty(),
}
}
fn to_kstr(&self) -> KStringCow<'_> {
(*self).into()
}
fn to_value(&self) -> Value {
Value::scalar(ScalarCow::new(KString::from_ref(self)))
}
fn as_scalar(&self) -> Option<ScalarCow<'_>> {
Some(ScalarCow::new(*self))
}
}
struct StrSource<'s> {
s: &'s str,
}
impl<'s> fmt::Display for StrSource<'s> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, r#""{}""#, self.s)
}
}
impl<'s> From<&'s str> for ScalarCow<'s> {
fn from(s: &'s str) -> Self {
ScalarCow {
0: ScalarCowEnum::Str(s.into()),
}
}
}
impl<'s> PartialEq<str> for ScalarCow<'s> {
fn eq(&self, other: &str) -> bool {
let other = other.into();
scalar_eq(self, &other)
}
}
impl<'s> PartialEq<&'s str> for ScalarCow<'s> {
fn eq(&self, other: &&str) -> bool {
let other = (*other).into();
scalar_eq(self, &other)
}
}
impl<'s> PartialOrd<str> for ScalarCow<'s> {
fn partial_cmp(&self, other: &str) -> Option<Ordering> {
let other = other.into();
scalar_cmp(self, &other)
}
}
impl ValueView for String {
fn as_debug(&self) -> &dyn fmt::Debug {
self
}
fn render(&self) -> DisplayCow<'_> {
DisplayCow::Borrowed(self)
}
fn source(&self) -> DisplayCow<'_> {
DisplayCow::Owned(Box::new(StrSource { s: self.as_str() }))
}
fn type_name(&self) -> &'static str {
ValueView::type_name(&self.as_str())
}
fn query_state(&self, state: State) -> bool {
ValueView::query_state(&self.as_str(), state)
}
fn to_kstr(&self) -> KStringCow<'_> {
self.as_str().into()
}
fn to_value(&self) -> Value {
ValueView::to_value(&self.as_str())
}
fn as_scalar(&self) -> Option<ScalarCow<'_>> {
Some(ScalarCow::new(self.as_str()))
}
}
impl<'s> From<String> for ScalarCow<'s> {
fn from(s: String) -> Self {
ScalarCow {
0: ScalarCowEnum::Str(s.into()),
}
}
}
impl<'s> From<&'s String> for ScalarCow<'s> {
fn from(s: &'s String) -> ScalarCow<'s> {
ScalarCow {
0: ScalarCowEnum::Str(s.as_str().into()),
}
}
}
impl<'s> PartialEq<String> for ScalarCow<'s> {
fn eq(&self, other: &String) -> bool {
let other = other.into();
scalar_eq(self, &other)
}
}
impl<'s> PartialOrd<String> for ScalarCow<'s> {
fn partial_cmp(&self, other: &String) -> Option<Ordering> {
let other = other.into();
scalar_cmp(self, &other)
}
}
impl ValueView for KString {
fn as_debug(&self) -> &dyn fmt::Debug {
self
}
fn render(&self) -> DisplayCow<'_> {
DisplayCow::Borrowed(self)
}
fn source(&self) -> DisplayCow<'_> {
DisplayCow::Owned(Box::new(StrSource { s: self.as_str() }))
}
fn type_name(&self) -> &'static str {
ValueView::type_name(&self.as_str())
}
fn query_state(&self, state: State) -> bool {
ValueView::query_state(&self.as_str(), state)
}
fn to_kstr(&self) -> KStringCow<'_> {
self.as_ref().into()
}
fn to_value(&self) -> Value {
Value::scalar(Scalar::new(self.clone()))
}
fn as_scalar(&self) -> Option<ScalarCow<'_>> {
Some(ScalarCow::new(self))
}
}
impl<'s> From<KString> for ScalarCow<'s> {
fn from(s: KString) -> Self {
ScalarCow {
0: ScalarCowEnum::Str(s.into()),
}
}
}
impl<'s> From<&'s KString> for ScalarCow<'s> {
fn from(s: &'s KString) -> Self {
ScalarCow {
0: ScalarCowEnum::Str(s.as_ref().into()),
}
}
}
impl<'s> PartialEq<KString> for ScalarCow<'s> {
fn eq(&self, other: &KString) -> bool {
let other = other.into();
scalar_eq(self, &other)
}
}
impl<'s> PartialOrd<KString> for ScalarCow<'s> {
fn partial_cmp(&self, other: &KString) -> Option<Ordering> {
let other = other.into();
scalar_cmp(self, &other)
}
}
impl<'s> ValueView for KStringCow<'s> {
fn as_debug(&self) -> &dyn fmt::Debug {
self
}
fn render(&self) -> DisplayCow<'_> {
DisplayCow::Borrowed(self)
}
fn source(&self) -> DisplayCow<'_> {
DisplayCow::Owned(Box::new(StrSource { s: self.as_str() }))
}
fn type_name(&self) -> &'static str {
ValueView::type_name(&self.as_str())
}
fn query_state(&self, state: State) -> bool {
ValueView::query_state(&self.as_str(), state)
}
fn to_kstr(&self) -> KStringCow<'_> {
self.clone()
}
fn to_value(&self) -> Value {
Value::scalar(Scalar::new(self.clone().into_owned()))
}
fn as_scalar(&self) -> Option<ScalarCow<'_>> {
Some(ScalarCow::new(self))
}
}
impl<'s> From<KStringCow<'s>> for ScalarCow<'s> {
fn from(s: KStringCow<'s>) -> Self {
ScalarCow {
0: ScalarCowEnum::Str(s),
}
}
}
impl<'s> From<&'s KStringCow<'s>> for ScalarCow<'s> {
fn from(s: &'s KStringCow<'s>) -> Self {
ScalarCow {
0: ScalarCowEnum::Str(s.clone()),
}
}
}
impl<'s> PartialEq<KStringCow<'s>> for ScalarCow<'s> {
fn eq(&self, other: &KStringCow<'s>) -> bool {
let other = other.into();
scalar_eq(self, &other)
}
}
impl<'s> PartialOrd<KStringCow<'s>> for ScalarCow<'s> {
fn partial_cmp(&self, other: &KStringCow<'s>) -> Option<Ordering> {
let other = other.into();
scalar_cmp(self, &other)
}
}
impl<'s> ValueView for KStringRef<'s> {
fn as_debug(&self) -> &dyn fmt::Debug {
self
}
fn render(&self) -> DisplayCow<'_> {
DisplayCow::Borrowed(self)
}
fn source(&self) -> DisplayCow<'_> {
DisplayCow::Owned(Box::new(StrSource { s: self.as_str() }))
}
fn type_name(&self) -> &'static str {
ValueView::type_name(&self.as_str())
}
fn query_state(&self, state: State) -> bool {
ValueView::query_state(&self.as_str(), state)
}
fn to_kstr(&self) -> KStringCow<'_> {
self.clone().into()
}
fn to_value(&self) -> Value {
Value::scalar(Scalar::new(self.to_owned()))
}
fn as_scalar(&self) -> Option<ScalarCow<'_>> {
Some(ScalarCow::new(self))
}
}
impl<'s> From<KStringRef<'s>> for ScalarCow<'s> {
fn from(s: KStringRef<'s>) -> Self {
ScalarCow {
0: ScalarCowEnum::Str(s.into()),
}
}
}
impl<'s> From<&'s KStringRef<'s>> for ScalarCow<'s> {
fn from(s: &'s KStringRef<'s>) -> Self {
ScalarCow {
0: ScalarCowEnum::Str(s.into()),
}
}
}
impl<'s> PartialEq<KStringRef<'s>> for ScalarCow<'s> {
fn eq(&self, other: &KStringRef<'s>) -> bool {
let other = other.into();
scalar_eq(self, &other)
}
}
impl<'s> PartialOrd<KStringRef<'s>> for ScalarCow<'s> {
fn partial_cmp(&self, other: &KStringRef<'s>) -> Option<Ordering> {
let other = other.into();
scalar_cmp(self, &other)
}
}
impl<'s> Eq for ScalarCow<'s> {}
fn scalar_eq<'s>(lhs: &ScalarCow<'s>, rhs: &ScalarCow<'s>) -> bool {
match (&lhs.0, &rhs.0) {
(&ScalarCowEnum::Integer(x), &ScalarCowEnum::Integer(y)) => x == y,
(&ScalarCowEnum::Integer(x), &ScalarCowEnum::Float(y)) => (x as f64) == y,
(&ScalarCowEnum::Float(x), &ScalarCowEnum::Integer(y)) => x == (y as f64),
(&ScalarCowEnum::Float(x), &ScalarCowEnum::Float(y)) => x == y,
(&ScalarCowEnum::Bool(x), &ScalarCowEnum::Bool(y)) => x == y,
(&ScalarCowEnum::DateTime(x), &ScalarCowEnum::DateTime(y)) => x == y,
(&ScalarCowEnum::Date(x), &ScalarCowEnum::Date(y)) => x == y,
(&ScalarCowEnum::DateTime(x), &ScalarCowEnum::Date(y)) => x == x.with_date(y),
(&ScalarCowEnum::Date(x), &ScalarCowEnum::DateTime(y)) => y.with_date(x) == y,
(&ScalarCowEnum::Str(ref x), &ScalarCowEnum::Str(ref y)) => x == y,
(_, &ScalarCowEnum::Bool(b)) | (&ScalarCowEnum::Bool(b), _) => b,
_ => false,
}
}
fn scalar_cmp<'s>(lhs: &ScalarCow<'s>, rhs: &ScalarCow<'s>) -> Option<Ordering> {
match (&lhs.0, &rhs.0) {
(&ScalarCowEnum::Integer(x), &ScalarCowEnum::Integer(y)) => x.partial_cmp(&y),
(&ScalarCowEnum::Integer(x), &ScalarCowEnum::Float(y)) => (x as f64).partial_cmp(&y),
(&ScalarCowEnum::Float(x), &ScalarCowEnum::Integer(y)) => x.partial_cmp(&(y as f64)),
(&ScalarCowEnum::Float(x), &ScalarCowEnum::Float(y)) => x.partial_cmp(&y),
(&ScalarCowEnum::Bool(x), &ScalarCowEnum::Bool(y)) => x.partial_cmp(&y),
(&ScalarCowEnum::DateTime(x), &ScalarCowEnum::DateTime(y)) => x.partial_cmp(&y),
(&ScalarCowEnum::Date(x), &ScalarCowEnum::Date(y)) => x.partial_cmp(&y),
(&ScalarCowEnum::DateTime(x), &ScalarCowEnum::Date(y)) => x.partial_cmp(&x.with_date(y)),
(&ScalarCowEnum::Date(x), &ScalarCowEnum::DateTime(y)) => y.with_date(x).partial_cmp(&y),
(&ScalarCowEnum::Str(ref x), &ScalarCowEnum::Str(ref y)) => x.partial_cmp(y),
_ => None,
}
}
#[cfg(test)]
mod test {
use super::*;
static TRUE: ScalarCow<'_> = ScalarCow(ScalarCowEnum::Bool(true));
static FALSE: ScalarCow<'_> = ScalarCow(ScalarCowEnum::Bool(false));
#[test]
fn test_to_str_bool() {
assert_eq!(TRUE.to_kstr(), "true");
}
#[test]
fn test_to_str_integer() {
let val: ScalarCow<'_> = 42i64.into();
assert_eq!(val.to_kstr(), "42");
}
#[test]
fn test_to_str_float() {
let val: ScalarCow<'_> = 42f64.into();
assert_eq!(val.to_kstr(), "42");
let val: ScalarCow<'_> = 42.34.into();
assert_eq!(val.to_kstr(), "42.34");
}
#[test]
fn test_to_str_str() {
let val: ScalarCow<'_> = "foobar".into();
assert_eq!(val.to_kstr(), "foobar");
}
#[test]
fn test_to_integer_bool() {
assert_eq!(TRUE.to_integer(), None);
}
#[test]
fn test_to_integer_integer() {
let val: ScalarCow<'_> = 42i64.into();
assert_eq!(val.to_integer(), Some(42i64));
}
#[test]
fn test_to_integer_float() {
let val: ScalarCow<'_> = 42f64.into();
assert_eq!(val.to_integer(), None);
let val: ScalarCow<'_> = 42.34.into();
assert_eq!(val.to_integer(), None);
}
#[test]
fn test_to_integer_str() {
let val: ScalarCow<'_> = "foobar".into();
assert_eq!(val.to_integer(), None);
let val: ScalarCow<'_> = "42.34".into();
assert_eq!(val.to_integer(), None);
let val: ScalarCow<'_> = "42".into();
assert_eq!(val.to_integer(), Some(42));
}
#[test]
fn test_to_float_bool() {
assert_eq!(TRUE.to_float(), None);
}
#[test]
fn test_to_float_integer() {
let val: ScalarCow<'_> = 42i64.into();
assert_eq!(val.to_float(), Some(42f64));
}
#[test]
fn test_to_float_float() {
let val: ScalarCow<'_> = 42f64.into();
assert_eq!(val.to_float(), Some(42f64));
let val: ScalarCow<'_> = 42.34.into();
assert_eq!(val.to_float(), Some(42.34));
}
#[test]
fn test_to_float_str() {
let val: ScalarCow<'_> = "foobar".into();
assert_eq!(val.to_float(), None);
let val: ScalarCow<'_> = "42.34".into();
assert_eq!(val.to_float(), Some(42.34));
let val: ScalarCow<'_> = "42".into();
assert_eq!(val.to_float(), Some(42f64));
}
#[test]
fn test_to_bool_bool() {
assert_eq!(TRUE.to_bool(), Some(true));
}
#[test]
fn test_to_bool_integer() {
let val: ScalarCow<'_> = 42i64.into();
assert_eq!(val.to_bool(), None);
}
#[test]
fn test_to_bool_float() {
let val: ScalarCow<'_> = 42f64.into();
assert_eq!(val.to_bool(), None);
let val: ScalarCow<'_> = 42.34.into();
assert_eq!(val.to_bool(), None);
}
#[test]
fn test_to_bool_str() {
let val: ScalarCow<'_> = "foobar".into();
assert_eq!(val.to_bool(), None);
let val: ScalarCow<'_> = "true".into();
assert_eq!(val.to_bool(), None);
let val: ScalarCow<'_> = "false".into();
assert_eq!(val.to_bool(), None);
}
#[test]
fn integer_equality() {
let val: ScalarCow<'_> = 42i64.into();
let zero: ScalarCow<'_> = 0i64.into();
assert_eq!(val, val);
assert_eq!(zero, zero);
assert!(val != zero);
assert!(zero != val);
}
#[test]
fn integers_have_ruby_truthiness() {
let val: ScalarCow<'_> = 42i64.into();
let zero: ScalarCow<'_> = 0i64.into();
assert_eq!(TRUE, val);
assert_eq!(val, TRUE);
assert!(val.query_state(State::Truthy));
assert_eq!(TRUE, zero);
assert_eq!(zero, TRUE);
assert!(zero.query_state(State::Truthy));
}
#[test]
fn float_equality() {
let val: ScalarCow<'_> = 42f64.into();
let zero: ScalarCow<'_> = 0f64.into();
assert_eq!(val, val);
assert_eq!(zero, zero);
assert!(val != zero);
assert!(zero != val);
}
#[test]
fn floats_have_ruby_truthiness() {
let val: ScalarCow<'_> = 42f64.into();
let zero: ScalarCow<'_> = 0f64.into();
assert_eq!(TRUE, val);
assert_eq!(val, TRUE);
assert!(val.query_state(State::Truthy));
assert_eq!(TRUE, zero);
assert_eq!(zero, TRUE);
assert!(zero.query_state(State::Truthy));
}
#[test]
fn boolean_equality() {
assert_eq!(TRUE, TRUE);
assert_eq!(FALSE, FALSE);
assert!(FALSE != TRUE);
assert!(TRUE != FALSE);
}
#[test]
fn booleans_have_ruby_truthiness() {
assert!(TRUE.query_state(State::Truthy));
assert!(!FALSE.query_state(State::Truthy));
}
#[test]
fn string_equality() {
let alpha: ScalarCow<'_> = "alpha".into();
let beta: ScalarCow<'_> = "beta".into();
let empty: ScalarCow<'_> = "".into();
assert_eq!(alpha, alpha);
assert_eq!(empty, empty);
assert!(alpha != beta);
assert!(beta != alpha);
}
#[test]
fn strings_have_ruby_truthiness() {
let alpha: ScalarCow<'_> = "alpha".into();
let empty: ScalarCow<'_> = "".into();
assert_eq!(TRUE, alpha);
assert_eq!(alpha, TRUE);
assert!(alpha.query_state(State::Truthy));
assert_eq!(TRUE, empty);
assert_eq!(empty, TRUE);
assert!(empty.query_state(State::Truthy));
}
#[test]
fn borrows_from_scalar_cow() {
fn is_borrowed(cow: Cow<'_, str>) -> bool {
match cow {
Cow::Borrowed(_) => true,
Cow::Owned(_) => false,
}
}
let s: String = "gamma".into();
let sc: ScalarCow<'_> = s.into();
{
fn extract_cow_str<'s>(value: &'s dyn ValueView) -> Cow<'s, str> {
value.to_kstr().into_cow_str()
}
assert_eq!(is_borrowed(extract_cow_str(sc.as_view())), false);
}
{
fn extract_cow_str<'s>(value: &'s dyn ValueView) -> Cow<'s, str> {
value.as_scalar().unwrap().into_cow_str()
}
assert_eq!(is_borrowed(extract_cow_str(&sc)), true);
}
}
}