1use crate::{traits::FieldValueKind, types::EntityTag};
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
19pub enum FieldStorageDecode {
20 ByKind,
22 Value,
24}
25
26#[derive(Clone, Copy, Debug, Eq, PartialEq)]
36pub enum ScalarCodec {
37 Blob,
38 Bool,
39 Date,
40 Duration,
41 Float32,
42 Float64,
43 Int64,
44 Principal,
45 Subaccount,
46 Text,
47 Timestamp,
48 Uint64,
49 Ulid,
50 Unit,
51}
52
53#[derive(Clone, Copy, Debug, Eq, PartialEq)]
63pub enum LeafCodec {
64 Scalar(ScalarCodec),
65 CborFallback,
66}
67
68#[derive(Clone, Copy, Debug)]
78pub struct EnumVariantModel {
79 pub(crate) ident: &'static str,
81 pub(crate) payload_kind: Option<&'static FieldKind>,
83 pub(crate) payload_storage_decode: FieldStorageDecode,
85}
86
87impl EnumVariantModel {
88 #[must_use]
90 pub const fn new(
91 ident: &'static str,
92 payload_kind: Option<&'static FieldKind>,
93 payload_storage_decode: FieldStorageDecode,
94 ) -> Self {
95 Self {
96 ident,
97 payload_kind,
98 payload_storage_decode,
99 }
100 }
101
102 #[must_use]
104 pub const fn ident(&self) -> &'static str {
105 self.ident
106 }
107
108 #[must_use]
110 pub const fn payload_kind(&self) -> Option<&'static FieldKind> {
111 self.payload_kind
112 }
113
114 #[must_use]
116 pub const fn payload_storage_decode(&self) -> FieldStorageDecode {
117 self.payload_storage_decode
118 }
119}
120
121#[derive(Debug)]
131pub struct FieldModel {
132 pub(crate) name: &'static str,
134 pub(crate) kind: FieldKind,
136 pub(crate) nullable: bool,
138 pub(crate) storage_decode: FieldStorageDecode,
140 pub(crate) leaf_codec: LeafCodec,
142}
143
144impl FieldModel {
145 #[must_use]
147 pub const fn new(name: &'static str, kind: FieldKind) -> Self {
148 Self::new_with_storage_decode_and_nullability(name, kind, FieldStorageDecode::ByKind, false)
149 }
150
151 #[must_use]
153 pub const fn new_with_storage_decode(
154 name: &'static str,
155 kind: FieldKind,
156 storage_decode: FieldStorageDecode,
157 ) -> Self {
158 Self::new_with_storage_decode_and_nullability(name, kind, storage_decode, false)
159 }
160
161 #[must_use]
163 pub const fn new_with_storage_decode_and_nullability(
164 name: &'static str,
165 kind: FieldKind,
166 storage_decode: FieldStorageDecode,
167 nullable: bool,
168 ) -> Self {
169 Self {
170 name,
171 kind,
172 nullable,
173 storage_decode,
174 leaf_codec: leaf_codec_for(kind, storage_decode),
175 }
176 }
177
178 #[must_use]
180 pub const fn name(&self) -> &'static str {
181 self.name
182 }
183
184 #[must_use]
186 pub const fn kind(&self) -> FieldKind {
187 self.kind
188 }
189
190 #[must_use]
192 pub const fn nullable(&self) -> bool {
193 self.nullable
194 }
195
196 #[must_use]
198 pub const fn storage_decode(&self) -> FieldStorageDecode {
199 self.storage_decode
200 }
201
202 #[must_use]
204 pub const fn leaf_codec(&self) -> LeafCodec {
205 self.leaf_codec
206 }
207}
208
209const fn leaf_codec_for(kind: FieldKind, storage_decode: FieldStorageDecode) -> LeafCodec {
213 if matches!(storage_decode, FieldStorageDecode::Value) {
214 return LeafCodec::CborFallback;
215 }
216
217 match kind {
218 FieldKind::Blob => LeafCodec::Scalar(ScalarCodec::Blob),
219 FieldKind::Bool => LeafCodec::Scalar(ScalarCodec::Bool),
220 FieldKind::Date => LeafCodec::Scalar(ScalarCodec::Date),
221 FieldKind::Duration => LeafCodec::Scalar(ScalarCodec::Duration),
222 FieldKind::Float32 => LeafCodec::Scalar(ScalarCodec::Float32),
223 FieldKind::Float64 => LeafCodec::Scalar(ScalarCodec::Float64),
224 FieldKind::Int => LeafCodec::Scalar(ScalarCodec::Int64),
225 FieldKind::Principal => LeafCodec::Scalar(ScalarCodec::Principal),
226 FieldKind::Subaccount => LeafCodec::Scalar(ScalarCodec::Subaccount),
227 FieldKind::Text => LeafCodec::Scalar(ScalarCodec::Text),
228 FieldKind::Timestamp => LeafCodec::Scalar(ScalarCodec::Timestamp),
229 FieldKind::Uint => LeafCodec::Scalar(ScalarCodec::Uint64),
230 FieldKind::Ulid => LeafCodec::Scalar(ScalarCodec::Ulid),
231 FieldKind::Unit => LeafCodec::Scalar(ScalarCodec::Unit),
232 FieldKind::Relation { key_kind, .. } => leaf_codec_for(*key_kind, storage_decode),
233 FieldKind::Account
234 | FieldKind::Decimal { .. }
235 | FieldKind::Enum { .. }
236 | FieldKind::Int128
237 | FieldKind::IntBig
238 | FieldKind::List(_)
239 | FieldKind::Map { .. }
240 | FieldKind::Set(_)
241 | FieldKind::Structured { .. }
242 | FieldKind::Uint128
243 | FieldKind::UintBig => LeafCodec::CborFallback,
244 }
245}
246
247#[derive(Clone, Copy, Debug, Eq, PartialEq)]
254pub enum RelationStrength {
255 Strong,
256 Weak,
257}
258
259#[derive(Clone, Copy, Debug)]
269pub enum FieldKind {
270 Account,
272 Blob,
273 Bool,
274 Date,
275 Decimal {
276 scale: u32,
278 },
279 Duration,
280 Enum {
281 path: &'static str,
283 variants: &'static [EnumVariantModel],
285 },
286 Float32,
287 Float64,
288 Int,
289 Int128,
290 IntBig,
291 Principal,
292 Subaccount,
293 Text,
294 Timestamp,
295 Uint,
296 Uint128,
297 UintBig,
298 Ulid,
299 Unit,
300
301 Relation {
304 target_path: &'static str,
306 target_entity_name: &'static str,
308 target_entity_tag: EntityTag,
310 target_store_path: &'static str,
312 key_kind: &'static Self,
313 strength: RelationStrength,
314 },
315
316 List(&'static Self),
318 Set(&'static Self),
319 Map {
323 key: &'static Self,
324 value: &'static Self,
325 },
326
327 Structured {
331 queryable: bool,
332 },
333}
334
335impl FieldKind {
336 #[must_use]
337 pub const fn value_kind(&self) -> FieldValueKind {
338 match self {
339 Self::Account
340 | Self::Blob
341 | Self::Bool
342 | Self::Date
343 | Self::Duration
344 | Self::Enum { .. }
345 | Self::Float32
346 | Self::Float64
347 | Self::Int
348 | Self::Int128
349 | Self::IntBig
350 | Self::Principal
351 | Self::Subaccount
352 | Self::Text
353 | Self::Timestamp
354 | Self::Uint
355 | Self::Uint128
356 | Self::UintBig
357 | Self::Ulid
358 | Self::Unit
359 | Self::Decimal { .. }
360 | Self::Relation { .. } => FieldValueKind::Atomic,
361 Self::List(_) | Self::Set(_) => FieldValueKind::Structured { queryable: true },
362 Self::Map { .. } => FieldValueKind::Structured { queryable: false },
363 Self::Structured { queryable } => FieldValueKind::Structured {
364 queryable: *queryable,
365 },
366 }
367 }
368
369 #[must_use]
377 pub const fn is_deterministic_collection_shape(&self) -> bool {
378 match self {
379 Self::Relation { key_kind, .. } => key_kind.is_deterministic_collection_shape(),
380
381 Self::List(inner) | Self::Set(inner) => inner.is_deterministic_collection_shape(),
382
383 Self::Map { key, value } => {
384 key.is_deterministic_collection_shape() && value.is_deterministic_collection_shape()
385 }
386
387 _ => true,
388 }
389 }
390}