extern crate alloc;
use alloc::borrow::Cow;
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::fmt;
use facet_reflect::Span;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum FieldLocationHint {
#[default]
KeyValue,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FieldKey<'de> {
Name(Cow<'de, str>),
Full(Box<FullFieldKey<'de>>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FullFieldKey<'de> {
pub name: Option<Cow<'de, str>>,
pub location: FieldLocationHint,
pub meta: ValueMeta<'de>,
}
impl<'de> FieldKey<'de> {
#[inline]
pub fn new(name: impl Into<Cow<'de, str>>, _location: FieldLocationHint) -> Self {
FieldKey::Name(name.into())
}
pub fn with_doc(
name: impl Into<Cow<'de, str>>,
location: FieldLocationHint,
doc: Vec<Cow<'de, str>>,
) -> Self {
if doc.is_empty() {
FieldKey::Name(name.into())
} else {
FieldKey::Full(Box::new(FullFieldKey {
name: Some(name.into()),
location,
meta: ValueMeta::builder().doc(doc).build(),
}))
}
}
pub fn tagged(tag: impl Into<Cow<'de, str>>, location: FieldLocationHint) -> Self {
FieldKey::Full(Box::new(FullFieldKey {
name: None,
location,
meta: ValueMeta::builder().tag(tag.into()).build(),
}))
}
pub fn tagged_with_doc(
tag: impl Into<Cow<'de, str>>,
location: FieldLocationHint,
doc: Vec<Cow<'de, str>>,
) -> Self {
FieldKey::Full(Box::new(FullFieldKey {
name: None,
location,
meta: ValueMeta::builder()
.tag(tag.into())
.maybe_doc(Some(doc))
.build(),
}))
}
pub fn tagged_with_name(
tag: impl Into<Cow<'de, str>>,
name: impl Into<Cow<'de, str>>,
location: FieldLocationHint,
) -> Self {
FieldKey::Full(Box::new(FullFieldKey {
name: Some(name.into()),
location,
meta: ValueMeta::builder().tag(tag.into()).build(),
}))
}
pub fn tagged_with_name_and_doc(
tag: impl Into<Cow<'de, str>>,
name: impl Into<Cow<'de, str>>,
location: FieldLocationHint,
doc: Vec<Cow<'de, str>>,
) -> Self {
FieldKey::Full(Box::new(FullFieldKey {
name: Some(name.into()),
location,
meta: ValueMeta::builder()
.tag(tag.into())
.maybe_doc(Some(doc))
.build(),
}))
}
pub fn unit(location: FieldLocationHint) -> Self {
FieldKey::Full(Box::new(FullFieldKey {
name: None,
location,
meta: ValueMeta::builder().tag(Cow::Borrowed("")).build(),
}))
}
pub fn unit_with_doc(location: FieldLocationHint, doc: Vec<Cow<'de, str>>) -> Self {
FieldKey::Full(Box::new(FullFieldKey {
name: None,
location,
meta: ValueMeta::builder()
.tag(Cow::Borrowed(""))
.maybe_doc(Some(doc))
.build(),
}))
}
#[inline]
pub fn name(&self) -> Option<&Cow<'de, str>> {
match self {
FieldKey::Name(name) => Some(name),
FieldKey::Full(full) => full.name.as_ref(),
}
}
#[inline]
pub fn doc(&self) -> Option<&[Cow<'de, str>]> {
match self {
FieldKey::Name(_) => None,
FieldKey::Full(full) => full.meta.doc(),
}
}
#[inline]
pub fn tag(&self) -> Option<&Cow<'de, str>> {
match self {
FieldKey::Name(_) => None,
FieldKey::Full(full) => full.meta.tag(),
}
}
#[inline]
pub fn meta(&self) -> Option<&ValueMeta<'de>> {
match self {
FieldKey::Name(_) => None,
FieldKey::Full(full) => Some(&full.meta),
}
}
#[inline]
pub fn location(&self) -> FieldLocationHint {
match self {
FieldKey::Name(_) => FieldLocationHint::KeyValue,
FieldKey::Full(full) => full.location,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ContainerKind {
Object,
Array,
}
impl ContainerKind {
pub const fn name(self) -> &'static str {
match self {
ContainerKind::Object => "object",
ContainerKind::Array => "array",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ValueTypeHint {
Null,
Bool,
Number,
String,
Bytes,
Sequence,
Map,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ScalarValue<'de> {
Unit,
Null,
Bool(bool),
Char(char),
I64(i64),
U64(u64),
I128(i128),
U128(u128),
F64(f64),
Str(Cow<'de, str>),
Bytes(Cow<'de, [u8]>),
}
impl<'de> ScalarValue<'de> {
pub fn to_string_value(&self) -> Option<alloc::string::String> {
match self {
ScalarValue::Str(s) => Some(s.to_string()),
ScalarValue::Bool(b) => Some(b.to_string()),
ScalarValue::I64(i) => Some(i.to_string()),
ScalarValue::U64(u) => Some(u.to_string()),
ScalarValue::I128(i) => Some(i.to_string()),
ScalarValue::U128(u) => Some(u.to_string()),
ScalarValue::F64(f) => Some(f.to_string()),
ScalarValue::Char(c) => Some(c.to_string()),
ScalarValue::Null => Some("null".to_string()),
ScalarValue::Unit => Some(alloc::string::String::new()),
ScalarValue::Bytes(_) => None,
}
}
pub fn to_display_string(&self) -> alloc::string::String {
match self {
ScalarValue::Str(s) => s.to_string(),
ScalarValue::Bool(b) => alloc::format!("bool({})", b),
ScalarValue::I64(i) => alloc::format!("i64({})", i),
ScalarValue::U64(u) => alloc::format!("u64({})", u),
ScalarValue::I128(i) => alloc::format!("i128({})", i),
ScalarValue::U128(u) => alloc::format!("u128({})", u),
ScalarValue::F64(f) => alloc::format!("f64({})", f),
ScalarValue::Char(c) => alloc::format!("char({})", c),
ScalarValue::Bytes(_) => "bytes".to_string(),
ScalarValue::Null => "null".to_string(),
ScalarValue::Unit => "unit".to_string(),
}
}
#[inline]
pub const fn kind_name(&self) -> &'static str {
match self {
ScalarValue::Unit => "unit",
ScalarValue::Null => "null",
ScalarValue::Bool(_) => "bool",
ScalarValue::Char(_) => "char",
ScalarValue::I64(_) => "i64",
ScalarValue::U64(_) => "u64",
ScalarValue::I128(_) => "i128",
ScalarValue::U128(_) => "u128",
ScalarValue::F64(_) => "f64",
ScalarValue::Str(_) => "string",
ScalarValue::Bytes(_) => "bytes",
}
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
#[non_exhaustive]
pub struct ValueMeta<'a> {
doc: Option<Vec<Cow<'a, str>>>,
tag: Option<Cow<'a, str>>,
span: Option<Span>,
}
impl<'a> ValueMeta<'a> {
pub const fn empty() -> Self {
Self {
doc: None,
tag: None,
span: None,
}
}
#[inline]
pub fn builder() -> ValueMetaBuilder<'a> {
ValueMetaBuilder::default()
}
#[inline]
pub fn doc(&self) -> Option<&[Cow<'a, str>]> {
self.doc.as_deref()
}
#[inline]
pub fn tag(&self) -> Option<&Cow<'a, str>> {
self.tag.as_ref()
}
#[inline]
pub fn span(&self) -> Option<Span> {
self.span
}
#[inline]
pub fn is_empty(&self) -> bool {
self.doc.is_none() && self.tag.is_none() && self.span.is_none()
}
}
#[derive(Debug, Clone, Default)]
pub struct ValueMetaBuilder<'a> {
doc: Option<Vec<Cow<'a, str>>>,
tag: Option<Cow<'a, str>>,
span: Option<Span>,
}
impl<'a> ValueMetaBuilder<'a> {
#[inline]
pub fn doc(mut self, doc: Vec<Cow<'a, str>>) -> Self {
if !doc.is_empty() {
self.doc = Some(doc);
}
self
}
#[inline]
pub fn maybe_doc(mut self, doc: Option<Vec<Cow<'a, str>>>) -> Self {
if let Some(d) = doc
&& !d.is_empty()
{
self.doc = Some(d);
}
self
}
#[inline]
pub fn tag(mut self, tag: Cow<'a, str>) -> Self {
self.tag = Some(tag);
self
}
#[inline]
pub fn maybe_tag(mut self, tag: Option<Cow<'a, str>>) -> Self {
if tag.is_some() {
self.tag = tag;
}
self
}
#[inline]
pub fn span(mut self, span: Span) -> Self {
self.span = Some(span);
self
}
#[inline]
pub fn build(self) -> ValueMeta<'a> {
ValueMeta {
doc: self.doc,
tag: self.tag,
span: self.span,
}
}
}
#[derive(Clone, PartialEq)]
pub struct ParseEvent<'de> {
pub kind: ParseEventKind<'de>,
pub span: facet_reflect::Span,
pub meta: Option<ValueMeta<'de>>,
}
impl<'de> ParseEvent<'de> {
#[inline]
pub fn new(kind: ParseEventKind<'de>, span: facet_reflect::Span) -> Self {
Self {
kind,
span,
meta: None,
}
}
#[inline]
pub fn with_meta(
mut self,
f: impl FnOnce(ValueMetaBuilder<'de>) -> ValueMetaBuilder<'de>,
) -> Self {
let meta = f(ValueMetaBuilder::default()).build();
if !meta.is_empty() {
self.meta = Some(meta);
}
self
}
}
#[derive(Clone, PartialEq)]
pub enum ParseEventKind<'de> {
StructStart(ContainerKind),
StructEnd,
FieldKey(FieldKey<'de>),
OrderedField,
SequenceStart(ContainerKind),
SequenceEnd,
Scalar(ScalarValue<'de>),
VariantTag(Option<&'de str>),
}
impl<'de> fmt::Debug for ParseEvent<'de> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}@{}", self.kind, self.span)
}
}
impl<'de> fmt::Debug for ParseEventKind<'de> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ParseEventKind::StructStart(kind) => f.debug_tuple("StructStart").field(kind).finish(),
ParseEventKind::StructEnd => f.write_str("StructEnd"),
ParseEventKind::FieldKey(key) => f.debug_tuple("FieldKey").field(key).finish(),
ParseEventKind::OrderedField => f.write_str("OrderedField"),
ParseEventKind::SequenceStart(kind) => {
f.debug_tuple("SequenceStart").field(kind).finish()
}
ParseEventKind::SequenceEnd => f.write_str("SequenceEnd"),
ParseEventKind::Scalar(value) => f.debug_tuple("Scalar").field(value).finish(),
ParseEventKind::VariantTag(tag) => f.debug_tuple("VariantTag").field(tag).finish(),
}
}
}
impl ParseEvent<'_> {
#[inline]
pub const fn kind_name(&self) -> &'static str {
self.kind.kind_name()
}
}
impl ParseEventKind<'_> {
#[inline]
pub const fn kind_name(&self) -> &'static str {
match self {
ParseEventKind::StructStart(_) => "struct start",
ParseEventKind::StructEnd => "struct end",
ParseEventKind::FieldKey(_) => "field key",
ParseEventKind::OrderedField => "ordered field",
ParseEventKind::SequenceStart(_) => "sequence start",
ParseEventKind::SequenceEnd => "sequence end",
ParseEventKind::Scalar(_) => "scalar",
ParseEventKind::VariantTag(_) => "variant tag",
}
}
}