1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//! Traits used for the library
//!
//! Most users will never implement these manually. See
//! [`Decode`](derive@crate::Decode)` and
//! [`DecodeScalar`](derive@crate::DecodeScalar) for a
//! documentation of the derives to implement these traits.
use std::fmt;

use crate::ast::{SpannedNode, Literal, Value, TypeName};
use crate::span::Spanned;
use crate::errors::DecodeError;
use crate::decode::Context;


/// Trait to decode KDL node from the AST
pub trait Decode<S: ErrorSpan>: Sized {
    /// Decodes the node from the ast
    fn decode_node(node: &SpannedNode<S>, ctx: &mut Context<S>)
        -> Result<Self, DecodeError<S>>;
}

/// Trait to decode children of the KDL node, mostly used for root document
pub trait DecodeChildren<S: ErrorSpan>: Sized {
    /// Decodes from a list of chidren ASTs
    fn decode_children(nodes: &[SpannedNode<S>], ctx: &mut Context<S>)
        -> Result<Self, DecodeError<S>>;
}

/// The trait is implemented for structures that can be used as part of other
/// structs
///
/// The type of field that `#[knuffel(flatten)]` is used for should implement
/// this trait. It is automatically implemented by `#[derive(knuffel::Decode)]`
/// by structures that have only optional properties and children (no
/// arguments).
pub trait DecodePartial<S: ErrorSpan>: Sized {
    /// The method is called when unknown child is encountered by parent
    /// structure
    ///
    /// Returns `Ok(true)` if the child is "consumed" (i.e. stored in this
    /// structure).
    fn insert_child(&mut self, node: &SpannedNode<S>, ctx: &mut Context<S>)
        -> Result<bool, DecodeError<S>>;
    /// The method is called when unknown property is encountered by parent
    /// structure
    ///
    /// Returns `Ok(true)` if the property is "consumed" (i.e. stored in this
    /// structure).
    fn insert_property(&mut self,
                       name: &Spanned<Box<str>, S>, value: &Value<S>,
                       ctx: &mut Context<S>)
        -> Result<bool, DecodeError<S>>;
}

/// The trait that decodes scalar value and checks its type
pub trait DecodeScalar<S: ErrorSpan>: Sized {
    /// Typecheck the value
    ///
    /// This method can only emit errors to the context in type mismatch case.
    /// Errors emitted to the context are considered fatal once the whole data
    /// is processed but non fatal when encountered. So even if there is a type
    /// in type name we can proceed and try parsing actual value.
    fn type_check(type_name: &Option<Spanned<TypeName, S>>,
                  ctx: &mut Context<S>);
    /// Decode value without typecheck
    ///
    /// This can be used by wrappers to parse some know value but use a
    /// different typename (kinda emulated subclassing)
    fn raw_decode(value: &Spanned<Literal, S>, ctx: &mut Context<S>)
        -> Result<Self, DecodeError<S>>;
    /// Decode the value and typecheck
    ///
    /// This should not be overriden and uses `type_check` in combination with
    /// `raw_decode`.
    fn decode(value: &Value<S>, ctx: &mut Context<S>)
        -> Result<Self, DecodeError<S>>
    {
        Self::type_check(&value.type_name, ctx);
        Self::raw_decode(&value.literal, ctx)
    }
}


/// The trait that decodes span into the final structure
pub trait DecodeSpan<S: ErrorSpan>: Sized {
    /// Decode span
    ///
    /// This method can use some extra data (say file name) from the context.
    /// Although, by default context is empty and end users are expected to use
    /// [`parse_with_context`](crate::parse_with_context) to add some values.
    fn decode_span(span: &S, ctx: &mut Context<S>) -> Self;
}

impl<T: ErrorSpan> DecodeSpan<T> for T {
    fn decode_span(span: &T, _: &mut Context<T>) -> Self {
        span.clone()
    }
}

/// Span must implement this trait to be used in the error messages
///
/// Custom span types can be used for this unlike for [`Span`]
pub trait ErrorSpan: Into<miette::SourceSpan>
                     + Clone + fmt::Debug + Send + Sync + 'static {}
impl<T> ErrorSpan for T
    where T: Into<miette::SourceSpan>,
          T: Clone + fmt::Debug + Send + Sync + 'static,
{}


/// Span trait used for parsing source code
///
/// It's sealed because needs some tight interoperation with the parser. Use
/// [`DecodeSpan`] to convert spans whenever needed.
pub trait Span: sealed::Sealed + chumsky::Span + ErrorSpan {}

#[allow(missing_debug_implementations)]
pub(crate) mod sealed {
    pub type Stream<'a, S, T> = chumsky::Stream<
        'a, char, S, Map<std::str::Chars<'a>, T>
    >;

    pub struct Map<I, F>(pub(crate) I, pub(crate) F);

    pub trait SpanTracker {
        type Span;
        fn next_span(&mut self, c: char) -> Self::Span;
    }

    impl<I, T> Iterator for Map<I, T>
         where I: Iterator<Item=char>,
               T: SpanTracker,
    {
        type Item = (char, T::Span);
        fn next(&mut self) -> Option<(char, T::Span)> {
            self.0.next().map(|c| (c, self.1.next_span(c)))
        }
    }

    pub trait Sealed {
        type Tracker: SpanTracker<Span=Self>;
        /// Note assuming ascii, single-width, non-newline chars here
        fn at_start(&self, chars: usize) -> Self;
        fn at_end(&self) -> Self;
        /// Note assuming ascii, single-width, non-newline chars here
        fn before_start(&self, chars: usize) -> Self;
        fn length(&self) -> usize;

        fn stream(s: &str) -> Stream<'_, Self, Self::Tracker>
            where Self: chumsky::Span;
    }
}