tc_collection/
schema.rs

1use std::fmt;
2
3use destream::en;
4use safecast::CastFrom;
5#[cfg(feature = "tensor")]
6use safecast::TryCastFrom;
7#[cfg(feature = "btree")]
8use safecast::{as_type, CastInto};
9
10use tc_error::*;
11use tc_transact::hash::{Digest, Hash, Output};
12use tc_value::Value;
13use tcgeneric::NativeClass;
14use tcgeneric::TCPathBuf;
15
16#[cfg(feature = "btree")]
17use crate::btree::{BTreeSchema, BTreeType};
18#[cfg(feature = "table")]
19use crate::table::{TableSchema, TableType};
20#[cfg(feature = "tensor")]
21use crate::tensor::{Schema as TensorSchema, TensorType};
22use crate::CollectionType;
23
24/// The schema of a `Collection`.
25#[derive(Clone, Eq, PartialEq)]
26pub enum Schema {
27    Null,
28    #[cfg(feature = "btree")]
29    BTree(BTreeSchema),
30    #[cfg(feature = "table")]
31    Table(TableSchema),
32    #[cfg(feature = "tensor")]
33    Dense(TensorSchema),
34    #[cfg(feature = "tensor")]
35    Sparse(TensorSchema),
36}
37
38#[cfg(feature = "btree")]
39as_type!(Schema, BTree, BTreeSchema);
40#[cfg(feature = "table")]
41as_type!(Schema, Table, TableSchema);
42
43impl<D: Digest> Hash<D> for Schema {
44    fn hash(self) -> Output<D> {
45        Hash::<D>::hash(&self)
46    }
47}
48
49impl<'a, D: Digest> Hash<D> for &'a Schema {
50    fn hash(self) -> Output<D> {
51        match self {
52            Schema::Null => tc_transact::hash::default_hash::<D>(),
53            #[cfg(feature = "btree")]
54            Schema::BTree(schema) => Hash::<D>::hash((BTreeType::default().path(), schema)),
55            #[cfg(feature = "table")]
56            Schema::Table(schema) => Hash::<D>::hash((TableType::default().path(), schema)),
57            #[cfg(feature = "tensor")]
58            Schema::Dense(schema) => Hash::<D>::hash((TensorType::Dense.path(), schema)),
59            #[cfg(feature = "tensor")]
60            Schema::Sparse(schema) => Hash::<D>::hash((TensorType::Sparse.path(), schema)),
61        }
62    }
63}
64
65impl TryFrom<(TCPathBuf, Value)> for Schema {
66    type Error = TCError;
67
68    fn try_from(value: (TCPathBuf, Value)) -> Result<Self, Self::Error> {
69        #[allow(unused_variables)]
70        let (classpath, schema) = value;
71
72        let class = CollectionType::from_path(&classpath)
73            .ok_or_else(|| bad_request!("invalid collection type: {}", classpath))?;
74
75        match class {
76            CollectionType::Null => Ok(Schema::Null),
77            #[cfg(feature = "btree")]
78            CollectionType::BTree(_) => BTreeSchema::try_cast_from_value(schema).map(Self::BTree),
79            #[cfg(feature = "table")]
80            CollectionType::Table(_) => TableSchema::try_cast_from_value(schema).map(Self::Table),
81            #[cfg(feature = "tensor")]
82            CollectionType::Tensor(class) => {
83                let schema = TensorSchema::try_cast_from(schema, |v| {
84                    bad_request!("invalid Tensor schema: {v:?}")
85                })?;
86
87                match class {
88                    TensorType::Dense => Ok(Self::Dense(schema)),
89                    TensorType::Sparse => Ok(Self::Sparse(schema)),
90                }
91            }
92        }
93    }
94}
95
96impl<'en> en::IntoStream<'en> for Schema {
97    fn into_stream<E: en::Encoder<'en>>(self, encoder: E) -> Result<E::Ok, E::Error> {
98        use destream::en::EncodeMap;
99
100        let mut map = encoder.encode_map(Some(1))?;
101
102        match self {
103            Self::Null => {
104                map.encode_entry(CollectionType::Null.path(), ())?;
105            }
106
107            #[cfg(feature = "btree")]
108            Self::BTree(schema) => {
109                map.encode_entry(BTreeType::default().path(), (schema,))?;
110            }
111
112            #[cfg(feature = "table")]
113            Self::Table(schema) => {
114                map.encode_entry(TableType::default().path(), (schema,))?;
115            }
116
117            #[cfg(feature = "tensor")]
118            Self::Dense(schema) | Self::Sparse(schema) => {
119                map.encode_entry(TensorType::Dense.path(), (schema,))?;
120            }
121        }
122
123        map.end()
124    }
125}
126
127impl CastFrom<Schema> for Value {
128    fn cast_from(schema: Schema) -> Self {
129        match schema {
130            Schema::Null => Value::None,
131            #[cfg(feature = "btree")]
132            Schema::BTree(schema) => schema.cast_into(),
133            #[cfg(feature = "table")]
134            Schema::Table(schema) => schema.cast_into(),
135            #[cfg(feature = "tensor")]
136            Schema::Dense(schema) => schema.cast_into(),
137            #[cfg(feature = "tensor")]
138            Schema::Sparse(schema) => schema.cast_into(),
139        }
140    }
141}
142
143impl fmt::Debug for Schema {
144    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145        match self {
146            Schema::Null => f.write_str("null collection schema"),
147            #[cfg(feature = "btree")]
148            Self::BTree(schema) => fmt::Debug::fmt(schema, f),
149            #[cfg(feature = "table")]
150            Self::Table(schema) => fmt::Debug::fmt(schema, f),
151            #[cfg(feature = "tensor")]
152            Self::Dense(schema) => fmt::Debug::fmt(schema, f),
153            #[cfg(feature = "tensor")]
154            Self::Sparse(schema) => fmt::Debug::fmt(schema, f),
155        }
156    }
157}