use std::collections::HashMap;
use facet::Facet;
#[derive(Facet, Debug, Clone)]
pub struct SchemaFile {
pub meta: Meta,
#[facet(skip_serializing_if = Option::is_none)]
pub imports: Option<HashMap<String, String>>,
pub schema: HashMap<Option<String>, Schema>,
}
#[derive(Facet, Debug, Clone)]
pub struct Meta {
pub id: String,
#[facet(skip_serializing_if = Option::is_none)]
pub version: Option<String>,
#[facet(skip_serializing_if = Option::is_none)]
pub cli: Option<String>,
#[facet(skip_serializing_if = Option::is_none)]
pub description: Option<String>,
#[facet(skip_serializing_if = Option::is_none)]
pub lsp: Option<LspExtensionConfig>,
}
#[derive(Facet, Debug, Clone)]
pub struct LspExtensionConfig {
pub launch: Vec<String>,
#[facet(skip_serializing_if = Option::is_none)]
pub capabilities: Option<Vec<String>>,
}
#[derive(Facet, Debug, Clone)]
#[facet(rename_all = "lowercase")]
#[repr(u8)]
pub enum Schema {
String(Option<StringConstraints>),
Int(Option<IntConstraints>),
Float(Option<FloatConstraints>),
Bool,
Unit,
Any,
Object(ObjectSchema),
Seq(SeqSchema),
Tuple(TupleSchema),
Map(MapSchema),
Union(UnionSchema),
Optional(OptionalSchema),
Enum(EnumSchema),
#[facet(rename = "one-of")]
OneOf(OneOfSchema),
Flatten(FlattenSchema),
Default(DefaultSchema),
Deprecated(DeprecatedSchema),
Literal(String),
#[facet(other)]
Type {
#[facet(tag)]
name: Option<String>,
},
}
#[derive(Facet, Debug, Clone, Default)]
#[facet(rename_all = "camelCase")]
pub struct StringConstraints {
pub min_len: Option<usize>,
pub max_len: Option<usize>,
pub pattern: Option<String>,
}
#[derive(Facet, Debug, Clone, Default)]
pub struct IntConstraints {
pub min: Option<i128>,
pub max: Option<i128>,
}
#[derive(Facet, Debug, Clone, Default)]
pub struct FloatConstraints {
pub min: Option<f64>,
pub max: Option<f64>,
}
#[derive(Facet, Debug, Clone)]
#[facet(metadata_container)]
pub struct ObjectKey {
pub value: Option<String>,
#[facet(metadata = "tag")]
pub tag: Option<String>,
}
impl ObjectKey {
pub fn named(name: impl Into<String>) -> Self {
Self {
value: Some(name.into()),
tag: None,
}
}
pub fn typed(tag: impl Into<String>) -> Self {
Self {
value: None,
tag: Some(tag.into()),
}
}
pub fn unit() -> Self {
Self {
value: None,
tag: Some(String::new()),
}
}
pub fn is_named(&self) -> bool {
self.value.is_some()
}
pub fn is_typed(&self) -> bool {
self.tag.is_some() && !self.tag.as_ref().unwrap().is_empty()
}
pub fn is_unit(&self) -> bool {
self.tag.as_ref().is_some_and(|t| t.is_empty())
}
pub fn name(&self) -> Option<&str> {
self.value.as_deref()
}
pub fn tag_name(&self) -> Option<&str> {
self.tag.as_deref().filter(|t| !t.is_empty())
}
}
impl std::hash::Hash for ObjectKey {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.value.hash(state);
self.tag.hash(state);
}
}
impl PartialEq for ObjectKey {
fn eq(&self, other: &Self) -> bool {
self.value == other.value && self.tag == other.tag
}
}
impl Eq for ObjectKey {}
#[derive(Facet, Debug, Clone)]
#[repr(transparent)]
pub struct ObjectSchema(pub HashMap<Documented<ObjectKey>, Schema>);
#[derive(Facet, Debug, Clone)]
#[repr(transparent)]
pub struct SeqSchema(pub (Documented<Box<Schema>>,));
#[derive(Facet, Debug, Clone)]
#[repr(transparent)]
pub struct TupleSchema(pub Vec<Documented<Schema>>);
#[derive(Facet, Debug, Clone)]
#[repr(transparent)]
pub struct MapSchema(pub Vec<Documented<Schema>>);
#[derive(Facet, Debug, Clone)]
#[repr(transparent)]
pub struct UnionSchema(pub Vec<Documented<Schema>>);
#[derive(Facet, Debug, Clone)]
#[repr(transparent)]
pub struct OptionalSchema(pub (Documented<Box<Schema>>,));
#[derive(Facet, Debug, Clone)]
#[repr(transparent)]
pub struct EnumSchema(pub HashMap<Documented<String>, Schema>);
#[derive(Facet, Debug, Clone)]
#[repr(transparent)]
pub struct OneOfSchema(pub (Documented<Box<Schema>>, Vec<RawStyx>));
#[derive(Facet, Debug, Clone)]
#[repr(transparent)]
pub struct FlattenSchema(pub (Documented<Box<Schema>>,));
#[derive(Debug, Clone, PartialEq, Eq, Facet)]
pub struct RawStyx(pub String);
impl RawStyx {
pub fn new(s: impl Into<String>) -> Self {
RawStyx(s.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for RawStyx {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0)
}
}
#[derive(Facet, Debug, Clone)]
#[repr(transparent)]
pub struct DefaultSchema(pub (RawStyx, Documented<Box<Schema>>));
#[derive(Facet, Debug, Clone)]
#[repr(transparent)]
pub struct DeprecatedSchema(pub (String, Documented<Box<Schema>>));
#[derive(Facet, Debug, Clone)]
#[facet(metadata_container)]
pub struct Documented<T> {
pub value: T,
#[facet(metadata = "doc")]
pub doc: Option<Vec<String>>,
}
impl<T> Documented<T> {
pub fn new(value: T) -> Self {
Self { value, doc: None }
}
pub fn with_doc(value: T, doc: Vec<String>) -> Self {
Self {
value,
doc: Some(doc),
}
}
pub fn with_doc_line(value: T, line: impl Into<String>) -> Self {
Self {
value,
doc: Some(vec![line.into()]),
}
}
pub fn value(&self) -> &T {
&self.value
}
pub fn value_mut(&mut self) -> &mut T {
&mut self.value
}
pub fn into_inner(self) -> T {
self.value
}
pub fn doc(&self) -> Option<&[String]> {
self.doc.as_deref()
}
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Documented<U> {
Documented {
value: f(self.value),
doc: self.doc,
}
}
}
impl<T: Default> Default for Documented<T> {
fn default() -> Self {
Self {
value: T::default(),
doc: None,
}
}
}
impl<T> std::ops::Deref for Documented<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl<T> std::ops::DerefMut for Documented<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.value
}
}
impl<T> From<T> for Documented<T> {
fn from(value: T) -> Self {
Self::new(value)
}
}
impl<T: std::hash::Hash> std::hash::Hash for Documented<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.value.hash(state);
}
}
impl<T: PartialEq> PartialEq for Documented<T> {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
impl<T: Eq> Eq for Documented<T> {}