use crate::scalar::ScalarTyp;
use crate::typ::{Fields, Typ};
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum SchemaTyp {
Scalar(ScalarTyp),
Array(u32, Box<SchemaTyp>),
Vec(Box<SchemaTyp>),
Optional(Box<SchemaTyp>),
SimpleEnum {
name: String,
variants: Vec<(u8, String)>,
},
Struct {
name: String,
fields: SchemaFields,
},
Enum {
name: String,
variants: Vec<(u8, String, SchemaTyp)>,
},
Custom(String, Vec<SchemaTyp>),
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum SchemaFields {
Named(Vec<(String, SchemaTyp)>),
Unnamed(Vec<SchemaTyp>),
}
impl From<&Typ> for SchemaTyp {
fn from(t: &Typ) -> Self {
match t {
Typ::Scalar(s) => SchemaTyp::Scalar(*s),
Typ::Array(n, inner) => SchemaTyp::Array(*n, Box::new(SchemaTyp::from(*inner))),
Typ::Vec(inner) => SchemaTyp::Vec(Box::new(SchemaTyp::from(*inner))),
Typ::Optional(inner) => SchemaTyp::Optional(Box::new(SchemaTyp::from(*inner))),
Typ::SimpleEnum(e) => SchemaTyp::SimpleEnum {
name: e.name.to_string(),
variants: e
.variants
.iter()
.map(|(i, n)| (*i, n.to_string()))
.collect(),
},
Typ::Struct(s) => SchemaTyp::Struct {
name: s.name.to_string(),
fields: match s.fields {
Fields::Named(fs) => SchemaFields::Named(
fs.iter()
.map(|(n, ty)| (n.to_string(), SchemaTyp::from(ty)))
.collect(),
),
Fields::Unnamed(fs) => {
SchemaFields::Unnamed(fs.iter().map(SchemaTyp::from).collect())
}
},
},
Typ::Enum(e) => SchemaTyp::Enum {
name: e.name.to_string(),
variants: e
.variants
.iter()
.map(|(i, (n, ty))| (*i, n.to_string(), SchemaTyp::from(ty)))
.collect(),
},
Typ::Custom(name, items) => SchemaTyp::Custom(
name.to_string(),
items.iter().map(SchemaTyp::from).collect(),
),
}
}
}
#[cfg(test)]
#[allow(dead_code)]
fn _schema_guard(s: &SchemaTyp) {
match s {
SchemaTyp::Scalar(_) => {}
SchemaTyp::Array(_, _) => {}
SchemaTyp::Vec(_) => {}
SchemaTyp::Optional(_) => {}
SchemaTyp::SimpleEnum { .. } => {}
SchemaTyp::Struct { .. } => {}
SchemaTyp::Enum { .. } => {}
SchemaTyp::Custom(_, _) => {}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::scalar::ScalarTyp;
use crate::typ::{Fields, StructType, Typ};
#[test]
fn from_typ_struct_roundtrips_shape() {
static T: Typ = Typ::Struct(StructType {
name: "S",
fields: Fields::Named(&[
("a", Typ::Scalar(ScalarTyp::U64)),
("b", Typ::Vec(&Typ::Scalar(ScalarTyp::Str))),
]),
});
let s = SchemaTyp::from(&T);
let expected = SchemaTyp::Struct {
name: "S".to_string(),
fields: SchemaFields::Named(vec![
("a".to_string(), SchemaTyp::Scalar(ScalarTyp::U64)),
(
"b".to_string(),
SchemaTyp::Vec(Box::new(SchemaTyp::Scalar(ScalarTyp::Str))),
),
]),
};
assert_eq!(s, expected);
}
#[test]
fn from_typ_covers_scalars_and_composites() {
assert_eq!(
SchemaTyp::from(&Typ::Scalar(ScalarTyp::Fuid)),
SchemaTyp::Scalar(ScalarTyp::Fuid)
);
assert_eq!(
SchemaTyp::from(&Typ::Optional(&Typ::Scalar(ScalarTyp::Id64))),
SchemaTyp::Optional(Box::new(SchemaTyp::Scalar(ScalarTyp::Id64)))
);
assert_eq!(
SchemaTyp::from(&Typ::Custom("c", &[Typ::Scalar(ScalarTyp::U8)])),
SchemaTyp::Custom("c".to_string(), vec![SchemaTyp::Scalar(ScalarTyp::U8)])
);
}
}