Skip to main content

vitaminc_ore/
target.rs

1//! Targets a caller names when the program is compiled, and the tables
2//! that say what fits them.
3//!
4//! An order space declares the type every value in it is encoded as: its
5//! target. [`OrderTarget`] names one while the program runs, as an index
6//! layer that reads its column types from a schema must. The zero-sized
7//! markers here name one when the program is compiled, so the compiler can
8//! check what goes in: [`FitsIn`] lists the conversions that never lose
9//! information, and [`OwnTarget`] gives a Rust type the target it is.
10//! Both are sealed tables, generated in this module, so no caller can add
11//! a conversion that might be refused or infer a target from a value.
12//!
13//! The same method takes either: [`OrderEncrypt::target`] is generic over
14//! [`Target`], which every marker and [`OrderTarget`] implement.
15//!
16//! A space can also place nulls first or last, and the policy follows the
17//! target. On a fixed-width marker it is a marker too, [`First`] or
18//! [`Last`], and the space's target becomes [`Nulls<T, P>`](Nulls): the
19//! compiler keeps a nulls-first term out of a nulls-last space's
20//! comparison, as it keeps an `I64` term out of an `I32` space's. On an
21//! [`OrderTarget`] it is a [`NullOrder`] chosen while the program runs,
22//! and the target becomes a [`RuntimeNulls`], whose terms carry their
23//! policy and compare as `None` with a term of the other.
24//!
25//! [`OrderEncrypt::target`]: crate::OrderEncrypt::target
26
27use core::fmt;
28use core::marker::PhantomData;
29
30use vitaminc_aead::{Bytes as RawBytes, Encrypt};
31
32use crate::{NullOrder, OrderScheme, OrderTarget};
33
34mod private {
35    /// Seals [`Target`](super::Target), [`FitsIn`](super::FitsIn) and
36    /// [`OwnTarget`](super::OwnTarget) to this crate.
37    pub trait Sealed {}
38}
39
40/// A target an order space can be opened with: one of the zero-sized
41/// markers in this module, named when the program is compiled, or an
42/// [`OrderTarget`], chosen while it runs.
43///
44/// Sealed: every target is one this crate encodes.
45pub trait Target: private::Sealed + Copy + fmt::Debug {
46    /// The target as the value every encoding is keyed by.
47    fn runtime(self) -> OrderTarget;
48
49    /// Where a space of this target places nulls: `None`, unless the
50    /// target is a [`Nulls`] or a [`RuntimeNulls`], which a space's
51    /// `nulls` method makes.
52    fn null_order(self) -> Option<NullOrder> {
53        None
54    }
55}
56
57/// A target known when the program is compiled: one of the markers in this
58/// module. What a space of such a target takes is checked by the compiler,
59/// through [`FitsIn`].
60pub trait StaticTarget: Target + Default {
61    /// The target this marker stands for.
62    const TARGET: OrderTarget;
63}
64
65/// A marker target of fixed width: every marker but [`Text`] and
66/// [`Bytes`]. Only these take a null policy, so
67/// `scheme.target(I32).nulls(Last)` compiles and
68/// `scheme.target(Text).nulls(Last)` does not.
69///
70/// Sealed: implemented for the thirteen fixed-width markers here.
71#[diagnostic::on_unimplemented(
72    message = "`{Self}` takes no null policy",
73    label = "not a fixed-width target",
74    note = "only a fixed-width target places nulls first or last: a text or bytes null already shows by its length, so placing it would hide nothing"
75)]
76pub trait FixedWidth: StaticTarget {}
77
78/// The null policy of a space whose target is named when the program is
79/// compiled: [`First`] or [`Last`], which a marker space's `nulls` method
80/// takes. The policy is then part of the space's type, as the target is.
81///
82/// Sealed: [`First`] and [`Last`] are the only policies.
83pub trait NullPolicy: private::Sealed + Copy + fmt::Debug + Default {
84    /// Where a space of this policy places nulls.
85    const ORDER: NullOrder;
86}
87
88/// Nulls sort below every value, as SQL's `NULLS FIRST`: the policy
89/// [`NullOrder::First`], named when the program is compiled.
90#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
91pub struct First;
92
93/// Nulls sort above every value, as SQL's `NULLS LAST`: the policy
94/// [`NullOrder::Last`], named when the program is compiled.
95#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
96pub struct Last;
97
98impl private::Sealed for First {}
99impl private::Sealed for Last {}
100
101impl NullPolicy for First {
102    const ORDER: NullOrder = NullOrder::First;
103}
104
105impl NullPolicy for Last {
106    const ORDER: NullOrder = NullOrder::Last;
107}
108
109/// A marker target in a space that places nulls first or last: the
110/// target `T` and the policy `P`, both part of the type. Made only by a
111/// marker space's `nulls` method, from a fixed-width target, so every
112/// `Nulls` names a domain label.
113///
114/// A space of a `Nulls` target is not a [`StaticTarget`] space, so it has
115/// no `encrypt`: the policy refuses the maximum of an integer or uuid
116/// target, so a value goes through `encrypt_checked`, which reports it.
117/// Terms of a `Nulls<I32, Last>` space do not compile against an `I32`
118/// space's comparison, nor against a `Nulls<I32, First>` space's.
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
120pub struct Nulls<T, P: NullPolicy> {
121    target: T,
122    policy: PhantomData<P>,
123}
124
125impl<T: FixedWidth, P: NullPolicy> Nulls<T, P> {
126    pub(crate) fn new(target: T) -> Self {
127        Self {
128            target,
129            policy: PhantomData,
130        }
131    }
132
133    /// The target the policy is set on.
134    pub fn target(self) -> T {
135        self.target
136    }
137
138    /// Where the space places nulls: `P`'s order.
139    pub fn null_order(self) -> NullOrder {
140        P::ORDER
141    }
142}
143
144impl<T: FixedWidth, P: NullPolicy> private::Sealed for Nulls<T, P> {}
145
146impl<T: FixedWidth, P: NullPolicy> Target for Nulls<T, P> {
147    fn runtime(self) -> OrderTarget {
148        self.target.runtime()
149    }
150
151    fn null_order(self) -> Option<NullOrder> {
152        Some(P::ORDER)
153    }
154}
155
156/// A scheme takes a target in a space that places nulls exactly when it
157/// takes the target: the policy changes no width.
158impl<S: Supports<T> + ?Sized, T: FixedWidth, P: NullPolicy> Supports<Nulls<T, P>> for S {
159    fn supports(target: Nulls<T, P>) -> bool {
160        <S as Supports<T>>::supports(target.target)
161    }
162}
163
164/// A target chosen while the program runs, in a space that places nulls
165/// first or last: the [`OrderTarget`] and its [`NullOrder`], both values.
166/// Made only by `nulls` on a space of an [`OrderTarget`], which refuses
167/// text and bytes, so every `RuntimeNulls` names a domain label.
168///
169/// This is for a layer that reads its column types and null policies from
170/// a schema while the program runs. Every term of such a space carries its
171/// policy, as it carries its target, so a nulls-first and a nulls-last
172/// term of one target compare as `None` rather than as noise.
173#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
174pub struct RuntimeNulls {
175    target: OrderTarget,
176    order: NullOrder,
177}
178
179impl RuntimeNulls {
180    pub(crate) fn new(target: OrderTarget, order: NullOrder) -> Self {
181        Self { target, order }
182    }
183
184    /// The target the policy is set on.
185    pub fn target(self) -> OrderTarget {
186        self.target
187    }
188
189    /// Where the space places nulls.
190    pub fn null_order(self) -> NullOrder {
191        self.order
192    }
193}
194
195impl private::Sealed for RuntimeNulls {}
196
197impl Target for RuntimeNulls {
198    fn runtime(self) -> OrderTarget {
199        self.target
200    }
201
202    fn null_order(self) -> Option<NullOrder> {
203        Some(self.order)
204    }
205}
206
207/// A scheme takes a target chosen while the program runs, in a space that
208/// places nulls, exactly when it takes the target.
209impl<S: Supports<OrderTarget> + ?Sized> Supports<RuntimeNulls> for S {
210    fn supports(target: RuntimeNulls) -> bool {
211        <S as Supports<OrderTarget>>::supports(target.target)
212    }
213}
214
215impl private::Sealed for OrderTarget {}
216
217impl Target for OrderTarget {
218    fn runtime(self) -> OrderTarget {
219        self
220    }
221}
222
223/// A value that always fits target `T`: the conversion loses nothing and
224/// the encoding refuses nothing, so [`OrderSpace::encrypt`] can take it
225/// without a value-refusal arm in its error.
226///
227/// A sealed table, one impl per conversion:
228///
229/// | Target | Takes |
230/// | --- | --- |
231/// | an integer target | every integer type whose whole range it holds, so `I32` takes `i8`, `i16`, `i32` and `u16` (a `u8` is not a scalar of the data model: `Vec<u8>` is bytes). There is no 8-bit target, so an `i8` fits `I16` and up: see [`OrderTarget`] |
232/// | `F64` | `f32`, `f64` |
233/// | `Bytes` | `&[u8]`, `Vec<u8>`, `[u8; N]`, [`Bytes`](vitaminc_aead::Bytes) |
234/// | `Date` | `chrono::NaiveDate` (feature `chrono`) |
235/// | `Timestamp` | `vitaminc_aead::Timestamp` (feature `chrono`) |
236/// | `Decimal` | `rust_decimal::Decimal` (feature `rust_decimal`) |
237/// | `Uuid` | `uuid::Uuid` (feature `uuid`) |
238///
239/// and a reference to any of them. What is not here can be refused: an
240/// `i64` may not fit `I32`, text may hold a code point Unicode 16 does not
241/// assign, and a `chrono::DateTime<Utc>` may be a leap second. Those go
242/// through [`OrderSpace::encrypt_checked`], which checks the value while
243/// the program runs.
244///
245/// [`OrderSpace::encrypt`]: crate::OrderSpace::encrypt
246/// [`OrderSpace::encrypt_checked`]: crate::OrderSpace::encrypt_checked
247#[diagnostic::on_unimplemented(
248    message = "`{Self}` is not a value that always fits `{T}`",
249    label = "does not always fit `{T}`",
250    note = "`encrypt` takes a value the encoding never refuses: a narrower integer, an `f32`, bytes, or a typed value such as a `NaiveDate`",
251    note = "a value the encoding can refuse (an integer that may be out of range, text, a `DateTime<Utc>`, or any other `Encrypt` value) goes through `encrypt_checked`, which checks it while the program runs"
252)]
253pub trait FitsIn<T: StaticTarget>: Encrypt + private::Sealed {}
254
255/// A Rust type's own target, for [`OrderEncrypt::encrypt`] and the other
256/// chains that name none: an `i64` is an `I64`, an `f32` an `F64`, a
257/// `&str` a `Text`.
258///
259/// Sealed, and implemented for the data model's own types only. A target
260/// is never inferred from a value: a JavaScript `BigInt` arrives as the
261/// narrowest integer that holds it, and inferring from the value would
262/// scatter one index across several domains. A newtype names its target
263/// with [`OrderEncrypt::target`]. An `i8` has no own target: an order
264/// term over 256 values reveals them (see [`OrderTarget`]), so an `i8`
265/// goes into a wider target it fits, by name:
266/// `scheme.target(I16).encrypt(value)`.
267///
268/// [`OrderEncrypt::encrypt`]: crate::OrderEncrypt::encrypt
269/// [`OrderEncrypt::target`]: crate::OrderEncrypt::target
270#[diagnostic::on_unimplemented(
271    message = "`{Self}` has no order target of its own",
272    label = "has no order target of its own",
273    note = "name the target: `scheme.target(I64).encrypt_checked(value)`",
274    note = "there is no 8-bit target: an order term over 256 values reveals them, so an `i8` goes into `I16` or wider by name (`scheme.target(I16).encrypt(value)`), or into an equality index"
275)]
276pub trait OwnTarget: Encrypt + private::Sealed {
277    /// The target this type is.
278    type Target: StaticTarget;
279}
280
281/// What a scheme takes: implemented by a scheme crate for every target
282/// its scheme encrypts, so that `scheme.target(Text)` on a fixed-width
283/// scheme fails to compile rather than returning
284/// [`OrderError::Unsupported`](crate::OrderError::Unsupported).
285///
286/// A scheme answers twice. `Supports<OrderTarget>` is required of every
287/// scheme (no space of any target opens without it), and its
288/// [`supports`](Self::supports) says which targets the scheme takes when
289/// one is chosen while the program runs. `Supports<I32>` and the other
290/// marker impls say the same when the target is named as the program is
291/// compiled. A scheme writes both at once with
292/// [`supports_targets!`](crate::supports_targets), from one list, so
293/// they cannot disagree; a scheme that takes every target writes
294/// [`supports_every_target!`](crate::supports_every_target). A space
295/// asks the runtime answer for every target it is opened with, and in a
296/// debug build asserts that a marker's answer agrees.
297///
298/// A scheme never answers for a target in a space that places nulls
299/// ([`Nulls`], [`RuntimeNulls`]): this crate answers for it, with the
300/// answer for the target
301/// the policy is set on, since the policy changes no width. Those impls
302/// cover every scheme, so a scheme cannot implement `Supports` for every
303/// `T: Target` at once; it lists its targets, as the macros do.
304#[diagnostic::on_unimplemented(
305    message = "`{Self}` has no order term for `{T}`",
306    label = "does not implement `Supports<{T}>`",
307    note = "a scheme lists the targets it takes with `vitaminc_ore::supports_targets!(Scheme; I32, Date)`, which answers for each marker and for `OrderTarget`; pick one it lists, or an `OrderTarget` chosen while the program runs"
308)]
309pub trait Supports<T: Target>: OrderScheme {
310    /// Whether the scheme takes terms of `target`. For a marker, `true`
311    /// (the impl exists); for an [`OrderTarget`], the scheme's list.
312    fn supports(target: T) -> bool;
313}
314
315/// Implement [`Supports`] for the targets a scheme takes, from one list:
316/// once for [`OrderTarget`], answering `true` for a listed target, and
317/// once per listed marker.
318///
319/// ```
320/// # use vitaminc_ore::{Context, OrderPlaintext, OrderScheme};
321/// # struct TenBytes;
322/// # impl OrderScheme for TenBytes {
323/// #     const NAME: &'static str = "ten-bytes";
324/// #     type Term = Vec<u8>;
325/// #     type Error = core::convert::Infallible;
326/// #     type Space = ();
327/// #     fn open(&self, _: vitaminc_ore::OrderTarget, _: &Context<'_>) -> Result<(), Self::Error> {
328/// #         Ok(())
329/// #     }
330/// #     fn encrypt_plaintext(&self, _: &(), p: &OrderPlaintext) -> Result<Vec<u8>, Self::Error> {
331/// #         use vitaminc_protected::Controlled;
332/// #         Ok(p.bytes().risky_ref().clone())
333/// #     }
334/// #     fn compare(a: &Vec<u8>, b: &Vec<u8>) -> Option<core::cmp::Ordering> { Some(a.cmp(b)) }
335/// # }
336/// // A fixed-width scheme over at most ten bytes.
337/// vitaminc_ore::supports_targets!(TenBytes; I16, U16, I32, U32, I64, U64, F64, Date);
338/// ```
339#[macro_export]
340macro_rules! supports_targets {
341    ($scheme:ty; $($marker:ident),* $(,)?) => {
342        impl $crate::Supports<$crate::OrderTarget> for $scheme {
343            fn supports(target: $crate::OrderTarget) -> bool {
344                #[allow(unreachable_patterns)]
345                match target {
346                    $($crate::OrderTarget::$marker => true,)*
347                    _ => false,
348                }
349            }
350        }
351        $(
352            impl $crate::Supports<$crate::target::$marker> for $scheme {
353                fn supports(_: $crate::target::$marker) -> bool {
354                    true
355                }
356            }
357        )*
358    };
359}
360
361/// Implement [`Supports`] for every target, for a scheme that takes them
362/// all, as the CLWW schemes do: [`supports_targets!`] with the full list.
363///
364/// ```
365/// # use vitaminc_ore::{Context, OrderPlaintext, OrderScheme};
366/// # struct Cllw;
367/// # impl OrderScheme for Cllw {
368/// #     const NAME: &'static str = "cllw";
369/// #     type Term = Vec<u8>;
370/// #     type Error = core::convert::Infallible;
371/// #     type Space = ();
372/// #     fn open(&self, _: vitaminc_ore::OrderTarget, _: &Context<'_>) -> Result<(), Self::Error> {
373/// #         Ok(())
374/// #     }
375/// #     fn encrypt_plaintext(&self, _: &(), p: &OrderPlaintext) -> Result<Vec<u8>, Self::Error> {
376/// #         use vitaminc_protected::Controlled;
377/// #         Ok(p.bytes().risky_ref().clone())
378/// #     }
379/// #     fn compare(a: &Vec<u8>, b: &Vec<u8>) -> Option<core::cmp::Ordering> { Some(a.cmp(b)) }
380/// # }
381/// vitaminc_ore::supports_every_target!(Cllw);
382/// ```
383#[macro_export]
384macro_rules! supports_every_target {
385    ($scheme:ty) => {
386        $crate::supports_targets!($scheme;
387            I16, U16, I32, U32, I64, U64, I128, U128,
388            F64, Date, Timestamp, Decimal, Text, Bytes, Uuid);
389    };
390}
391
392/// One marker per target, each a zero-sized `Copy` type that stands for
393/// its [`OrderTarget`] variant.
394macro_rules! markers {
395    ($($(#[$doc:meta])* $marker:ident),* $(,)?) => {
396        $(
397            $(#[$doc])*
398            #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
399            pub struct $marker;
400
401            impl private::Sealed for $marker {}
402
403            impl Target for $marker {
404                fn runtime(self) -> OrderTarget {
405                    OrderTarget::$marker
406                }
407            }
408
409            impl StaticTarget for $marker {
410                const TARGET: OrderTarget = OrderTarget::$marker;
411            }
412        )*
413    };
414}
415
416/// The fixed-width markers: every one but `Text` and `Bytes`.
417macro_rules! fixed_width {
418    ($($marker:ident),* $(,)?) => {
419        $(impl FixedWidth for $marker {})*
420    };
421}
422
423fixed_width!(I16, U16, I32, U32, I64, U64, I128, U128, F64, Date, Timestamp, Decimal, Uuid);
424
425markers! {
426    /// [`OrderTarget::I16`]. The narrowest integer target: an 8-bit one
427    /// would reveal its values, as [`OrderTarget`] explains.
428    I16,
429    /// [`OrderTarget::U16`].
430    U16,
431    /// [`OrderTarget::I32`].
432    I32,
433    /// [`OrderTarget::U32`].
434    U32,
435    /// [`OrderTarget::I64`].
436    I64,
437    /// [`OrderTarget::U64`].
438    U64,
439    /// [`OrderTarget::I128`].
440    I128,
441    /// [`OrderTarget::U128`].
442    U128,
443    /// [`OrderTarget::F64`].
444    F64,
445    /// [`OrderTarget::Date`].
446    Date,
447    /// [`OrderTarget::Timestamp`].
448    Timestamp,
449    /// [`OrderTarget::Decimal`].
450    Decimal,
451    /// [`OrderTarget::Text`].
452    Text,
453    /// [`OrderTarget::Bytes`].
454    Bytes,
455    /// [`OrderTarget::Uuid`].
456    Uuid,
457}
458
459/// Seal the value types the tables below name, by value and by reference.
460macro_rules! sealed {
461    ($($ty:ty),* $(,)?) => {
462        $(
463            impl private::Sealed for $ty {}
464            impl private::Sealed for &$ty {}
465        )*
466    };
467}
468
469/// `FitsIn` rows: each target, then every type that always fits it, by
470/// value and by reference.
471macro_rules! fits {
472    ($($target:ident: $($ty:ty),*;)*) => {
473        $($(
474            impl FitsIn<$target> for $ty {}
475            impl FitsIn<$target> for &$ty {}
476        )*)*
477    };
478}
479
480/// `OwnTarget` rows: a type and the target it is, by value and by
481/// reference.
482macro_rules! own {
483    ($($ty:ty => $target:ident),* $(,)?) => {
484        $(
485            impl OwnTarget for $ty {
486                type Target = $target;
487            }
488            impl OwnTarget for &$ty {
489                type Target = $target;
490            }
491        )*
492    };
493}
494
495sealed!(
496    i8,
497    i16,
498    u16,
499    i32,
500    u32,
501    i64,
502    u64,
503    i128,
504    u128,
505    f32,
506    f64,
507    str,
508    String,
509    [u8],
510    Vec<u8>,
511);
512
513impl private::Sealed for RawBytes<'_> {}
514impl private::Sealed for &RawBytes<'_> {}
515impl<const N: usize> private::Sealed for [u8; N] {}
516impl<const N: usize> private::Sealed for &[u8; N] {}
517
518// An integer target takes every integer type whose whole range it holds:
519// a signed target holds a narrower type of either sign, an unsigned
520// target only a narrower unsigned one. There is no `u8` row: a `u8` is
521// not a scalar of the data model (a `Vec<u8>` is bytes), so it has no
522// `Encrypt` impl to fit with.
523fits! {
524    I16: i8, i16;
525    U16: u16;
526    I32: i8, i16, i32, u16;
527    U32: u16, u32;
528    I64: i8, i16, i32, i64, u16, u32;
529    U64: u16, u32, u64;
530    I128: i8, i16, i32, i64, i128, u16, u32, u64;
531    U128: u16, u32, u64, u128;
532    F64: f32, f64;
533    Bytes: Vec<u8>;
534}
535
536impl FitsIn<Bytes> for &[u8] {}
537impl FitsIn<Bytes> for RawBytes<'_> {}
538impl FitsIn<Bytes> for &RawBytes<'_> {}
539impl<const N: usize> FitsIn<Bytes> for [u8; N] {}
540impl<const N: usize> FitsIn<Bytes> for &[u8; N] {}
541
542own! {
543    i16 => I16,
544    u16 => U16,
545    i32 => I32,
546    u32 => U32,
547    i64 => I64,
548    u64 => U64,
549    i128 => I128,
550    u128 => U128,
551    f32 => F64,
552    f64 => F64,
553    String => Text,
554    Vec<u8> => Bytes,
555}
556
557impl OwnTarget for &str {
558    type Target = Text;
559}
560impl OwnTarget for &[u8] {
561    type Target = Bytes;
562}
563impl OwnTarget for RawBytes<'_> {
564    type Target = Bytes;
565}
566impl OwnTarget for &RawBytes<'_> {
567    type Target = Bytes;
568}
569impl<const N: usize> OwnTarget for [u8; N] {
570    type Target = Bytes;
571}
572impl<const N: usize> OwnTarget for &[u8; N] {
573    type Target = Bytes;
574}
575
576// The typed values callers hold. Each is inside the range its encoding
577// takes for every value the type can hold: chrono's `NaiveDate` spans
578// exactly the day range `Logical::Date` admits, a `Timestamp` is never a
579// leap second and lies in chrono's range, and a `rust_decimal::Decimal`
580// has a 96-bit mantissa and a scale of at most 28, which is what the
581// decimal encoding takes. A `chrono::DateTime<Utc>` may be a leap second,
582// which has no count, so it is checked, not fitting.
583#[cfg(feature = "chrono")]
584mod chrono_rows {
585    use super::*;
586    use chrono::{DateTime, NaiveDate, Utc};
587    use vitaminc_aead::Timestamp as Instant;
588
589    impl private::Sealed for NaiveDate {}
590    impl private::Sealed for &NaiveDate {}
591    impl private::Sealed for DateTime<Utc> {}
592    impl private::Sealed for &DateTime<Utc> {}
593    impl private::Sealed for Instant {}
594    impl private::Sealed for &Instant {}
595
596    impl FitsIn<Date> for NaiveDate {}
597    impl FitsIn<Date> for &NaiveDate {}
598    impl FitsIn<Timestamp> for Instant {}
599    impl FitsIn<Timestamp> for &Instant {}
600
601    impl OwnTarget for NaiveDate {
602        type Target = Date;
603    }
604    impl OwnTarget for &NaiveDate {
605        type Target = Date;
606    }
607    impl OwnTarget for DateTime<Utc> {
608        type Target = Timestamp;
609    }
610    impl OwnTarget for &DateTime<Utc> {
611        type Target = Timestamp;
612    }
613    impl OwnTarget for Instant {
614        type Target = Timestamp;
615    }
616    impl OwnTarget for &Instant {
617        type Target = Timestamp;
618    }
619}
620
621#[cfg(feature = "rust_decimal")]
622mod decimal_rows {
623    use super::*;
624
625    impl private::Sealed for rust_decimal::Decimal {}
626    impl private::Sealed for &rust_decimal::Decimal {}
627    impl FitsIn<Decimal> for rust_decimal::Decimal {}
628    impl FitsIn<Decimal> for &rust_decimal::Decimal {}
629    impl OwnTarget for rust_decimal::Decimal {
630        type Target = Decimal;
631    }
632    impl OwnTarget for &rust_decimal::Decimal {
633        type Target = Decimal;
634    }
635}
636
637#[cfg(feature = "uuid")]
638mod uuid_rows {
639    use super::*;
640
641    impl private::Sealed for uuid::Uuid {}
642    impl private::Sealed for &uuid::Uuid {}
643    impl FitsIn<Uuid> for uuid::Uuid {}
644    impl FitsIn<Uuid> for &uuid::Uuid {}
645    impl OwnTarget for uuid::Uuid {
646        type Target = Uuid;
647    }
648    impl OwnTarget for &uuid::Uuid {
649        type Target = Uuid;
650    }
651}
652
653#[cfg(test)]
654mod tests {
655    use super::*;
656
657    #[test]
658    fn every_marker_stands_for_its_target_and_every_target_is_itself() {
659        fn check<T: StaticTarget>(expected: OrderTarget) {
660            assert_eq!(T::TARGET, expected);
661            assert_eq!(T::default().runtime(), expected);
662        }
663        check::<I16>(OrderTarget::I16);
664        check::<U16>(OrderTarget::U16);
665        check::<I32>(OrderTarget::I32);
666        check::<U32>(OrderTarget::U32);
667        check::<I64>(OrderTarget::I64);
668        check::<U64>(OrderTarget::U64);
669        check::<I128>(OrderTarget::I128);
670        check::<U128>(OrderTarget::U128);
671        check::<F64>(OrderTarget::F64);
672        check::<Date>(OrderTarget::Date);
673        check::<Timestamp>(OrderTarget::Timestamp);
674        check::<Decimal>(OrderTarget::Decimal);
675        check::<Text>(OrderTarget::Text);
676        check::<Bytes>(OrderTarget::Bytes);
677        check::<Uuid>(OrderTarget::Uuid);
678        for target in OrderTarget::ALL {
679            assert_eq!(target.runtime(), *target);
680        }
681    }
682
683    /// A four-byte scheme, the shape of block ORE at one width.
684    struct Four;
685
686    impl OrderScheme for Four {
687        const NAME: &'static str = "four";
688        type Term = Vec<u8>;
689        type Error = core::convert::Infallible;
690        type Space = ();
691
692        fn open(
693            &self,
694            _: OrderTarget,
695            _: &vitaminc_context::Context<'_>,
696        ) -> Result<(), Self::Error> {
697            Ok(())
698        }
699
700        fn encrypt_plaintext(
701            &self,
702            _: &(),
703            _: &crate::OrderPlaintext,
704        ) -> Result<Vec<u8>, Self::Error> {
705            Ok(vec![0])
706        }
707
708        fn compare(a: &Vec<u8>, b: &Vec<u8>) -> Option<core::cmp::Ordering> {
709            Some(a.cmp(b))
710        }
711    }
712
713    crate::supports_targets!(Four; I32, U32, Date);
714
715    #[test]
716    fn a_scheme_takes_a_target_with_a_null_policy_exactly_when_it_takes_the_target() {
717        fn marker<P: NullPolicy>(order: NullOrder) {
718            assert!(
719                <Four as Supports<Nulls<I32, P>>>::supports(Nulls::new(I32)),
720                "{order:?}: a marker the scheme takes"
721            );
722            let placed = Nulls::<Date, P>::new(Date);
723            assert_eq!(placed.target(), Date);
724            assert_eq!(placed.null_order(), order);
725            assert_eq!(placed.runtime(), OrderTarget::Date);
726            assert_eq!(Target::null_order(placed), Some(order));
727        }
728        marker::<First>(NullOrder::First);
729        marker::<Last>(NullOrder::Last);
730        for order in [NullOrder::First, NullOrder::Last] {
731            assert!(
732                <Four as Supports<RuntimeNulls>>::supports(RuntimeNulls::new(
733                    OrderTarget::Date,
734                    order
735                )),
736                "{order:?}: a runtime target the scheme takes"
737            );
738            assert!(
739                !<Four as Supports<RuntimeNulls>>::supports(RuntimeNulls::new(
740                    OrderTarget::I64,
741                    order
742                )),
743                "{order:?}: a runtime target the scheme does not take"
744            );
745            let placed = RuntimeNulls::new(OrderTarget::Date, order);
746            assert_eq!(placed.target(), OrderTarget::Date);
747            assert_eq!(placed.null_order(), order);
748            assert_eq!(placed.runtime(), OrderTarget::Date);
749            assert_eq!(Target::null_order(placed), Some(order));
750        }
751        assert_eq!(I32.null_order(), None, "a marker places no nulls");
752        assert_eq!(
753            OrderTarget::I32.null_order(),
754            None,
755            "nor does a runtime target"
756        );
757    }
758
759    /// Four bytes again, with a hand-written marker answer that refuses
760    /// `U32`, so the policy impls can be seen to ask the target's answer
761    /// rather than assume one.
762    struct Refusing;
763
764    impl OrderScheme for Refusing {
765        const NAME: &'static str = "refusing";
766        type Term = Vec<u8>;
767        type Error = core::convert::Infallible;
768        type Space = ();
769
770        fn open(
771            &self,
772            _: OrderTarget,
773            _: &vitaminc_context::Context<'_>,
774        ) -> Result<(), Self::Error> {
775            Ok(())
776        }
777
778        fn encrypt_plaintext(
779            &self,
780            _: &(),
781            _: &crate::OrderPlaintext,
782        ) -> Result<Vec<u8>, Self::Error> {
783            Ok(vec![0])
784        }
785
786        fn compare(a: &Vec<u8>, b: &Vec<u8>) -> Option<core::cmp::Ordering> {
787            Some(a.cmp(b))
788        }
789    }
790
791    impl Supports<OrderTarget> for Refusing {
792        fn supports(_: OrderTarget) -> bool {
793            false
794        }
795    }
796
797    impl Supports<U32> for Refusing {
798        fn supports(_: U32) -> bool {
799            false
800        }
801    }
802
803    #[test]
804    fn a_policy_target_takes_the_answer_of_the_target_it_is_set_on() {
805        fn marker<P: NullPolicy>() {
806            assert!(
807                !<Refusing as Supports<Nulls<U32, P>>>::supports(Nulls::new(U32)),
808                "{:?}: a marker the scheme refuses stays refused under a policy",
809                P::ORDER
810            );
811        }
812        marker::<First>();
813        marker::<Last>();
814    }
815
816    #[test]
817    fn each_policy_marker_stands_for_its_null_order() {
818        assert_eq!(First::ORDER, NullOrder::First);
819        assert_eq!(Last::ORDER, NullOrder::Last);
820    }
821}