1extern crate chrono;
12extern crate enumset;
13extern crate indexmap;
14extern crate ordered_float;
15#[macro_use]
16extern crate serde_derive;
17extern crate bytes;
18extern crate edn;
19extern crate uuid;
20#[macro_use]
21extern crate lazy_static;
22
23use std::fmt;
24
25use std::ffi::CString;
26
27use std::ops::Deref;
28
29use std::os::raw::c_char;
30
31use std::rc::Rc;
32
33use std::sync::Arc;
34
35use std::collections::BTreeMap;
36
37use bytes::Bytes;
38use indexmap::IndexMap;
39
40use enumset::{EnumSet, EnumSetType};
41
42use ordered_float::OrderedFloat;
43
44use chrono::{DateTime, Timelike};
45
46use uuid::Uuid;
47
48use edn::{Cloned, FromMicros, FromRc, Keyword, Utc, ValueRc};
49
50use edn::entities::{
51 AttributePlace, EntidOrIdent, EntityPlace, TransactableValueMarker, ValuePlace,
52};
53
54mod value_type_set;
55pub mod values;
56
57pub use crate::value_type_set::ValueTypeSet;
58
59#[macro_export]
60macro_rules! bail {
61 ($e:expr) => {
62 return Err($e.into());
63 };
64}
65
66pub type Entid = i64;
72
73#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
76pub struct KnownEntid(pub Entid);
77
78impl From<KnownEntid> for Entid {
79 fn from(k: KnownEntid) -> Entid {
80 k.0
81 }
82}
83
84impl<V: TransactableValueMarker> From<KnownEntid> for EntityPlace<V> {
85 fn from(value: KnownEntid) -> Self {
86 Self::Entid(EntidOrIdent::Entid(value.0))
87 }
88}
89
90impl From<KnownEntid> for AttributePlace {
91 fn from(value: KnownEntid) -> Self {
92 Self::Entid(EntidOrIdent::Entid(value.0))
93 }
94}
95
96impl<V: TransactableValueMarker> From<KnownEntid> for ValuePlace<V> {
97 fn from(value: KnownEntid) -> Self {
98 Self::Entid(EntidOrIdent::Entid(value.0))
99 }
100}
101
102pub enum AttributeBitFlags {
107 IndexAVET = 1,
108 IndexVAET = 1 << 1,
109 IndexFulltext = 1 << 2,
110 UniqueValue = 1 << 3,
111}
112
113pub mod attribute {
114 use crate::TypedValue;
115
116 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
117 pub enum Unique {
118 Value,
119 Identity,
120 }
121
122 impl Unique {
123 pub fn into_typed_value(self) -> TypedValue {
125 match self {
126 Unique::Value => TypedValue::typed_ns_keyword("db.unique", "value"),
127 Unique::Identity => TypedValue::typed_ns_keyword("db.unique", "identity"),
128 }
129 }
130 }
131}
132
133#[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
138pub struct Attribute {
139 pub value_type: ValueType,
141
142 pub multival: bool,
146
147 pub unique: Option<attribute::Unique>,
163
164 pub index: bool,
166
167 pub fulltext: bool,
171
172 pub component: bool,
179
180 pub no_history: bool,
182}
183
184impl Attribute {
185 pub fn flags(&self) -> u8 {
187 let mut flags: u8 = 0;
188
189 if self.index {
190 flags |= AttributeBitFlags::IndexAVET as u8;
191 }
192 if self.value_type == ValueType::Ref {
193 flags |= AttributeBitFlags::IndexVAET as u8;
194 }
195 if self.fulltext {
196 flags |= AttributeBitFlags::IndexFulltext as u8;
197 }
198 if self.unique.is_some() {
199 flags |= AttributeBitFlags::UniqueValue as u8;
200 }
201 flags
202 }
203
204 pub fn to_edn_value(&self, ident: Option<Keyword>) -> edn::Value {
205 let mut attribute_map: BTreeMap<edn::Value, edn::Value> = BTreeMap::default();
206 if let Some(ident) = ident {
207 attribute_map.insert(values::DB_IDENT.clone(), edn::Value::Keyword(ident));
208 }
209
210 attribute_map.insert(
211 values::DB_VALUE_TYPE.clone(),
212 self.value_type.into_edn_value(),
213 );
214
215 attribute_map.insert(
216 values::DB_CARDINALITY.clone(),
217 if self.multival {
218 values::DB_CARDINALITY_MANY.clone()
219 } else {
220 values::DB_CARDINALITY_ONE.clone()
221 },
222 );
223
224 match self.unique {
225 Some(attribute::Unique::Value) => {
226 attribute_map.insert(values::DB_UNIQUE.clone(), values::DB_UNIQUE_VALUE.clone());
227 }
228 Some(attribute::Unique::Identity) => {
229 attribute_map.insert(
230 values::DB_UNIQUE.clone(),
231 values::DB_UNIQUE_IDENTITY.clone(),
232 );
233 }
234 None => (),
235 }
236
237 if self.index {
238 attribute_map.insert(values::DB_INDEX.clone(), edn::Value::Boolean(true));
239 }
240
241 if self.fulltext {
242 attribute_map.insert(values::DB_FULLTEXT.clone(), edn::Value::Boolean(true));
243 }
244
245 if self.component {
246 attribute_map.insert(values::DB_IS_COMPONENT.clone(), edn::Value::Boolean(true));
247 }
248
249 if self.no_history {
250 attribute_map.insert(values::DB_NO_HISTORY.clone(), edn::Value::Boolean(true));
251 }
252
253 edn::Value::Map(attribute_map)
254 }
255}
256
257impl Default for Attribute {
258 fn default() -> Attribute {
259 Attribute {
260 value_type: ValueType::Ref,
262 fulltext: false,
263 index: false,
264 multival: false,
265 unique: None,
266 component: false,
267 no_history: false,
268 }
269 }
270}
271
272#[derive(EnumSetType, Debug, Hash, Ord, PartialOrd)]
275#[repr(u32)]
276pub enum ValueType {
277 Ref,
278 Boolean,
279 Instant,
280 Long,
281 Double,
282 String,
283 Keyword,
284 Uuid,
285 Bytes,
286}
287
288impl ValueType {
289 pub fn all_enums() -> EnumSet<ValueType> {
290 let mut s = EnumSet::new();
292 s.insert(ValueType::Ref);
293 s.insert(ValueType::Boolean);
294 s.insert(ValueType::Instant);
295 s.insert(ValueType::Long);
296 s.insert(ValueType::Double);
297 s.insert(ValueType::String);
298 s.insert(ValueType::Keyword);
299 s.insert(ValueType::Uuid);
300 s.insert(ValueType::Bytes);
301 s
302 }
303}
304
305impl ValueType {
306 pub fn into_keyword(self) -> Keyword {
307 Keyword::namespaced(
308 "db.type",
309 match self {
310 ValueType::Ref => "ref",
311 ValueType::Boolean => "boolean",
312 ValueType::Instant => "instant",
313 ValueType::Long => "long",
314 ValueType::Double => "double",
315 ValueType::String => "string",
316 ValueType::Keyword => "keyword",
317 ValueType::Uuid => "uuid",
318 ValueType::Bytes => "bytes",
319 },
320 )
321 }
322
323 pub fn from_keyword(keyword: &Keyword) -> Option<Self> {
324 if keyword.namespace() != Some("db.type") {
325 None
326 } else {
327 match keyword.name() {
328 "ref" => Some(ValueType::Ref),
329 "boolean" => Some(ValueType::Boolean),
330 "instant" => Some(ValueType::Instant),
331 "long" => Some(ValueType::Long),
332 "double" => Some(ValueType::Double),
333 "string" => Some(ValueType::String),
334 "keyword" => Some(ValueType::Keyword),
335 "uuid" => Some(ValueType::Uuid),
336 "bytes" => Some(ValueType::Bytes),
337 _ => None,
338 }
339 }
340 }
341
342 pub fn into_typed_value(self) -> TypedValue {
343 TypedValue::typed_ns_keyword(
344 "db.type",
345 match self {
346 ValueType::Ref => "ref",
347 ValueType::Boolean => "boolean",
348 ValueType::Instant => "instant",
349 ValueType::Long => "long",
350 ValueType::Double => "double",
351 ValueType::String => "string",
352 ValueType::Keyword => "keyword",
353 ValueType::Uuid => "uuid",
354 ValueType::Bytes => "bytes",
355 },
356 )
357 }
358
359 pub fn into_edn_value(self) -> edn::Value {
360 match self {
361 ValueType::Ref => values::DB_TYPE_REF.clone(),
362 ValueType::Boolean => values::DB_TYPE_BOOLEAN.clone(),
363 ValueType::Instant => values::DB_TYPE_INSTANT.clone(),
364 ValueType::Long => values::DB_TYPE_LONG.clone(),
365 ValueType::Double => values::DB_TYPE_DOUBLE.clone(),
366 ValueType::String => values::DB_TYPE_STRING.clone(),
367 ValueType::Keyword => values::DB_TYPE_KEYWORD.clone(),
368 ValueType::Uuid => values::DB_TYPE_UUID.clone(),
369 ValueType::Bytes => values::DB_TYPE_BYTES.clone(),
370 }
371 }
372
373 pub fn is_numeric(self) -> bool {
374 matches!(self, ValueType::Long | ValueType::Double)
375 }
376}
377
378impl fmt::Display for ValueType {
379 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
380 write!(
381 f,
382 "{}",
383 match *self {
384 ValueType::Ref => ":db.type/ref",
385 ValueType::Boolean => ":db.type/boolean",
386 ValueType::Instant => ":db.type/instant",
387 ValueType::Long => ":db.type/long",
388 ValueType::Double => ":db.type/double",
389 ValueType::String => ":db.type/string",
390 ValueType::Keyword => ":db.type/keyword",
391 ValueType::Uuid => ":db.type/uuid",
392 ValueType::Bytes => ":db.type/bytes",
393 }
394 )
395 }
396}
397
398impl TransactableValueMarker for TypedValue {}
400
401#[derive(Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq, Serialize, Deserialize)]
406pub enum TypedValue {
407 Ref(Entid),
408 Boolean(bool),
409 Long(i64),
410 Double(OrderedFloat<f64>),
411 Instant(DateTime<Utc>), String(ValueRc<String>),
414 Keyword(ValueRc<Keyword>),
415 Uuid(Uuid), Bytes(Bytes),
417}
418
419impl From<KnownEntid> for TypedValue {
420 fn from(k: KnownEntid) -> TypedValue {
421 TypedValue::Ref(k.0)
422 }
423}
424
425impl TypedValue {
426 #[inline]
429 pub fn is_congruent_with<T: Into<Option<ValueType>>>(&self, t: T) -> bool {
430 t.into().is_none_or(|x| self.matches_type(x))
431 }
432
433 #[inline]
434 pub fn matches_type(&self, t: ValueType) -> bool {
435 self.value_type() == t
436 }
437
438 pub fn value_type(&self) -> ValueType {
439 match self {
440 TypedValue::Ref(_) => ValueType::Ref,
441 TypedValue::Boolean(_) => ValueType::Boolean,
442 TypedValue::Long(_) => ValueType::Long,
443 TypedValue::Instant(_) => ValueType::Instant,
444 TypedValue::Double(_) => ValueType::Double,
445 TypedValue::String(_) => ValueType::String,
446 TypedValue::Keyword(_) => ValueType::Keyword,
447 TypedValue::Uuid(_) => ValueType::Uuid,
448 TypedValue::Bytes(_) => ValueType::Bytes,
449 }
450 }
451
452 pub fn typed_ns_keyword<S: AsRef<str>, T: AsRef<str>>(ns: S, name: T) -> TypedValue {
456 Keyword::namespaced(ns.as_ref(), name.as_ref()).into()
457 }
458
459 pub fn typed_string<S: AsRef<str>>(s: S) -> TypedValue {
463 s.as_ref().into()
464 }
465
466 pub fn current_instant() -> TypedValue {
467 Utc::now().into()
468 }
469
470 pub fn instant(micros: i64) -> TypedValue {
473 DateTime::<Utc>::from_micros(micros).into()
474 }
475
476 pub fn into_known_entid(self) -> Option<KnownEntid> {
477 match self {
478 TypedValue::Ref(v) => Some(KnownEntid(v)),
479 _ => None,
480 }
481 }
482
483 pub fn into_entid(self) -> Option<Entid> {
484 match self {
485 TypedValue::Ref(v) => Some(v),
486 _ => None,
487 }
488 }
489
490 pub fn into_kw(self) -> Option<ValueRc<Keyword>> {
491 match self {
492 TypedValue::Keyword(v) => Some(v),
493 _ => None,
494 }
495 }
496
497 pub fn into_boolean(self) -> Option<bool> {
498 match self {
499 TypedValue::Boolean(v) => Some(v),
500 _ => None,
501 }
502 }
503
504 pub fn into_long(self) -> Option<i64> {
505 match self {
506 TypedValue::Long(v) => Some(v),
507 _ => None,
508 }
509 }
510
511 pub fn into_double(self) -> Option<f64> {
512 match self {
513 TypedValue::Double(v) => Some(v.into_inner()),
514 _ => None,
515 }
516 }
517
518 pub fn into_instant(self) -> Option<DateTime<Utc>> {
519 match self {
520 TypedValue::Instant(v) => Some(v),
521 _ => None,
522 }
523 }
524
525 pub fn into_timestamp(self) -> Option<i64> {
526 match self {
527 TypedValue::Instant(v) => Some(v.timestamp()),
528 _ => None,
529 }
530 }
531
532 pub fn into_string(self) -> Option<ValueRc<String>> {
533 match self {
534 TypedValue::String(v) => Some(v),
535 _ => None,
536 }
537 }
538
539 pub fn into_c_string(self) -> Option<*mut c_char> {
540 match self {
541 TypedValue::String(v) => {
542 let s: String = v.cloned();
544
545 let c: CString = CString::new(s).expect("String conversion failed!");
547
548 Some(c.into_raw())
550 }
551 _ => None,
552 }
553 }
554
555 pub fn into_kw_c_string(self) -> Option<*mut c_char> {
556 match self {
557 TypedValue::Keyword(v) => {
558 let s: String = v.to_string();
560
561 let c: CString = CString::new(s).expect("String conversion failed!");
563
564 Some(c.into_raw())
566 }
567 _ => None,
568 }
569 }
570
571 pub fn into_uuid_c_string(self) -> Option<*mut c_char> {
572 match self {
573 TypedValue::Uuid(v) => {
574 let s: String = v.hyphenated().to_string();
576
577 let c: CString = CString::new(s).expect("String conversion failed!");
579
580 Some(c.into_raw())
582 }
583 _ => None,
584 }
585 }
586
587 pub fn into_uuid(self) -> Option<Uuid> {
588 match self {
589 TypedValue::Uuid(v) => Some(v),
590 _ => None,
591 }
592 }
593
594 pub fn into_uuid_string(self) -> Option<String> {
595 match self {
596 TypedValue::Uuid(v) => Some(v.hyphenated().to_string()),
597 _ => None,
598 }
599 }
600
601 pub fn into_bytes(self) -> Option<Bytes> {
602 match self {
603 TypedValue::Bytes(b) => Some(b),
604 _ => None,
605 }
606 }
607}
608
609impl From<bool> for TypedValue {
612 fn from(value: bool) -> TypedValue {
613 TypedValue::Boolean(value)
614 }
615}
616
617impl From<DateTime<Utc>> for TypedValue {
620 fn from(value: DateTime<Utc>) -> TypedValue {
621 TypedValue::Instant(value.microsecond_precision())
622 }
623}
624
625impl From<Uuid> for TypedValue {
626 fn from(value: Uuid) -> TypedValue {
627 TypedValue::Uuid(value)
628 }
629}
630
631impl<'a> From<&'a str> for TypedValue {
632 fn from(value: &'a str) -> TypedValue {
633 TypedValue::String(ValueRc::new(value.to_string()))
634 }
635}
636
637impl From<Arc<String>> for TypedValue {
638 fn from(value: Arc<String>) -> TypedValue {
639 TypedValue::String(ValueRc::from_arc(value))
640 }
641}
642
643impl From<Rc<String>> for TypedValue {
644 fn from(value: Rc<String>) -> TypedValue {
645 TypedValue::String(ValueRc::from_rc(value))
646 }
647}
648
649impl From<Box<String>> for TypedValue {
650 fn from(value: Box<String>) -> TypedValue {
651 TypedValue::String(ValueRc::new(*value))
652 }
653}
654
655impl From<String> for TypedValue {
656 fn from(value: String) -> TypedValue {
657 TypedValue::String(ValueRc::new(value))
658 }
659}
660
661impl From<Arc<Keyword>> for TypedValue {
662 fn from(value: Arc<Keyword>) -> TypedValue {
663 TypedValue::Keyword(ValueRc::from_arc(value))
664 }
665}
666
667impl From<Rc<Keyword>> for TypedValue {
668 fn from(value: Rc<Keyword>) -> TypedValue {
669 TypedValue::Keyword(ValueRc::from_rc(value))
670 }
671}
672
673impl From<Keyword> for TypedValue {
674 fn from(value: Keyword) -> TypedValue {
675 TypedValue::Keyword(ValueRc::new(value))
676 }
677}
678
679impl From<u32> for TypedValue {
680 fn from(value: u32) -> TypedValue {
681 TypedValue::Long(value as i64)
682 }
683}
684
685impl From<i32> for TypedValue {
686 fn from(value: i32) -> TypedValue {
687 TypedValue::Long(value as i64)
688 }
689}
690
691impl From<f64> for TypedValue {
692 fn from(value: f64) -> TypedValue {
693 TypedValue::Double(OrderedFloat(value))
694 }
695}
696
697impl From<&[u8]> for TypedValue {
698 fn from(bslice: &[u8]) -> Self {
699 TypedValue::Bytes(Bytes::copy_from_slice(bslice))
700 }
701}
702
703trait MicrosecondPrecision {
704 fn microsecond_precision(self) -> Self;
706}
707
708impl MicrosecondPrecision for DateTime<Utc> {
709 fn microsecond_precision(self) -> DateTime<Utc> {
710 let nanoseconds = self.nanosecond();
711 if nanoseconds.is_multiple_of(1000) {
712 return self;
713 }
714 let microseconds = nanoseconds / 1000;
715 let truncated = microseconds * 1000;
716 #[expect(
717 clippy::expect_used,
718 reason = "timestamp truncation to microseconds should always produce valid values"
719 )]
720 self.with_nanosecond(truncated).expect("valid timestamp")
721 }
722}
723
724#[derive(Clone, Debug, Eq, PartialEq)]
737pub enum Binding {
738 Scalar(TypedValue),
739 Vec(ValueRc<Vec<Binding>>),
740 Map(ValueRc<StructuredMap>),
741}
742
743impl<T> From<T> for Binding
744where
745 T: Into<TypedValue>,
746{
747 fn from(value: T) -> Self {
748 Binding::Scalar(value.into())
749 }
750}
751
752impl From<StructuredMap> for Binding {
753 fn from(value: StructuredMap) -> Self {
754 Binding::Map(ValueRc::new(value))
755 }
756}
757
758impl From<Vec<Binding>> for Binding {
759 fn from(value: Vec<Binding>) -> Self {
760 Binding::Vec(ValueRc::new(value))
761 }
762}
763
764impl Binding {
765 pub fn into_scalar(self) -> Option<TypedValue> {
766 match self {
767 Binding::Scalar(v) => Some(v),
768 _ => None,
769 }
770 }
771
772 pub fn into_vec(self) -> Option<ValueRc<Vec<Binding>>> {
773 match self {
774 Binding::Vec(v) => Some(v),
775 _ => None,
776 }
777 }
778
779 pub fn into_map(self) -> Option<ValueRc<StructuredMap>> {
780 match self {
781 Binding::Map(v) => Some(v),
782 _ => None,
783 }
784 }
785
786 pub fn as_scalar(&self) -> Option<&TypedValue> {
787 match self {
788 Binding::Scalar(ref v) => Some(v),
789 _ => None,
790 }
791 }
792
793 pub fn as_vec(&self) -> Option<&Vec<Binding>> {
794 match self {
795 Binding::Vec(ref v) => Some(v),
796 _ => None,
797 }
798 }
799
800 pub fn as_map(&self) -> Option<&StructuredMap> {
801 match self {
802 Binding::Map(ref v) => Some(v),
803 _ => None,
804 }
805 }
806}
807
808#[derive(Clone, Debug, Default, Eq, PartialEq)]
819pub struct StructuredMap(pub IndexMap<ValueRc<Keyword>, Binding>);
820
821impl Deref for StructuredMap {
822 type Target = IndexMap<ValueRc<Keyword>, Binding>;
823
824 fn deref(&self) -> &Self::Target {
825 &self.0
826 }
827}
828
829impl StructuredMap {
830 pub fn insert<N, B>(&mut self, name: N, value: B)
831 where
832 N: Into<ValueRc<Keyword>>,
833 B: Into<Binding>,
834 {
835 self.0.insert(name.into(), value.into());
836 }
837}
838
839impl From<IndexMap<ValueRc<Keyword>, Binding>> for StructuredMap {
840 fn from(src: IndexMap<ValueRc<Keyword>, Binding>) -> Self {
841 StructuredMap(src)
842 }
843}
844
845impl<T> From<Vec<(Keyword, T)>> for StructuredMap
847where
848 T: Into<Binding>,
849{
850 fn from(value: Vec<(Keyword, T)>) -> Self {
851 let mut sm = StructuredMap::default();
852 for (k, v) in value.into_iter() {
853 sm.insert(k, v);
854 }
855 sm
856 }
857}
858
859impl Binding {
860 #[inline]
863 pub fn is_congruent_with<T: Into<Option<ValueType>>>(&self, t: T) -> bool {
864 t.into().is_none_or(|x| self.matches_type(x))
865 }
866
867 #[inline]
868 pub fn matches_type(&self, t: ValueType) -> bool {
869 self.value_type() == Some(t)
870 }
871
872 pub fn value_type(&self) -> Option<ValueType> {
873 match self {
874 Binding::Scalar(ref v) => Some(v.value_type()),
875
876 Binding::Map(_) => None,
877 Binding::Vec(_) => None,
878 }
879 }
880}
881
882pub fn now() -> DateTime<Utc> {
884 Utc::now().microsecond_precision()
885}
886
887impl Binding {
888 pub fn into_known_entid(self) -> Option<KnownEntid> {
889 match self {
890 Binding::Scalar(TypedValue::Ref(v)) => Some(KnownEntid(v)),
891 _ => None,
892 }
893 }
894
895 pub fn into_entid(self) -> Option<Entid> {
896 match self {
897 Binding::Scalar(TypedValue::Ref(v)) => Some(v),
898 _ => None,
899 }
900 }
901
902 pub fn into_kw(self) -> Option<ValueRc<Keyword>> {
903 match self {
904 Binding::Scalar(TypedValue::Keyword(v)) => Some(v),
905 _ => None,
906 }
907 }
908
909 pub fn into_boolean(self) -> Option<bool> {
910 match self {
911 Binding::Scalar(TypedValue::Boolean(v)) => Some(v),
912 _ => None,
913 }
914 }
915
916 pub fn into_long(self) -> Option<i64> {
917 match self {
918 Binding::Scalar(TypedValue::Long(v)) => Some(v),
919 _ => None,
920 }
921 }
922
923 pub fn into_double(self) -> Option<f64> {
924 match self {
925 Binding::Scalar(TypedValue::Double(v)) => Some(v.into_inner()),
926 _ => None,
927 }
928 }
929
930 pub fn into_instant(self) -> Option<DateTime<Utc>> {
931 match self {
932 Binding::Scalar(TypedValue::Instant(v)) => Some(v),
933 _ => None,
934 }
935 }
936
937 pub fn into_timestamp(self) -> Option<i64> {
938 match self {
939 Binding::Scalar(TypedValue::Instant(v)) => Some(v.timestamp()),
940 _ => None,
941 }
942 }
943
944 pub fn into_string(self) -> Option<ValueRc<String>> {
945 match self {
946 Binding::Scalar(TypedValue::String(v)) => Some(v),
947 _ => None,
948 }
949 }
950
951 pub fn into_uuid(self) -> Option<Uuid> {
952 match self {
953 Binding::Scalar(TypedValue::Uuid(v)) => Some(v),
954 _ => None,
955 }
956 }
957
958 pub fn into_uuid_string(self) -> Option<String> {
959 match self {
960 Binding::Scalar(TypedValue::Uuid(v)) => Some(v.hyphenated().to_string()),
961 _ => None,
962 }
963 }
964
965 pub fn into_c_string(self) -> Option<*mut c_char> {
966 match self {
967 Binding::Scalar(v) => v.into_c_string(),
968 _ => None,
969 }
970 }
971
972 pub fn into_kw_c_string(self) -> Option<*mut c_char> {
973 match self {
974 Binding::Scalar(v) => v.into_kw_c_string(),
975 _ => None,
976 }
977 }
978
979 pub fn into_uuid_c_string(self) -> Option<*mut c_char> {
980 match self {
981 Binding::Scalar(v) => v.into_uuid_c_string(),
982 _ => None,
983 }
984 }
985
986 pub fn as_entid(&self) -> Option<&Entid> {
987 match self {
988 Binding::Scalar(TypedValue::Ref(ref v)) => Some(v),
989 _ => None,
990 }
991 }
992
993 pub fn as_kw(&self) -> Option<&ValueRc<Keyword>> {
994 match self {
995 Binding::Scalar(TypedValue::Keyword(ref v)) => Some(v),
996 _ => None,
997 }
998 }
999
1000 pub fn as_boolean(&self) -> Option<&bool> {
1001 match self {
1002 Binding::Scalar(TypedValue::Boolean(ref v)) => Some(v),
1003 _ => None,
1004 }
1005 }
1006
1007 pub fn as_long(&self) -> Option<&i64> {
1008 match self {
1009 Binding::Scalar(TypedValue::Long(ref v)) => Some(v),
1010 _ => None,
1011 }
1012 }
1013
1014 pub fn as_double(&self) -> Option<&f64> {
1015 match self {
1016 Binding::Scalar(TypedValue::Double(ref v)) => Some(&v.0),
1017 _ => None,
1018 }
1019 }
1020
1021 pub fn as_instant(&self) -> Option<&DateTime<Utc>> {
1022 match self {
1023 Binding::Scalar(TypedValue::Instant(ref v)) => Some(v),
1024 _ => None,
1025 }
1026 }
1027
1028 pub fn as_string(&self) -> Option<&ValueRc<String>> {
1029 match self {
1030 Binding::Scalar(TypedValue::String(ref v)) => Some(v),
1031 _ => None,
1032 }
1033 }
1034
1035 pub fn as_uuid(&self) -> Option<&Uuid> {
1036 match self {
1037 Binding::Scalar(TypedValue::Uuid(ref v)) => Some(v),
1038 _ => None,
1039 }
1040 }
1041}
1042
1043#[test]
1044fn test_typed_value() {
1045 assert!(TypedValue::Boolean(false).is_congruent_with(None));
1046 assert!(TypedValue::Boolean(false).is_congruent_with(ValueType::Boolean));
1047 assert!(!TypedValue::typed_string("foo").is_congruent_with(ValueType::Boolean));
1048 assert!(TypedValue::typed_string("foo").is_congruent_with(ValueType::String));
1049 assert!(TypedValue::typed_string("foo").is_congruent_with(None));
1050}
1051
1052#[cfg(test)]
1053mod tests {
1054 use super::*;
1055
1056 #[test]
1057 fn test_attribute_flags() {
1058 let attr1 = Attribute {
1059 index: true,
1060 value_type: ValueType::Ref,
1061 fulltext: false,
1062 unique: None,
1063 multival: false,
1064 component: false,
1065 no_history: false,
1066 };
1067
1068 assert!(attr1.flags() & AttributeBitFlags::IndexAVET as u8 != 0);
1069 assert!(attr1.flags() & AttributeBitFlags::IndexVAET as u8 != 0);
1070 assert!(attr1.flags() & AttributeBitFlags::IndexFulltext as u8 == 0);
1071 assert!(attr1.flags() & AttributeBitFlags::UniqueValue as u8 == 0);
1072
1073 let attr2 = Attribute {
1074 index: false,
1075 value_type: ValueType::Boolean,
1076 fulltext: true,
1077 unique: Some(attribute::Unique::Value),
1078 multival: false,
1079 component: false,
1080 no_history: false,
1081 };
1082
1083 assert!(attr2.flags() & AttributeBitFlags::IndexAVET as u8 == 0);
1084 assert!(attr2.flags() & AttributeBitFlags::IndexVAET as u8 == 0);
1085 assert!(attr2.flags() & AttributeBitFlags::IndexFulltext as u8 != 0);
1086 assert!(attr2.flags() & AttributeBitFlags::UniqueValue as u8 != 0);
1087
1088 let attr3 = Attribute {
1089 index: false,
1090 value_type: ValueType::Boolean,
1091 fulltext: true,
1092 unique: Some(attribute::Unique::Identity),
1093 multival: false,
1094 component: false,
1095 no_history: false,
1096 };
1097
1098 assert!(attr3.flags() & AttributeBitFlags::IndexAVET as u8 == 0);
1099 assert!(attr3.flags() & AttributeBitFlags::IndexVAET as u8 == 0);
1100 assert!(attr3.flags() & AttributeBitFlags::IndexFulltext as u8 != 0);
1101 assert!(attr3.flags() & AttributeBitFlags::UniqueValue as u8 != 0);
1102 }
1103}