1#![allow(clippy::eq_op)]
4
5mod date;
6mod datetime;
7pub(crate) mod ser;
8
9use std::cmp::Ordering;
10use std::{borrow::Cow, fmt};
11
12use crate::model::KString;
13use crate::model::KStringCow;
14use crate::model::KStringRef;
15
16use crate::model::value::{DisplayCow, State};
17use crate::model::{Value, ValueView};
18
19pub use date::*;
20pub use datetime::*;
21pub use ser::to_scalar;
22
23#[derive(Clone, serde::Serialize, serde::Deserialize)]
25#[serde(transparent)]
26#[repr(transparent)]
27pub struct ScalarCow<'s>(ScalarCowEnum<'s>);
28
29pub type Scalar = ScalarCow<'static>;
31
32#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
34#[serde(untagged)]
35enum ScalarCowEnum<'s> {
36 Integer(i64),
37 Float(f64),
38 Bool(bool),
39 DateTime(DateTime),
40 Date(Date),
41 Str(KStringCow<'s>),
42}
43
44impl<'s> ScalarCow<'s> {
45 pub fn new<T: Into<Self>>(value: T) -> Self {
47 value.into()
48 }
49
50 pub fn into_owned(self) -> Scalar {
52 match self.0 {
53 ScalarCowEnum::Integer(x) => Scalar::new(x),
54 ScalarCowEnum::Float(x) => Scalar::new(x),
55 ScalarCowEnum::Bool(x) => Scalar::new(x),
56 ScalarCowEnum::DateTime(x) => Scalar::new(x),
57 ScalarCowEnum::Date(x) => Scalar::new(x),
58 ScalarCowEnum::Str(x) => Scalar::new(x.into_owned()),
59 }
60 }
61
62 pub fn as_ref<'r: 's>(&'r self) -> ScalarCow<'r> {
64 match self.0 {
65 ScalarCowEnum::Integer(x) => ScalarCow::new(x),
66 ScalarCowEnum::Float(x) => ScalarCow::new(x),
67 ScalarCowEnum::Bool(x) => ScalarCow::new(x),
68 ScalarCowEnum::DateTime(x) => ScalarCow::new(x),
69 ScalarCowEnum::Date(x) => ScalarCow::new(x),
70 ScalarCowEnum::Str(ref x) => ScalarCow::new(x.as_ref()),
71 }
72 }
73
74 pub fn as_view<'r: 's>(&'r self) -> &'s dyn ValueView {
76 match self.0 {
77 ScalarCowEnum::Integer(ref x) => x,
78 ScalarCowEnum::Float(ref x) => x,
79 ScalarCowEnum::Bool(ref x) => x,
80 ScalarCowEnum::DateTime(ref x) => x,
81 ScalarCowEnum::Date(ref x) => x,
82 ScalarCowEnum::Str(ref x) => x,
83 }
84 }
85
86 pub fn into_string(self) -> KString {
88 match self.0 {
89 ScalarCowEnum::Integer(x) => x.to_string().into(),
90 ScalarCowEnum::Float(x) => x.to_string().into(),
91 ScalarCowEnum::Bool(x) => x.to_string().into(),
92 ScalarCowEnum::DateTime(x) => x.to_string().into(),
93 ScalarCowEnum::Date(x) => x.to_string().into(),
94 ScalarCowEnum::Str(x) => x.into_owned(),
95 }
96 }
97
98 pub fn to_integer(&self) -> Option<i64> {
100 match self.0 {
101 ScalarCowEnum::Integer(ref x) => Some(*x),
102 ScalarCowEnum::Str(ref x) => x.parse::<i64>().ok(),
103 _ => None,
104 }
105 }
106
107 pub fn to_float(&self) -> Option<f64> {
109 match self.0 {
110 ScalarCowEnum::Integer(ref x) => Some(*x as f64),
111 ScalarCowEnum::Float(ref x) => Some(*x),
112 ScalarCowEnum::Str(ref x) => x.parse::<f64>().ok(),
113 _ => None,
114 }
115 }
116
117 pub fn to_bool(&self) -> Option<bool> {
119 match self.0 {
120 ScalarCowEnum::Bool(ref x) => Some(*x),
121 _ => None,
122 }
123 }
124
125 pub fn to_date_time(&self) -> Option<DateTime> {
127 match self.0 {
128 ScalarCowEnum::DateTime(ref x) => Some(*x),
129 ScalarCowEnum::Str(ref x) => DateTime::from_str(x.as_str()),
130 _ => None,
131 }
132 }
133
134 pub fn to_date(&self) -> Option<Date> {
136 match self.0 {
137 ScalarCowEnum::DateTime(ref x) => Some(x.date()),
138 ScalarCowEnum::Date(ref x) => Some(*x),
139 ScalarCowEnum::Str(ref x) => Date::from_str(x.as_str()),
140 _ => None,
141 }
142 }
143
144 pub fn into_cow_str(self) -> Cow<'s, str> {
146 match self {
147 Self(ScalarCowEnum::Str(x)) => x.into_cow_str(),
148 other => other.into_string().into_cow_str(),
149 }
150 }
151}
152
153impl<'s> fmt::Debug for ScalarCow<'s> {
154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155 fmt::Debug::fmt(&self.0, f)
156 }
157}
158
159impl<'s> ValueView for ScalarCow<'s> {
160 fn as_debug(&self) -> &dyn fmt::Debug {
161 self
162 }
163
164 fn render(&self) -> DisplayCow<'_> {
165 self.as_view().render()
166 }
167 fn source(&self) -> DisplayCow<'_> {
168 self.as_view().source()
169 }
170 fn type_name(&self) -> &'static str {
171 self.as_view().type_name()
172 }
173 fn query_state(&self, state: State) -> bool {
174 self.as_view().query_state(state)
175 }
176
177 fn to_kstr(&self) -> KStringCow<'_> {
178 self.as_view().to_kstr()
179 }
180 fn to_value(&self) -> Value {
181 self.as_view().to_value()
182 }
183
184 fn as_scalar(&self) -> Option<ScalarCow<'_>> {
185 Some(self.as_ref())
186 }
187}
188
189impl<'s> PartialEq<ScalarCow<'s>> for ScalarCow<'s> {
190 fn eq(&self, other: &Self) -> bool {
191 scalar_eq(self, other)
192 }
193}
194
195impl<'s> PartialOrd<ScalarCow<'s>> for ScalarCow<'s> {
196 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
197 scalar_cmp(self, other)
198 }
199}
200
201impl ValueView for i64 {
202 fn as_debug(&self) -> &dyn fmt::Debug {
203 self
204 }
205
206 fn render(&self) -> DisplayCow<'_> {
207 DisplayCow::Borrowed(self)
208 }
209 fn source(&self) -> DisplayCow<'_> {
210 DisplayCow::Borrowed(self)
211 }
212 fn type_name(&self) -> &'static str {
213 "whole number"
214 }
215 fn query_state(&self, state: State) -> bool {
216 match state {
217 State::Truthy => true,
218 State::DefaultValue => false,
219 State::Empty => false,
220 State::Blank => false,
221 }
222 }
223
224 fn to_kstr(&self) -> KStringCow<'_> {
225 self.render().to_string().into()
226 }
227 fn to_value(&self) -> Value {
228 Value::scalar(*self)
229 }
230
231 fn as_scalar(&self) -> Option<ScalarCow<'_>> {
232 Some(ScalarCow::new(*self))
233 }
234}
235
236impl<'s> From<i64> for ScalarCow<'s> {
237 fn from(s: i64) -> Self {
238 ScalarCow(ScalarCowEnum::Integer(s))
239 }
240}
241
242impl<'s> PartialEq<i64> for ScalarCow<'s> {
243 fn eq(&self, other: &i64) -> bool {
244 let other = (*other).into();
245 scalar_eq(self, &other)
246 }
247}
248
249impl<'s> PartialOrd<i64> for ScalarCow<'s> {
250 fn partial_cmp(&self, other: &i64) -> Option<Ordering> {
251 let other = (*other).into();
252 scalar_cmp(self, &other)
253 }
254}
255
256macro_rules! impl_copyable {
257 ($user: ty, $internal: ty) => {
258 impl ValueView for $user {
259 fn as_debug(&self) -> &dyn fmt::Debug {
260 self
261 }
262
263 fn render(&self) -> DisplayCow<'_> {
264 DisplayCow::Borrowed(self)
265 }
266 fn source(&self) -> DisplayCow<'_> {
267 DisplayCow::Borrowed(self)
268 }
269 fn type_name(&self) -> &'static str {
270 <$internal>::from(*self).type_name()
271 }
272 fn query_state(&self, state: State) -> bool {
273 <$internal>::from(*self).query_state(state)
274 }
275
276 fn to_kstr(&self) -> KStringCow<'_> {
277 self.render().to_string().into()
278 }
279 fn to_value(&self) -> Value {
280 <$internal>::from(*self).to_value()
281 }
282
283 fn as_scalar(&self) -> Option<ScalarCow<'_>> {
284 Some(ScalarCow::new(<$internal>::from(*self)))
285 }
286 }
287
288 impl<'s> From<$user> for ScalarCow<'s> {
289 fn from(s: $user) -> Self {
290 ScalarCow::from(<$internal>::from(s))
291 }
292 }
293
294 impl<'s> PartialEq<$user> for ScalarCow<'s> {
295 fn eq(&self, other: &$user) -> bool {
296 let other = <$internal>::from(*other).into();
297 scalar_eq(self, &other)
298 }
299 }
300
301 impl<'s> PartialOrd<$user> for ScalarCow<'s> {
302 fn partial_cmp(&self, other: &$user) -> Option<Ordering> {
303 let other = <$internal>::from(*other).into();
304 scalar_cmp(self, &other)
305 }
306 }
307 };
308}
309
310impl_copyable!(u8, i64);
311impl_copyable!(i8, i64);
312impl_copyable!(u16, i64);
313impl_copyable!(i16, i64);
314impl_copyable!(u32, i64);
315impl_copyable!(i32, i64);
316
317impl ValueView for f64 {
318 fn as_debug(&self) -> &dyn fmt::Debug {
319 self
320 }
321
322 fn render(&self) -> DisplayCow<'_> {
323 DisplayCow::Borrowed(self)
324 }
325 fn source(&self) -> DisplayCow<'_> {
326 DisplayCow::Borrowed(self)
327 }
328 fn type_name(&self) -> &'static str {
329 "fractional number"
330 }
331 fn query_state(&self, state: State) -> bool {
332 match state {
333 State::Truthy => true,
334 State::DefaultValue => false,
335 State::Empty => false,
336 State::Blank => false,
337 }
338 }
339
340 fn to_kstr(&self) -> KStringCow<'_> {
341 self.render().to_string().into()
342 }
343 fn to_value(&self) -> Value {
344 Value::scalar(*self)
345 }
346
347 fn as_scalar(&self) -> Option<ScalarCow<'_>> {
348 Some(ScalarCow::new(*self))
349 }
350}
351
352impl<'s> From<f64> for ScalarCow<'s> {
353 fn from(s: f64) -> Self {
354 ScalarCow(ScalarCowEnum::Float(s))
355 }
356}
357
358impl<'s> PartialEq<f64> for ScalarCow<'s> {
359 fn eq(&self, other: &f64) -> bool {
360 let other = (*other).into();
361 scalar_eq(self, &other)
362 }
363}
364
365impl<'s> PartialOrd<f64> for ScalarCow<'s> {
366 fn partial_cmp(&self, other: &f64) -> Option<Ordering> {
367 let other = (*other).into();
368 scalar_cmp(self, &other)
369 }
370}
371
372impl_copyable!(f32, f64);
373
374impl ValueView for bool {
375 fn as_debug(&self) -> &dyn fmt::Debug {
376 self
377 }
378
379 fn render(&self) -> DisplayCow<'_> {
380 DisplayCow::Borrowed(self)
381 }
382 fn source(&self) -> DisplayCow<'_> {
383 DisplayCow::Borrowed(self)
384 }
385 fn type_name(&self) -> &'static str {
386 "boolean"
387 }
388 fn query_state(&self, state: State) -> bool {
389 match state {
390 State::Truthy => *self,
391 State::DefaultValue => !self,
392 State::Empty => false,
393 State::Blank => !self,
394 }
395 }
396
397 fn to_kstr(&self) -> KStringCow<'_> {
398 self.render().to_string().into()
399 }
400 fn to_value(&self) -> Value {
401 Value::scalar(*self)
402 }
403
404 fn as_scalar(&self) -> Option<ScalarCow<'_>> {
405 Some(ScalarCow::new(*self))
406 }
407}
408
409impl<'s> From<bool> for ScalarCow<'s> {
410 fn from(s: bool) -> Self {
411 ScalarCow(ScalarCowEnum::Bool(s))
412 }
413}
414
415impl<'s> PartialEq<bool> for ScalarCow<'s> {
416 fn eq(&self, other: &bool) -> bool {
417 let other = (*other).into();
418 scalar_eq(self, &other)
419 }
420}
421
422impl<'s> PartialOrd<bool> for ScalarCow<'s> {
423 fn partial_cmp(&self, other: &bool) -> Option<Ordering> {
424 let other = (*other).into();
425 scalar_cmp(self, &other)
426 }
427}
428
429impl ValueView for DateTime {
430 fn as_debug(&self) -> &dyn fmt::Debug {
431 self
432 }
433
434 fn render(&self) -> DisplayCow<'_> {
435 DisplayCow::Borrowed(self)
436 }
437 fn source(&self) -> DisplayCow<'_> {
438 DisplayCow::Borrowed(self)
439 }
440 fn type_name(&self) -> &'static str {
441 "date time"
442 }
443 fn query_state(&self, state: State) -> bool {
444 match state {
445 State::Truthy => true,
446 State::DefaultValue => false,
447 State::Empty => false,
448 State::Blank => false,
449 }
450 }
451
452 fn to_kstr(&self) -> KStringCow<'_> {
453 self.render().to_string().into()
454 }
455 fn to_value(&self) -> Value {
456 Value::scalar(*self)
457 }
458
459 fn as_scalar(&self) -> Option<ScalarCow<'_>> {
460 Some(ScalarCow::new(*self))
461 }
462}
463
464impl<'s> From<DateTime> for ScalarCow<'s> {
465 fn from(s: DateTime) -> Self {
466 ScalarCow(ScalarCowEnum::DateTime(s))
467 }
468}
469
470impl<'s> PartialEq<DateTime> for ScalarCow<'s> {
471 fn eq(&self, other: &DateTime) -> bool {
472 let other = (*other).into();
473 scalar_eq(self, &other)
474 }
475}
476
477impl<'s> PartialOrd<DateTime> for ScalarCow<'s> {
478 fn partial_cmp(&self, other: &DateTime) -> Option<Ordering> {
479 let other = (*other).into();
480 scalar_cmp(self, &other)
481 }
482}
483
484impl ValueView for Date {
485 fn as_debug(&self) -> &dyn fmt::Debug {
486 self
487 }
488
489 fn render(&self) -> DisplayCow<'_> {
490 DisplayCow::Borrowed(self)
491 }
492 fn source(&self) -> DisplayCow<'_> {
493 DisplayCow::Borrowed(self)
494 }
495 fn type_name(&self) -> &'static str {
496 "date"
497 }
498 fn query_state(&self, state: State) -> bool {
499 match state {
500 State::Truthy => true,
501 State::DefaultValue => false,
502 State::Empty => false,
503 State::Blank => false,
504 }
505 }
506
507 fn to_kstr(&self) -> KStringCow<'_> {
508 self.render().to_string().into()
509 }
510 fn to_value(&self) -> Value {
511 Value::scalar(*self)
512 }
513
514 fn as_scalar(&self) -> Option<ScalarCow<'_>> {
515 Some(ScalarCow::new(*self))
516 }
517}
518
519impl<'s> From<Date> for ScalarCow<'s> {
520 fn from(s: Date) -> Self {
521 ScalarCow(ScalarCowEnum::Date(s))
522 }
523}
524
525impl<'s> PartialEq<Date> for ScalarCow<'s> {
526 fn eq(&self, other: &Date) -> bool {
527 let other = (*other).into();
528 scalar_eq(self, &other)
529 }
530}
531
532impl<'s> PartialOrd<Date> for ScalarCow<'s> {
533 fn partial_cmp(&self, other: &Date) -> Option<Ordering> {
534 let other = (*other).into();
535 scalar_cmp(self, &other)
536 }
537}
538
539impl<'s> ValueView for &'s str {
540 fn as_debug(&self) -> &dyn fmt::Debug {
541 self
542 }
543
544 fn render(&self) -> DisplayCow<'_> {
545 DisplayCow::Borrowed(self)
546 }
547 fn source(&self) -> DisplayCow<'_> {
548 DisplayCow::Owned(Box::new(StrSource { s: self }))
549 }
550 fn type_name(&self) -> &'static str {
551 "string"
552 }
553 fn query_state(&self, state: State) -> bool {
554 match state {
555 State::Truthy => true,
556 State::DefaultValue => self.is_empty(),
557 State::Empty => self.is_empty(),
558 State::Blank => self.trim().is_empty(),
559 }
560 }
561
562 fn to_kstr(&self) -> KStringCow<'_> {
563 (*self).into()
564 }
565 fn to_value(&self) -> Value {
566 Value::scalar(ScalarCow::new(KString::from_ref(self)))
567 }
568
569 fn as_scalar(&self) -> Option<ScalarCow<'_>> {
570 Some(ScalarCow::new(*self))
571 }
572}
573
574struct StrSource<'s> {
575 s: &'s str,
576}
577
578impl<'s> fmt::Display for StrSource<'s> {
579 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
580 write!(f, r#""{}""#, self.s)
581 }
582}
583
584impl<'s> From<&'s str> for ScalarCow<'s> {
585 fn from(s: &'s str) -> Self {
586 ScalarCow(ScalarCowEnum::Str(s.into()))
587 }
588}
589
590impl<'s> PartialEq<str> for ScalarCow<'s> {
591 fn eq(&self, other: &str) -> bool {
592 let other = other.into();
593 scalar_eq(self, &other)
594 }
595}
596
597impl<'s> PartialEq<&'s str> for ScalarCow<'s> {
598 fn eq(&self, other: &&str) -> bool {
599 let other = (*other).into();
600 scalar_eq(self, &other)
601 }
602}
603
604impl<'s> PartialOrd<str> for ScalarCow<'s> {
605 fn partial_cmp(&self, other: &str) -> Option<Ordering> {
606 let other = other.into();
607 scalar_cmp(self, &other)
608 }
609}
610
611impl ValueView for String {
612 fn as_debug(&self) -> &dyn fmt::Debug {
613 self
614 }
615
616 fn render(&self) -> DisplayCow<'_> {
617 DisplayCow::Borrowed(self)
618 }
619 fn source(&self) -> DisplayCow<'_> {
620 DisplayCow::Owned(Box::new(StrSource { s: self.as_str() }))
621 }
622 fn type_name(&self) -> &'static str {
623 ValueView::type_name(&self.as_str())
624 }
625 fn query_state(&self, state: State) -> bool {
626 ValueView::query_state(&self.as_str(), state)
627 }
628
629 fn to_kstr(&self) -> KStringCow<'_> {
630 self.as_str().into()
631 }
632 fn to_value(&self) -> Value {
633 ValueView::to_value(&self.as_str())
634 }
635
636 fn as_scalar(&self) -> Option<ScalarCow<'_>> {
637 Some(ScalarCow::new(self.as_str()))
638 }
639}
640
641impl<'s> From<String> for ScalarCow<'s> {
642 fn from(s: String) -> Self {
643 ScalarCow(ScalarCowEnum::Str(s.into()))
644 }
645}
646
647impl<'s> From<&'s String> for ScalarCow<'s> {
648 fn from(s: &'s String) -> ScalarCow<'s> {
649 ScalarCow(ScalarCowEnum::Str(s.as_str().into()))
650 }
651}
652
653impl<'s> PartialEq<String> for ScalarCow<'s> {
654 fn eq(&self, other: &String) -> bool {
655 let other = other.into();
656 scalar_eq(self, &other)
657 }
658}
659
660impl<'s> PartialOrd<String> for ScalarCow<'s> {
661 fn partial_cmp(&self, other: &String) -> Option<Ordering> {
662 let other = other.into();
663 scalar_cmp(self, &other)
664 }
665}
666
667impl ValueView for KString {
668 fn as_debug(&self) -> &dyn fmt::Debug {
669 self
670 }
671
672 fn render(&self) -> DisplayCow<'_> {
673 DisplayCow::Borrowed(self)
674 }
675 fn source(&self) -> DisplayCow<'_> {
676 DisplayCow::Owned(Box::new(StrSource { s: self.as_str() }))
677 }
678 fn type_name(&self) -> &'static str {
679 ValueView::type_name(&self.as_str())
680 }
681 fn query_state(&self, state: State) -> bool {
682 ValueView::query_state(&self.as_str(), state)
683 }
684
685 fn to_kstr(&self) -> KStringCow<'_> {
686 self.as_ref().into()
687 }
688 fn to_value(&self) -> Value {
689 Value::scalar(Scalar::new(self.clone()))
690 }
691
692 fn as_scalar(&self) -> Option<ScalarCow<'_>> {
693 Some(ScalarCow::new(self))
694 }
695}
696
697impl<'s> From<KString> for ScalarCow<'s> {
698 fn from(s: KString) -> Self {
699 ScalarCow(ScalarCowEnum::Str(s.into()))
700 }
701}
702
703impl<'s> From<&'s KString> for ScalarCow<'s> {
704 fn from(s: &'s KString) -> Self {
705 ScalarCow(ScalarCowEnum::Str(s.as_ref().into()))
706 }
707}
708
709impl<'s> PartialEq<KString> for ScalarCow<'s> {
710 fn eq(&self, other: &KString) -> bool {
711 let other = other.into();
712 scalar_eq(self, &other)
713 }
714}
715
716impl<'s> PartialOrd<KString> for ScalarCow<'s> {
717 fn partial_cmp(&self, other: &KString) -> Option<Ordering> {
718 let other = other.into();
719 scalar_cmp(self, &other)
720 }
721}
722
723impl<'s> ValueView for KStringCow<'s> {
724 fn as_debug(&self) -> &dyn fmt::Debug {
725 self
726 }
727
728 fn render(&self) -> DisplayCow<'_> {
729 DisplayCow::Borrowed(self)
730 }
731 fn source(&self) -> DisplayCow<'_> {
732 DisplayCow::Owned(Box::new(StrSource { s: self.as_str() }))
733 }
734 fn type_name(&self) -> &'static str {
735 ValueView::type_name(&self.as_str())
736 }
737 fn query_state(&self, state: State) -> bool {
738 ValueView::query_state(&self.as_str(), state)
739 }
740
741 fn to_kstr(&self) -> KStringCow<'_> {
742 self.clone()
743 }
744 fn to_value(&self) -> Value {
745 Value::scalar(Scalar::new(self.clone().into_owned()))
746 }
747
748 fn as_scalar(&self) -> Option<ScalarCow<'_>> {
749 Some(ScalarCow::new(self))
750 }
751}
752
753impl<'s> From<KStringCow<'s>> for ScalarCow<'s> {
754 fn from(s: KStringCow<'s>) -> Self {
755 ScalarCow(ScalarCowEnum::Str(s))
756 }
757}
758
759impl<'s> From<&'s KStringCow<'s>> for ScalarCow<'s> {
760 fn from(s: &'s KStringCow<'s>) -> Self {
761 ScalarCow(ScalarCowEnum::Str(s.clone()))
762 }
763}
764
765impl<'s> PartialEq<KStringCow<'s>> for ScalarCow<'s> {
766 fn eq(&self, other: &KStringCow<'s>) -> bool {
767 let other = other.into();
768 scalar_eq(self, &other)
769 }
770}
771
772impl<'s> PartialOrd<KStringCow<'s>> for ScalarCow<'s> {
773 fn partial_cmp(&self, other: &KStringCow<'s>) -> Option<Ordering> {
774 let other = other.into();
775 scalar_cmp(self, &other)
776 }
777}
778
779impl<'s> ValueView for KStringRef<'s> {
780 fn as_debug(&self) -> &dyn fmt::Debug {
781 self
782 }
783
784 fn render(&self) -> DisplayCow<'_> {
785 DisplayCow::Borrowed(self)
786 }
787 fn source(&self) -> DisplayCow<'_> {
788 DisplayCow::Owned(Box::new(StrSource { s: self.as_str() }))
789 }
790 fn type_name(&self) -> &'static str {
791 ValueView::type_name(&self.as_str())
792 }
793 fn query_state(&self, state: State) -> bool {
794 ValueView::query_state(&self.as_str(), state)
795 }
796
797 fn to_kstr(&self) -> KStringCow<'_> {
798 self.into()
799 }
800 fn to_value(&self) -> Value {
801 Value::scalar(Scalar::new(self.to_owned()))
802 }
803
804 fn as_scalar(&self) -> Option<ScalarCow<'_>> {
805 Some(ScalarCow::new(self))
806 }
807}
808
809impl<'s> From<KStringRef<'s>> for ScalarCow<'s> {
810 fn from(s: KStringRef<'s>) -> Self {
811 ScalarCow(ScalarCowEnum::Str(s.into()))
812 }
813}
814
815impl<'s> From<&'s KStringRef<'s>> for ScalarCow<'s> {
816 fn from(s: &'s KStringRef<'s>) -> Self {
817 ScalarCow(ScalarCowEnum::Str(s.into()))
818 }
819}
820
821impl<'s> PartialEq<KStringRef<'s>> for ScalarCow<'s> {
822 fn eq(&self, other: &KStringRef<'s>) -> bool {
823 let other = other.into();
824 scalar_eq(self, &other)
825 }
826}
827
828impl<'s> PartialOrd<KStringRef<'s>> for ScalarCow<'s> {
829 fn partial_cmp(&self, other: &KStringRef<'s>) -> Option<Ordering> {
830 let other = other.into();
831 scalar_cmp(self, &other)
832 }
833}
834
835impl<'s> Eq for ScalarCow<'s> {}
836
837fn scalar_eq<'s>(lhs: &ScalarCow<'s>, rhs: &ScalarCow<'s>) -> bool {
838 match (&lhs.0, &rhs.0) {
839 (&ScalarCowEnum::Integer(x), &ScalarCowEnum::Integer(y)) => x == y,
840 (&ScalarCowEnum::Integer(x), &ScalarCowEnum::Float(y)) => (x as f64) == y,
841 (&ScalarCowEnum::Float(x), &ScalarCowEnum::Integer(y)) => x == (y as f64),
842 (&ScalarCowEnum::Float(x), &ScalarCowEnum::Float(y)) => x == y,
843 (&ScalarCowEnum::Bool(x), &ScalarCowEnum::Bool(y)) => x == y,
844 (&ScalarCowEnum::DateTime(x), &ScalarCowEnum::DateTime(y)) => x == y,
845 (&ScalarCowEnum::Date(x), &ScalarCowEnum::Date(y)) => x == y,
846 (&ScalarCowEnum::DateTime(x), &ScalarCowEnum::Date(y)) => x == x.with_date(y),
847 (&ScalarCowEnum::Date(x), &ScalarCowEnum::DateTime(y)) => y.with_date(x) == y,
848 (ScalarCowEnum::Str(x), ScalarCowEnum::Str(y)) => x == y,
849 (_, &ScalarCowEnum::Bool(b)) | (&ScalarCowEnum::Bool(b), _) => b,
851 _ => false,
852 }
853}
854
855fn scalar_cmp<'s>(lhs: &ScalarCow<'s>, rhs: &ScalarCow<'s>) -> Option<Ordering> {
856 match (&lhs.0, &rhs.0) {
857 (&ScalarCowEnum::Integer(x), &ScalarCowEnum::Integer(y)) => x.partial_cmp(&y),
858 (&ScalarCowEnum::Integer(x), &ScalarCowEnum::Float(y)) => (x as f64).partial_cmp(&y),
859 (&ScalarCowEnum::Float(x), &ScalarCowEnum::Integer(y)) => x.partial_cmp(&(y as f64)),
860 (&ScalarCowEnum::Float(x), &ScalarCowEnum::Float(y)) => x.partial_cmp(&y),
861 (&ScalarCowEnum::Bool(x), &ScalarCowEnum::Bool(y)) => x.partial_cmp(&y),
862 (&ScalarCowEnum::DateTime(x), &ScalarCowEnum::DateTime(y)) => x.partial_cmp(&y),
863 (&ScalarCowEnum::Date(x), &ScalarCowEnum::Date(y)) => x.partial_cmp(&y),
864 (&ScalarCowEnum::DateTime(x), &ScalarCowEnum::Date(y)) => x.partial_cmp(&x.with_date(y)),
865 (&ScalarCowEnum::Date(x), &ScalarCowEnum::DateTime(y)) => y.with_date(x).partial_cmp(&y),
866 (ScalarCowEnum::Str(x), ScalarCowEnum::Str(y)) => x.partial_cmp(y),
867 _ => None,
868 }
869}
870
871#[cfg(test)]
872mod test {
873 use super::*;
874
875 static TRUE: ScalarCow<'_> = ScalarCow(ScalarCowEnum::Bool(true));
876 static FALSE: ScalarCow<'_> = ScalarCow(ScalarCowEnum::Bool(false));
877
878 #[test]
879 fn test_to_str_bool() {
880 assert_eq!(TRUE.to_kstr(), "true");
881 }
882
883 #[test]
884 fn test_to_str_integer() {
885 let val: ScalarCow<'_> = 42i64.into();
886 assert_eq!(val.to_kstr(), "42");
887 }
888
889 #[test]
890 fn test_to_str_float() {
891 let val: ScalarCow<'_> = 42f64.into();
892 assert_eq!(val.to_kstr(), "42");
893
894 let val: ScalarCow<'_> = 42.34.into();
895 assert_eq!(val.to_kstr(), "42.34");
896 }
897
898 #[test]
899 fn test_to_str_str() {
900 let val: ScalarCow<'_> = "foobar".into();
901 assert_eq!(val.to_kstr(), "foobar");
902 }
903
904 #[test]
905 fn test_to_integer_bool() {
906 assert_eq!(TRUE.to_integer(), None);
907 }
908
909 #[test]
910 fn test_to_integer_integer() {
911 let val: ScalarCow<'_> = 42i64.into();
912 assert_eq!(val.to_integer(), Some(42i64));
913 }
914
915 #[test]
916 fn test_to_integer_float() {
917 let val: ScalarCow<'_> = 42f64.into();
918 assert_eq!(val.to_integer(), None);
919
920 let val: ScalarCow<'_> = 42.34.into();
921 assert_eq!(val.to_integer(), None);
922 }
923
924 #[test]
925 fn test_to_integer_str() {
926 let val: ScalarCow<'_> = "foobar".into();
927 assert_eq!(val.to_integer(), None);
928
929 let val: ScalarCow<'_> = "42.34".into();
930 assert_eq!(val.to_integer(), None);
931
932 let val: ScalarCow<'_> = "42".into();
933 assert_eq!(val.to_integer(), Some(42));
934 }
935
936 #[test]
937 fn test_to_float_bool() {
938 assert_eq!(TRUE.to_float(), None);
939 }
940
941 #[test]
942 fn test_to_float_integer() {
943 let val: ScalarCow<'_> = 42i64.into();
944 assert_eq!(val.to_float(), Some(42f64));
945 }
946
947 #[test]
948 fn test_to_float_float() {
949 let val: ScalarCow<'_> = 42f64.into();
950 assert_eq!(val.to_float(), Some(42f64));
951
952 let val: ScalarCow<'_> = 42.34.into();
953 assert_eq!(val.to_float(), Some(42.34));
954 }
955
956 #[test]
957 fn test_to_float_str() {
958 let val: ScalarCow<'_> = "foobar".into();
959 assert_eq!(val.to_float(), None);
960
961 let val: ScalarCow<'_> = "42.34".into();
962 assert_eq!(val.to_float(), Some(42.34));
963
964 let val: ScalarCow<'_> = "42".into();
965 assert_eq!(val.to_float(), Some(42f64));
966 }
967
968 #[test]
969 fn test_to_bool_bool() {
970 assert_eq!(TRUE.to_bool(), Some(true));
971 }
972
973 #[test]
974 fn test_to_bool_integer() {
975 let val: ScalarCow<'_> = 42i64.into();
976 assert_eq!(val.to_bool(), None);
977 }
978
979 #[test]
980 fn test_to_bool_float() {
981 let val: ScalarCow<'_> = 42f64.into();
982 assert_eq!(val.to_bool(), None);
983
984 let val: ScalarCow<'_> = 42.34.into();
985 assert_eq!(val.to_bool(), None);
986 }
987
988 #[test]
989 fn test_to_bool_str() {
990 let val: ScalarCow<'_> = "foobar".into();
991 assert_eq!(val.to_bool(), None);
992
993 let val: ScalarCow<'_> = "true".into();
994 assert_eq!(val.to_bool(), None);
995
996 let val: ScalarCow<'_> = "false".into();
997 assert_eq!(val.to_bool(), None);
998 }
999
1000 #[test]
1001 fn integer_equality() {
1002 let val: ScalarCow<'_> = 42i64.into();
1003 let zero: ScalarCow<'_> = 0i64.into();
1004 assert_eq!(val, val);
1005 assert_eq!(zero, zero);
1006 assert!(val != zero);
1007 assert!(zero != val);
1008 }
1009
1010 #[test]
1011 fn integers_have_ruby_truthiness() {
1012 let val: ScalarCow<'_> = 42i64.into();
1013 let zero: ScalarCow<'_> = 0i64.into();
1014 assert_eq!(TRUE, val);
1015 assert_eq!(val, TRUE);
1016 assert!(val.query_state(State::Truthy));
1017
1018 assert_eq!(TRUE, zero);
1019 assert_eq!(zero, TRUE);
1020 assert!(zero.query_state(State::Truthy));
1021 }
1022
1023 #[test]
1024 fn float_equality() {
1025 let val: ScalarCow<'_> = 42f64.into();
1026 let zero: ScalarCow<'_> = 0f64.into();
1027 assert_eq!(val, val);
1028 assert_eq!(zero, zero);
1029 assert!(val != zero);
1030 assert!(zero != val);
1031 }
1032
1033 #[test]
1034 fn floats_have_ruby_truthiness() {
1035 let val: ScalarCow<'_> = 42f64.into();
1036 let zero: ScalarCow<'_> = 0f64.into();
1037 assert_eq!(TRUE, val);
1038 assert_eq!(val, TRUE);
1039 assert!(val.query_state(State::Truthy));
1040
1041 assert_eq!(TRUE, zero);
1042 assert_eq!(zero, TRUE);
1043 assert!(zero.query_state(State::Truthy));
1044 }
1045
1046 #[test]
1047 fn boolean_equality() {
1048 assert_eq!(TRUE, TRUE);
1049 assert_eq!(FALSE, FALSE);
1050 assert!(FALSE != TRUE);
1051 assert!(TRUE != FALSE);
1052 }
1053
1054 #[test]
1055 fn booleans_have_ruby_truthiness() {
1056 assert!(TRUE.query_state(State::Truthy));
1057 assert!(!FALSE.query_state(State::Truthy));
1058 }
1059
1060 #[test]
1061 fn string_equality() {
1062 let alpha: ScalarCow<'_> = "alpha".into();
1063 let beta: ScalarCow<'_> = "beta".into();
1064 let empty: ScalarCow<'_> = "".into();
1065 assert_eq!(alpha, alpha);
1066 assert_eq!(empty, empty);
1067 assert!(alpha != beta);
1068 assert!(beta != alpha);
1069 }
1070
1071 #[test]
1072 fn strings_have_ruby_truthiness() {
1073 let alpha: ScalarCow<'_> = "alpha".into();
1075 let empty: ScalarCow<'_> = "".into();
1076 assert_eq!(TRUE, alpha);
1077 assert_eq!(alpha, TRUE);
1078 assert!(alpha.query_state(State::Truthy));
1079
1080 assert_eq!(TRUE, empty);
1081 assert_eq!(empty, TRUE);
1082 assert!(empty.query_state(State::Truthy));
1083 }
1084
1085 #[test]
1086 fn borrows_from_scalar_cow() {
1087 fn is_borrowed(cow: Cow<'_, str>) -> bool {
1088 match cow {
1089 Cow::Borrowed(_) => true,
1090 Cow::Owned(_) => false,
1091 }
1092 }
1093
1094 let s: String = "gamma".into();
1095 let sc: ScalarCow<'_> = s.into();
1096
1097 {
1099 fn extract_cow_str(value: &dyn ValueView) -> Cow<'_, str> {
1100 value.to_kstr().into_cow_str()
1101 }
1102 assert_eq!(is_borrowed(extract_cow_str(sc.as_view())), false);
1103 }
1104
1105 {
1107 fn extract_cow_str(value: &dyn ValueView) -> Cow<'_, str> {
1108 value.as_scalar().unwrap().into_cow_str()
1109 }
1110 assert_eq!(is_borrowed(extract_cow_str(&sc)), true);
1111 }
1112 }
1113}