facet_core/types/def/
scalar.rs

1use crate::PtrConst;
2
3/// Definition for scalar types
4#[derive(Clone, Copy, Debug)]
5#[repr(C)]
6#[non_exhaustive]
7pub struct ScalarDef<'shape> {
8    /// Affinity of the scalar — is spiritually more like a number, more like a string, something else?
9    /// example: an IPv4 address is both. good luck.
10    pub affinity: &'shape ScalarAffinity<'shape>,
11}
12
13impl<'shape> ScalarDef<'shape> {
14    /// Returns a builder for ScalarDef
15    pub const fn builder() -> ScalarDefBuilder<'shape> {
16        ScalarDefBuilder::new()
17    }
18}
19
20/// Builder for ScalarDef
21#[derive(Default)]
22pub struct ScalarDefBuilder<'shape> {
23    affinity: Option<&'shape ScalarAffinity<'shape>>,
24}
25
26impl<'shape> ScalarDefBuilder<'shape> {
27    /// Creates a new ScalarDefBuilder
28    #[allow(clippy::new_without_default)]
29    pub const fn new() -> Self {
30        Self { affinity: None }
31    }
32
33    /// Sets the affinity for the ScalarDef
34    pub const fn affinity(mut self, affinity: &'shape ScalarAffinity<'shape>) -> Self {
35        self.affinity = Some(affinity);
36        self
37    }
38
39    /// Builds the ScalarDef
40    pub const fn build(self) -> ScalarDef<'shape> {
41        ScalarDef {
42            affinity: self.affinity.unwrap(),
43        }
44    }
45}
46
47/// Scalar affinity: what a scalar spiritually is: a number, a string, a bool, something else
48/// entirely?
49#[derive(Clone, Copy, Debug)]
50#[repr(C)]
51#[non_exhaustive]
52pub enum ScalarAffinity<'shape> {
53    /// Number-like scalar affinity
54    Number(NumberAffinity<'shape>),
55    /// Complex-Number-like scalar affinity
56    ComplexNumber(ComplexNumberAffinity<'shape>),
57    /// String-like scalar affinity
58    String(StringAffinity),
59    /// Boolean scalar affinity
60    Boolean(BoolAffinity),
61    /// Empty scalar affinity
62    Empty(EmptyAffinity),
63    /// Socket address scalar affinity
64    SocketAddr(SocketAddrAffinity),
65    /// IP Address scalar affinity
66    IpAddr(IpAddrAffinity),
67    /// URL scalar affinity
68    Url(UrlAffinity),
69    /// UUID or UUID-like identifier, containing 16 bytes of information
70    UUID(UuidAffinity),
71    /// ULID or ULID-like identifier, containing 16 bytes of information
72    ULID(UlidAffinity),
73    /// Timestamp or Datetime-like scalar affinity
74    Time(TimeAffinity<'shape>),
75    /// Something you're not supposed to look inside of
76    Opaque(OpaqueAffinity),
77    /// Other scalar affinity
78    Other(OtherAffinity),
79    /// Character scalar affinity
80    Char(CharAffinity),
81    /// Path scalar affinity (file/disk paths)
82    Path(PathAffinity),
83}
84
85impl<'shape> ScalarAffinity<'shape> {
86    /// Returns a NumberAffinityBuilder
87    pub const fn number() -> NumberAffinityBuilder<'shape> {
88        NumberAffinityBuilder::new()
89    }
90
91    /// Returns a ComplexNumberAffinityBuilder
92    pub const fn complex_number() -> ComplexNumberAffinityBuilder<'shape> {
93        ComplexNumberAffinityBuilder::new()
94    }
95
96    /// Returns a StringAffinityBuilder
97    pub const fn string() -> StringAffinityBuilder {
98        StringAffinityBuilder::new()
99    }
100
101    /// Returns a BoolAffinityBuilder
102    pub const fn boolean() -> BoolAffinityBuilder {
103        BoolAffinityBuilder::new()
104    }
105
106    /// Returns an EmptyAffinityBuilder
107    pub const fn empty() -> EmptyAffinityBuilder {
108        EmptyAffinityBuilder::new()
109    }
110
111    /// Returns a SocketAddrAffinityBuilder
112    pub const fn socket_addr() -> SocketAddrAffinityBuilder {
113        SocketAddrAffinityBuilder::new()
114    }
115
116    /// Returns an IpAddrAffinityBuilder
117    pub const fn ip_addr() -> IpAddrAffinityBuilder {
118        IpAddrAffinityBuilder::new()
119    }
120
121    /// Returns a UrlAffinityBuilder
122    pub const fn url() -> UrlAffinityBuilder {
123        UrlAffinityBuilder::new()
124    }
125
126    /// Returns an UuidAffinityBuilder
127    pub const fn uuid() -> UuidAffinityBuilder {
128        UuidAffinityBuilder::new()
129    }
130
131    /// Returns a UlidAffinityBuilder
132    pub const fn ulid() -> UlidAffinityBuilder {
133        UlidAffinityBuilder::new()
134    }
135
136    /// Returns an TimeAffinityBuilder
137    pub const fn time() -> TimeAffinityBuilder<'shape> {
138        TimeAffinityBuilder::new()
139    }
140
141    /// Returns an OpaqueAffinityBuilder
142    pub const fn opaque() -> OpaqueAffinityBuilder {
143        OpaqueAffinityBuilder::new()
144    }
145
146    /// Returns an OtherAffinityBuilder
147    pub const fn other() -> OtherAffinityBuilder {
148        OtherAffinityBuilder::new()
149    }
150
151    /// Returns a CharAffinityBuilder
152    pub const fn char() -> CharAffinityBuilder {
153        CharAffinityBuilder::new()
154    }
155
156    /// Returns a PathAffinityBuilder
157    pub const fn path() -> PathAffinityBuilder {
158        PathAffinityBuilder::new()
159    }
160}
161
162//////////////////////////////////////////////////////////////////////////////////////////
163// Affinities
164//////////////////////////////////////////////////////////////////////////////////////////
165
166/// Definition for number-like scalar affinities
167#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
168#[repr(C)]
169#[non_exhaustive]
170pub struct NumberAffinity<'shape> {
171    /// Bit representation of numbers
172    pub bits: NumberBits,
173
174    /// Minimum representable value
175    pub min: PtrConst<'shape>,
176
177    /// Maximum representable value
178    pub max: PtrConst<'shape>,
179
180    /// Positive infinity representable value
181    pub positive_infinity: Option<PtrConst<'shape>>,
182
183    /// Negative infinity representable value
184    pub negative_infinity: Option<PtrConst<'shape>>,
185
186    /// Example NaN (Not a Number) value.
187    /// Why sample? Because there are many NaN values, and we need to provide a representative one.
188    pub nan_sample: Option<PtrConst<'shape>>,
189
190    /// Positive zero representation. If there's only one zero, only set this one.
191    pub positive_zero: Option<PtrConst<'shape>>,
192
193    /// Negative zero representation
194    pub negative_zero: Option<PtrConst<'shape>>,
195
196    /// "Machine epsilon" (<https://en.wikipedia.org/wiki/Machine_epsilon>), AKA relative
197    /// approximation error, if relevant
198    pub epsilon: Option<PtrConst<'shape>>,
199}
200
201/// Represents whether a numeric type is signed or unsigned
202#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
203#[repr(C)]
204pub enum Signedness {
205    /// Signed numeric type
206    Signed,
207    /// Unsigned numeric type
208    Unsigned,
209}
210
211/// Size specification for integer types
212#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
213#[repr(C)]
214pub enum IntegerSize {
215    /// Fixed-size integer (e.g., u64, i32)
216    Fixed(usize),
217    /// Pointer-sized integer (e.g., usize, isize)
218    PointerSized,
219}
220
221impl IntegerSize {
222    /// Returns the actual number of bits for this integer size
223    pub const fn bits(&self) -> usize {
224        match self {
225            IntegerSize::Fixed(bits) => *bits,
226            IntegerSize::PointerSized => core::mem::size_of::<usize>() * 8,
227        }
228    }
229}
230
231/// Bit representation of numbers
232#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
233#[repr(C)]
234#[non_exhaustive]
235pub enum NumberBits {
236    /// Integer number limits with specified size and signedness
237    Integer {
238        /// Size specification for the integer
239        size: IntegerSize,
240        /// Whether the integer is signed or unsigned
241        sign: Signedness,
242    },
243    /// Floating-point number limits with specified sign, exponent and mantissa bits
244    Float {
245        /// Number of bits used for the sign (typically 1)
246        sign_bits: usize,
247        /// Number of bits used for the exponent
248        exponent_bits: usize,
249        /// Number of bits used for the mantissa (fraction part)
250        mantissa_bits: usize,
251        /// Floating-point numbers that are large enough to not be "in subnormal mode"
252        /// have their mantissa represent a number between 1 (included) and 2 (excluded)
253        /// This indicates whether the representation of the mantissa has the significant digit
254        /// (always 1) explicitly written out
255        has_explicit_first_mantissa_bit: bool,
256    },
257    /// Fixed-point number limits with specified integer and fractional bits
258    Fixed {
259        /// Number of bits used for the sign (typically 0 or 1)
260        sign_bits: usize,
261        /// Number of bits used for the integer part
262        integer_bits: usize,
263        /// Number of bits used for the fractional part
264        fraction_bits: usize,
265    },
266    /// Decimal number limits with unsized-integer, scaling, and sign bits
267    Decimal {
268        /// Number of bits used for the sign (typically 0 or 1)
269        sign_bits: usize,
270        /// Number of bits used for the integer part
271        integer_bits: usize,
272        /// Number of bits used for the scale part
273        scale_bits: usize,
274    },
275}
276
277impl<'shape> NumberAffinity<'shape> {
278    /// Returns a builder for NumberAffinity
279    pub const fn builder() -> NumberAffinityBuilder<'shape> {
280        NumberAffinityBuilder::new()
281    }
282}
283
284/// Builder for NumberAffinity
285#[repr(C)]
286pub struct NumberAffinityBuilder<'shape> {
287    limits: Option<NumberBits>,
288    min: Option<PtrConst<'shape>>,
289    max: Option<PtrConst<'shape>>,
290    positive_infinity: Option<PtrConst<'shape>>,
291    negative_infinity: Option<PtrConst<'shape>>,
292    nan_sample: Option<PtrConst<'shape>>,
293    positive_zero: Option<PtrConst<'shape>>,
294    negative_zero: Option<PtrConst<'shape>>,
295    epsilon: Option<PtrConst<'shape>>,
296}
297
298impl<'shape> NumberAffinityBuilder<'shape> {
299    /// Creates a new NumberAffinityBuilder
300    #[allow(clippy::new_without_default)]
301    pub const fn new() -> Self {
302        Self {
303            limits: None,
304            min: None,
305            max: None,
306            positive_infinity: None,
307            negative_infinity: None,
308            nan_sample: None,
309            positive_zero: None,
310            negative_zero: None,
311            epsilon: None,
312        }
313    }
314
315    /// Sets the number limits as integer with specified bits and sign
316    pub const fn integer(mut self, bits: usize, sign: Signedness) -> Self {
317        self.limits = Some(NumberBits::Integer {
318            size: IntegerSize::Fixed(bits),
319            sign,
320        });
321        self
322    }
323
324    /// Sets the number limits as signed integer with specified bits
325    pub const fn signed_integer(self, bits: usize) -> Self {
326        self.integer(bits, Signedness::Signed)
327    }
328
329    /// Sets the number limits as unsigned integer with specified bits
330    pub const fn unsigned_integer(self, bits: usize) -> Self {
331        self.integer(bits, Signedness::Unsigned)
332    }
333
334    /// Sets the number limits as pointer-sized signed integer
335    pub const fn pointer_sized_signed_integer(mut self) -> Self {
336        self.limits = Some(NumberBits::Integer {
337            size: IntegerSize::PointerSized,
338            sign: Signedness::Signed,
339        });
340        self
341    }
342
343    /// Sets the number limits as pointer-sized unsigned integer
344    pub const fn pointer_sized_unsigned_integer(mut self) -> Self {
345        self.limits = Some(NumberBits::Integer {
346            size: IntegerSize::PointerSized,
347            sign: Signedness::Unsigned,
348        });
349        self
350    }
351
352    /// Sets the number limits as float with specified bits
353    pub const fn float(
354        mut self,
355        sign_bits: usize,
356        exponent_bits: usize,
357        mantissa_bits: usize,
358        has_explicit_first_mantissa_bit: bool,
359    ) -> Self {
360        self.limits = Some(NumberBits::Float {
361            sign_bits,
362            exponent_bits,
363            mantissa_bits,
364            has_explicit_first_mantissa_bit,
365        });
366        self
367    }
368
369    /// Sets the number limits as fixed-point with specified bits
370    pub const fn fixed(
371        mut self,
372        sign_bits: usize,
373        integer_bits: usize,
374        fraction_bits: usize,
375    ) -> Self {
376        self.limits = Some(NumberBits::Fixed {
377            sign_bits,
378            integer_bits,
379            fraction_bits,
380        });
381        self
382    }
383
384    /// Sets the min value for the NumberAffinity
385    pub const fn min(mut self, min: PtrConst<'shape>) -> Self {
386        self.min = Some(min);
387        self
388    }
389
390    /// Sets the max value for the NumberAffinity
391    pub const fn max(mut self, max: PtrConst<'shape>) -> Self {
392        self.max = Some(max);
393        self
394    }
395
396    /// Sets the positive infinity value for the NumberAffinity
397    pub const fn positive_infinity(mut self, value: PtrConst<'shape>) -> Self {
398        self.positive_infinity = Some(value);
399        self
400    }
401
402    /// Sets the negative infinity value for the NumberAffinity
403    pub const fn negative_infinity(mut self, value: PtrConst<'shape>) -> Self {
404        self.negative_infinity = Some(value);
405        self
406    }
407
408    /// Sets the NaN sample value for the NumberAffinity
409    pub const fn nan_sample(mut self, value: PtrConst<'shape>) -> Self {
410        self.nan_sample = Some(value);
411        self
412    }
413
414    /// Sets the positive zero value for the NumberAffinity
415    pub const fn positive_zero(mut self, value: PtrConst<'shape>) -> Self {
416        self.positive_zero = Some(value);
417        self
418    }
419
420    /// Sets the negative zero value for the NumberAffinity
421    pub const fn negative_zero(mut self, value: PtrConst<'shape>) -> Self {
422        self.negative_zero = Some(value);
423        self
424    }
425
426    /// Sets the relative uncertainty for the NumberAffinity
427    pub const fn epsilon(mut self, value: PtrConst<'shape>) -> Self {
428        self.epsilon = Some(value);
429        self
430    }
431
432    /// Builds the ScalarAffinity
433    pub const fn build(self) -> ScalarAffinity<'shape> {
434        ScalarAffinity::Number(NumberAffinity {
435            bits: self.limits.unwrap(),
436            min: self.min.unwrap(),
437            max: self.max.unwrap(),
438            positive_infinity: self.positive_infinity,
439            negative_infinity: self.negative_infinity,
440            nan_sample: self.nan_sample,
441            positive_zero: self.positive_zero,
442            negative_zero: self.negative_zero,
443            epsilon: self.epsilon,
444        })
445    }
446}
447
448/// Definition for string-like scalar affinities
449#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
450#[repr(C)]
451#[non_exhaustive]
452pub struct ComplexNumberAffinity<'shape> {
453    /// hiding the actual enum in a non-pub element
454    inner: ComplexNumberAffinityInner<'shape>,
455}
456
457#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
458#[repr(C)]
459#[non_exhaustive]
460enum ComplexNumberAffinityInner<'shape> {
461    /// represented as a+ib
462    Cartesian {
463        /// the underlying number affinity for both components
464        /// (assuming they are the same seems reasonable)
465        component: NumberAffinity<'shape>,
466    },
467    /// represented as a*exp(ib)
468    Polar {
469        /// the number affinity for the absolute value
470        absolute: NumberAffinity<'shape>,
471        /// the number affinity for the ...angle? bearing?
472        bearing: NumberAffinity<'shape>,
473    },
474}
475
476impl<'shape> ComplexNumberAffinity<'shape> {
477    /// Returns a builder for ComplexNumberAffinity
478    pub const fn builder() -> ComplexNumberAffinityBuilder<'shape> {
479        ComplexNumberAffinityBuilder::new()
480    }
481}
482
483/// Builder for ComplexNumberAffinity
484#[repr(C)]
485pub struct ComplexNumberAffinityBuilder<'shape> {
486    inner: ComplexNumberAffinityBuilderInner<'shape>,
487}
488
489#[repr(C)]
490enum ComplexNumberAffinityBuilderInner<'shape> {
491    Undefined,
492    Cartesian {
493        // note: this could have been a NumberAffinityBuilder,
494        // but we want to be able to set this up from existing Number types
495        component: NumberAffinity<'shape>,
496    },
497    Polar {
498        absolute: NumberAffinity<'shape>,
499        bearing: NumberAffinity<'shape>,
500    },
501}
502
503impl<'shape> ComplexNumberAffinityBuilder<'shape> {
504    /// Creates a new ComplexNumberAffinityBuilder
505    #[allow(clippy::new_without_default)]
506    pub const fn new() -> Self {
507        Self {
508            inner: ComplexNumberAffinityBuilderInner::Undefined,
509        }
510    }
511
512    /// sets the coordinates system to be cartesian
513    pub const fn cartesian(self, component: NumberAffinity<'shape>) -> Self {
514        Self {
515            inner: ComplexNumberAffinityBuilderInner::Cartesian { component },
516        }
517    }
518
519    /// sets the coordinates system to be polar
520    pub const fn polar(
521        self,
522        absolute: NumberAffinity<'shape>,
523        bearing: NumberAffinity<'shape>,
524    ) -> Self {
525        Self {
526            inner: ComplexNumberAffinityBuilderInner::Polar { absolute, bearing },
527        }
528    }
529
530    /// Builds the ScalarAffinity
531    pub const fn build(self) -> ScalarAffinity<'shape> {
532        use ComplexNumberAffinityBuilderInner as Inner;
533        use ComplexNumberAffinityInner as AffInner;
534        let inner = match self.inner {
535            Inner::Undefined => panic!(),
536            Inner::Cartesian { component } => AffInner::Cartesian { component },
537            Inner::Polar { absolute, bearing } => AffInner::Polar { absolute, bearing },
538        };
539        ScalarAffinity::ComplexNumber(ComplexNumberAffinity { inner })
540    }
541}
542
543/// Definition for string-like scalar affinities
544#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
545#[repr(C)]
546#[non_exhaustive]
547pub struct StringAffinity {
548    /// Maximum inline length
549    pub max_inline_length: Option<usize>,
550}
551
552impl StringAffinity {
553    /// Returns a builder for StringAffinity
554    pub const fn builder() -> StringAffinityBuilder {
555        StringAffinityBuilder::new()
556    }
557}
558
559/// Builder for StringAffinity
560#[repr(C)]
561pub struct StringAffinityBuilder {
562    max_inline_length: Option<usize>,
563}
564
565impl StringAffinityBuilder {
566    /// Creates a new StringAffinityBuilder
567    #[allow(clippy::new_without_default)]
568    pub const fn new() -> Self {
569        Self {
570            max_inline_length: None,
571        }
572    }
573
574    /// Sets the max_inline_length for the StringAffinity
575    pub const fn max_inline_length(mut self, max_inline_length: usize) -> Self {
576        self.max_inline_length = Some(max_inline_length);
577        self
578    }
579
580    /// Builds the ScalarAffinity
581    pub const fn build(self) -> ScalarAffinity<'static> {
582        ScalarAffinity::String(StringAffinity {
583            max_inline_length: self.max_inline_length,
584        })
585    }
586}
587
588/// Definition for boolean scalar affinities
589#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
590#[repr(C)]
591#[non_exhaustive]
592pub struct BoolAffinity {}
593
594impl BoolAffinity {
595    /// Returns a builder for BoolAffinity
596    pub const fn builder() -> BoolAffinityBuilder {
597        BoolAffinityBuilder::new()
598    }
599}
600
601/// Builder for BoolAffinity
602#[repr(C)]
603pub struct BoolAffinityBuilder {}
604
605impl BoolAffinityBuilder {
606    /// Creates a new BoolAffinityBuilder
607    #[allow(clippy::new_without_default)]
608    pub const fn new() -> Self {
609        Self {}
610    }
611
612    /// Builds the ScalarAffinity
613    pub const fn build(self) -> ScalarAffinity<'static> {
614        ScalarAffinity::Boolean(BoolAffinity {})
615    }
616}
617
618/// Definition for empty scalar affinities
619#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
620#[repr(C)]
621#[non_exhaustive]
622pub struct EmptyAffinity {}
623
624impl EmptyAffinity {
625    /// Returns a builder for EmptyAffinity
626    pub const fn builder() -> EmptyAffinityBuilder {
627        EmptyAffinityBuilder::new()
628    }
629}
630
631/// Builder for EmptyAffinity
632#[repr(C)]
633pub struct EmptyAffinityBuilder {}
634
635impl EmptyAffinityBuilder {
636    /// Creates a new EmptyAffinityBuilder
637    #[allow(clippy::new_without_default)]
638    pub const fn new() -> Self {
639        Self {}
640    }
641
642    /// Builds the ScalarAffinity
643    pub const fn build(self) -> ScalarAffinity<'static> {
644        ScalarAffinity::Empty(EmptyAffinity {})
645    }
646}
647
648/// Definition for socket address scalar affinities
649#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
650#[repr(C)]
651#[non_exhaustive]
652pub struct SocketAddrAffinity {}
653
654impl SocketAddrAffinity {
655    /// Returns a builder for SocketAddrAffinity
656    pub const fn builder() -> SocketAddrAffinityBuilder {
657        SocketAddrAffinityBuilder::new()
658    }
659}
660
661/// Builder for SocketAddrAffinity
662#[repr(C)]
663pub struct SocketAddrAffinityBuilder {}
664
665impl SocketAddrAffinityBuilder {
666    /// Creates a new SocketAddrAffinityBuilder
667    #[allow(clippy::new_without_default)]
668    pub const fn new() -> Self {
669        Self {}
670    }
671
672    /// Builds the ScalarAffinity
673    pub const fn build(self) -> ScalarAffinity<'static> {
674        ScalarAffinity::SocketAddr(SocketAddrAffinity {})
675    }
676}
677
678/// Definition for IP address scalar affinities
679#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
680#[repr(C)]
681#[non_exhaustive]
682pub struct IpAddrAffinity {}
683
684impl IpAddrAffinity {
685    /// Returns a builder for IpAddrAffinity
686    pub const fn builder() -> IpAddrAffinityBuilder {
687        IpAddrAffinityBuilder::new()
688    }
689}
690
691/// Builder for IpAddrAffinity
692#[repr(C)]
693pub struct IpAddrAffinityBuilder {}
694
695impl IpAddrAffinityBuilder {
696    /// Creates a new IpAddrAffinityBuilder
697    #[allow(clippy::new_without_default)]
698    pub const fn new() -> Self {
699        Self {}
700    }
701
702    /// Builds the ScalarAffinity
703    pub const fn build(self) -> ScalarAffinity<'static> {
704        ScalarAffinity::IpAddr(IpAddrAffinity {})
705    }
706}
707
708/// Definition for URL scalar affinities
709#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
710#[repr(C)]
711#[non_exhaustive]
712pub struct UrlAffinity {}
713
714impl UrlAffinity {
715    /// Returns a builder for UrlAffinity
716    pub const fn builder() -> UrlAffinityBuilder {
717        UrlAffinityBuilder::new()
718    }
719}
720
721/// Builder for UrlAffinity
722#[repr(C)]
723pub struct UrlAffinityBuilder {}
724
725impl UrlAffinityBuilder {
726    /// Creates a new UrlAffinityBuilder
727    #[allow(clippy::new_without_default)]
728    pub const fn new() -> Self {
729        Self {}
730    }
731
732    /// Builds the ScalarAffinity
733    pub const fn build(self) -> ScalarAffinity<'static> {
734        ScalarAffinity::Url(UrlAffinity {})
735    }
736}
737
738/// Definition for UUID and UUID-like scalar affinities
739#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
740#[repr(C)]
741#[non_exhaustive]
742pub struct UuidAffinity {}
743
744impl UuidAffinity {
745    /// Returns a builder for UuidAffinity
746    pub const fn builder() -> UuidAffinityBuilder {
747        UuidAffinityBuilder::new()
748    }
749}
750
751/// Builder for UuidAffinity
752#[repr(C)]
753pub struct UuidAffinityBuilder {}
754
755impl UuidAffinityBuilder {
756    /// Creates a new UuidAffinityBuilder
757    #[allow(clippy::new_without_default)]
758    pub const fn new() -> Self {
759        Self {}
760    }
761
762    /// Builds the ScalarAffinity
763    pub const fn build(self) -> ScalarAffinity<'static> {
764        ScalarAffinity::UUID(UuidAffinity {})
765    }
766}
767
768/// Definition for ULID and ULID-like scalar affinities
769#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
770#[repr(C)]
771#[non_exhaustive]
772pub struct UlidAffinity {}
773
774impl UlidAffinity {
775    /// Returns a builder for UlidAffinity
776    pub const fn builder() -> UlidAffinityBuilder {
777        UlidAffinityBuilder::new()
778    }
779}
780
781/// Builder for UlidAffinity
782#[repr(C)]
783pub struct UlidAffinityBuilder {}
784
785impl UlidAffinityBuilder {
786    /// Creates a new UlidAffinityBuilder
787    #[allow(clippy::new_without_default)]
788    pub const fn new() -> Self {
789        UlidAffinityBuilder {}
790    }
791
792    /// Builds the ScalarAffinity
793    pub const fn build(self) -> ScalarAffinity<'static> {
794        ScalarAffinity::ULID(UlidAffinity {})
795    }
796}
797
798/// Definition for Datetime/Timestamp scalar affinities
799#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
800#[repr(C)]
801#[non_exhaustive]
802pub struct TimeAffinity<'shape> {
803    /// What serves as the reference, or "time zero"
804    /// for implementations that don't depend on an epoch in the traditionnal sense,
805    /// the first moment of year 1AD can be used
806    epoch: Option<PtrConst<'shape>>,
807
808    /// The first moment representable
809    min: Option<PtrConst<'shape>>,
810
811    /// The last moment representable
812    max: Option<PtrConst<'shape>>,
813
814    /// The moment immediately after the epoch,
815    /// serving as a proxy for the smallest interval of time representable
816    /// (do use None if this interval depends on when in time the interval occurs, e.g. if someone
817    /// ever decides to store a timestamp on floating-point numbers)
818    granularity: Option<PtrConst<'shape>>,
819
820    // TODO: the following solution leaves a LOT to desire.
821    // Some examples of things where this breaks:
822    // - leap years, day length in daylight savings, leap seconds
823    // - datetime objects that seamlessly switch from Julian to Gregorian calendar
824    //   - even worse if this transition is based on when a given country did, if there even is
825    //   something that does this
826    // - datetime objects that allow you to specify both individual Gregorian months and ISO 8601
827    //   weeks (but of course not at the same time, which is the whole difficulty)
828    /// For DateTime types made of interval elements some of which are optional
829    /// (for instance, letting you say "the 1st of March" without specifying year, hours, etc.)
830    /// Specify how long the interval elements (hour, minute, etc.) are
831    /// (all represented as moments separated from the epoch by said intervals)
832    /// the intervals MUST be of increasing length. (TODO bikeshedding for this line)
833    interval_elements: Option<&'shape [PtrConst<'shape>]>,
834
835    /// the minimum interval between timezone-local times which correspond to the same global time
836    /// (planet-local time? I mean duh that's what global means right?)
837    /// store a copy of the epoch for a lack of timezone support, and None for "it's more
838    /// complicated than that".
839    timezone_granularity: Option<PtrConst<'shape>>,
840}
841
842impl<'shape> TimeAffinity<'shape> {
843    /// Returns a builder for TimeAffinity
844    pub const fn builder() -> TimeAffinityBuilder<'shape> {
845        TimeAffinityBuilder::new()
846    }
847}
848
849/// Builder for UuidAffinity
850#[repr(C)]
851pub struct TimeAffinityBuilder<'shape> {
852    epoch: Option<PtrConst<'shape>>,
853    min: Option<PtrConst<'shape>>,
854    max: Option<PtrConst<'shape>>,
855    granularity: Option<PtrConst<'shape>>,
856    interval_elements: Option<&'shape [PtrConst<'shape>]>,
857    timezone_granularity: Option<PtrConst<'shape>>,
858}
859
860impl<'shape> TimeAffinityBuilder<'shape> {
861    /// Creates a new UuidAffinityBuilder
862    #[allow(clippy::new_without_default)]
863    pub const fn new() -> Self {
864        Self {
865            epoch: None,
866            min: None,
867            max: None,
868            granularity: None,
869            interval_elements: None,
870            timezone_granularity: None,
871        }
872    }
873
874    /// Sets the epoch for the TimeAffinity
875    pub const fn epoch(mut self, epoch: PtrConst<'shape>) -> Self {
876        self.epoch = Some(epoch);
877        self
878    }
879
880    /// Sets the min value for the TimeAffinity
881    pub const fn min(mut self, min: PtrConst<'shape>) -> Self {
882        self.min = Some(min);
883        self
884    }
885
886    /// Sets the max value for the TimeAffinity
887    pub const fn max(mut self, max: PtrConst<'shape>) -> Self {
888        self.max = Some(max);
889        self
890    }
891
892    /// Sets the granularity for the TimeAffinity
893    pub const fn granularity(mut self, granularity: PtrConst<'shape>) -> Self {
894        self.granularity = Some(granularity);
895        self
896    }
897
898    /// Sets the interval elements for the TimeAffinity
899    pub const fn interval_elements(
900        mut self,
901        interval_elements: &'shape [PtrConst<'shape>],
902    ) -> Self {
903        self.interval_elements = Some(interval_elements);
904        self
905    }
906
907    /// Sets the timezone granularity for the TimeAffinity
908    pub const fn timezone_granularity(mut self, timezone_granularity: PtrConst<'shape>) -> Self {
909        self.timezone_granularity = Some(timezone_granularity);
910        self
911    }
912
913    /// Builds the ScalarAffinity
914    pub const fn build(self) -> ScalarAffinity<'shape> {
915        ScalarAffinity::Time(TimeAffinity {
916            epoch: self.epoch,
917            min: self.min,
918            max: self.max,
919            granularity: self.granularity,
920            interval_elements: self.interval_elements,
921            timezone_granularity: self.timezone_granularity,
922        })
923    }
924}
925
926/// Definition for opaque scalar affinities
927#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
928#[repr(C)]
929#[non_exhaustive]
930pub struct OpaqueAffinity {}
931
932impl OpaqueAffinity {
933    /// Returns a builder for OpaqueAffinity
934    pub const fn builder() -> OpaqueAffinityBuilder {
935        OpaqueAffinityBuilder::new()
936    }
937}
938
939/// Builder for OpaqueAffinity
940#[repr(C)]
941pub struct OpaqueAffinityBuilder {}
942
943impl OpaqueAffinityBuilder {
944    /// Creates a new OpaqueAffinityBuilder
945    #[allow(clippy::new_without_default)]
946    pub const fn new() -> Self {
947        Self {}
948    }
949
950    /// Builds the ScalarAffinity
951    pub const fn build(self) -> ScalarAffinity<'static> {
952        ScalarAffinity::Opaque(OpaqueAffinity {})
953    }
954}
955
956/// Definition for other scalar affinities
957#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
958#[repr(C)]
959#[non_exhaustive]
960pub struct OtherAffinity {}
961
962impl OtherAffinity {
963    /// Returns a builder for OtherAffinity
964    pub const fn builder() -> OtherAffinityBuilder {
965        OtherAffinityBuilder::new()
966    }
967}
968
969/// Builder for OtherAffinity
970#[repr(C)]
971pub struct OtherAffinityBuilder {}
972
973impl OtherAffinityBuilder {
974    /// Creates a new OtherAffinityBuilder
975    #[allow(clippy::new_without_default)]
976    pub const fn new() -> Self {
977        Self {}
978    }
979
980    /// Builds the ScalarAffinity
981    pub const fn build(self) -> ScalarAffinity<'static> {
982        ScalarAffinity::Other(OtherAffinity {})
983    }
984}
985
986/// Definition for character scalar affinities
987#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
988#[repr(C)]
989#[non_exhaustive]
990pub struct CharAffinity {}
991
992impl CharAffinity {
993    /// Returns a builder for CharAffinity
994    pub const fn builder() -> CharAffinityBuilder {
995        CharAffinityBuilder::new()
996    }
997}
998
999/// Builder for CharAffinity
1000#[repr(C)]
1001pub struct CharAffinityBuilder {}
1002
1003impl CharAffinityBuilder {
1004    /// Creates a new CharAffinityBuilder
1005    #[allow(clippy::new_without_default)]
1006    pub const fn new() -> Self {
1007        Self {}
1008    }
1009
1010    /// Builds the ScalarAffinity
1011    pub const fn build(self) -> ScalarAffinity<'static> {
1012        ScalarAffinity::Char(CharAffinity {})
1013    }
1014}
1015
1016/// Definition for path scalar affinities
1017#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1018#[repr(C)]
1019#[non_exhaustive]
1020pub struct PathAffinity {}
1021
1022impl PathAffinity {
1023    /// Returns a builder for PathAffinity
1024    pub const fn builder() -> PathAffinityBuilder {
1025        PathAffinityBuilder::new()
1026    }
1027}
1028
1029/// Builder for PathAffinity
1030#[repr(C)]
1031pub struct PathAffinityBuilder {}
1032
1033impl PathAffinityBuilder {
1034    /// Creates a new PathAffinityBuilder
1035    #[allow(clippy::new_without_default)]
1036    pub const fn new() -> Self {
1037        Self {}
1038    }
1039
1040    /// Builds the ScalarAffinity
1041    pub const fn build(self) -> ScalarAffinity<'static> {
1042        ScalarAffinity::Path(PathAffinity {})
1043    }
1044}