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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
//! Structures that represent abstract syntax tree (AST) of the KDL document
//!
//! All of these types are parameterized by the `S` type which is a span type
//! (perhaps implements [`Span`](crate::traits::Span). The idea is that most of
//! the time spans are used for errors (either at parsing time, or at runtime),
//! and original source is somewhere around to show in error snippets. So it's
//! faster to only track byte offsets and calculate line number and column when
//! printing code snippet. So use [`span::Span`](crate::traits::Span).
//!
//! But sometimes you will not have KDL source around, or performance of
//! priting matters (i.e. you log source spans). In that case, span should
//! contain line and column numbers for things, use
//! [`LineSpan`](crate::span::LineSpan) for that.

use std::collections::BTreeMap;
use std::convert::Infallible;
use std::fmt;
use std::str::FromStr;

use crate::span::Spanned;

/// A shortcut for nodes children that includes span of enclosing braces `{..}`
pub type SpannedChildren<S> = Spanned<Vec<SpannedNode<S>>, S>;
/// KDL names with span information are represented using this type
pub type SpannedName<S> = Spanned<Box<str>, S>;
/// A KDL node with span of the whole node (including children)
pub type SpannedNode<S> = Spanned<Node<S>, S>;

/// Single node of the KDL document
#[derive(Debug, Clone)]
#[cfg_attr(feature="minicbor", derive(minicbor::Encode, minicbor::Decode))]
pub struct Node<S> {
    /// A type name if specified in parenthesis
    #[cfg_attr(feature="minicbor", n(0))]
    pub type_name: Option<Spanned<TypeName, S>>,
    /// A node name
    #[cfg_attr(feature="minicbor", n(1))]
    pub node_name: SpannedName<S>,
    /// Positional arguments
    #[cfg_attr(feature="minicbor", n(2))]
    pub arguments: Vec<Value<S>>,
    /// Named properties
    #[cfg_attr(feature="minicbor", n(3))]
    pub properties: BTreeMap<SpannedName<S>, Value<S>>,
    /// Node's children. This field is not none if there are braces `{..}`
    #[cfg_attr(feature="minicbor", n(4))]
    pub children: Option<SpannedChildren<S>>,
}

/// KDL document root
#[derive(Debug, Clone)]
#[cfg_attr(feature="minicbor", derive(minicbor::Encode, minicbor::Decode))]
pub struct Document<S> {
    /// Nodes of the document
    #[cfg_attr(feature="minicbor", n(0))]
    pub nodes: Vec<SpannedNode<S>>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature="minicbor", derive(minicbor::Encode, minicbor::Decode))]
#[cfg_attr(feature="minicbor", cbor(index_only))]
pub(crate) enum Radix {
    #[cfg_attr(feature="minicbor", n(2))]
    Bin,
    #[cfg_attr(feature="minicbor", n(16))]
    Hex,
    #[cfg_attr(feature="minicbor", n(8))]
    Oct,
    #[cfg_attr(feature="minicbor", n(10))]
    Dec,
}

/// Potentially unlimited size integer value
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature="minicbor", derive(minicbor::Encode, minicbor::Decode))]
pub struct Integer(
    #[cfg_attr(feature="minicbor", n(0))]
    pub(crate) Radix,
    #[cfg_attr(feature="minicbor", n(1))]
    pub(crate) Box<str>,
);

/// Potentially unlimited precision decimal value
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature="minicbor", derive(minicbor::Encode, minicbor::Decode))]
#[cfg_attr(feature="minicbor", cbor(transparent))]
pub struct Decimal(
    #[cfg_attr(feature="minicbor", n(0))]
    pub(crate) Box<str>,
);

/// Possibly typed KDL scalar value
#[derive(Debug, Clone)]
#[cfg_attr(feature="minicbor", derive(minicbor::Encode, minicbor::Decode))]
pub struct Value<S> {
    /// A type name if specified in parenthesis
    #[cfg_attr(feature="minicbor", n(0))]
    pub type_name: Option<Spanned<TypeName, S>>,
    /// The actual value literal
    #[cfg_attr(feature="minicbor", n(1))]
    pub literal: Spanned<Literal, S>,
}

/// Type identifier
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeName(TypeNameInner);

#[derive(Debug, Clone, PartialEq, Eq)]
enum TypeNameInner {
    Builtin(BuiltinType),
    Custom(Box<str>),
}

/// Known type identifier described by the KDL specification
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BuiltinType {
    /// `u8`: 8-bit unsigned integer type
    U8,
    /// `i8`: 8-bit signed integer type
    I8,
    /// `u16`: 16-bit unsigned integer type
    U16,
    /// `i16`: 16-bit signed integer type
    I16,
    /// `u32`: 32-bit unsigned integer type
    U32,
    /// `i32`: 32-bit signed integer type
    I32,
    /// `u64`: 64-bit unsigned integer type
    U64,
    /// `i64`: 64-bit signed integer type
    I64,
    /// `usize`: platform-dependent unsigned integer type
    Usize,
    /// `isize`: platform-dependent signed integer type
    Isize,
    /// `base64` denotes binary bytes type encoded using base64 encoding
    Base64,
}

/// Scalar KDL value
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature="minicbor", derive(minicbor::Encode, minicbor::Decode))]
pub enum Literal {
    /// Null value
    #[cfg_attr(feature="minicbor", n(0))]
    Null,
    /// Boolean value
    #[cfg_attr(feature="minicbor", n(1))]
    Bool(
        #[cfg_attr(feature="minicbor", n(0))]
        bool
    ),
    /// Integer value
    #[cfg_attr(feature="minicbor", n(2))]
    Int(
        #[cfg_attr(feature="minicbor", n(0))]
        Integer
    ),
    /// Decimal (or floating point) value
    #[cfg_attr(feature="minicbor", n(3))]
    Decimal(
        #[cfg_attr(feature="minicbor", n(0))]
        Decimal
    ),
    /// String value
    #[cfg_attr(feature="minicbor", n(4))]
    String(
        #[cfg_attr(feature="minicbor", n(0))]
        Box<str>
    ),
}

impl<S> Node<S> {
    /// Returns node children
    pub fn children(&self)
        -> impl Iterator<Item=&Spanned<Node<S>, S>> +
                ExactSizeIterator
    {
        self.children.as_ref().map(|c| c.iter()).unwrap_or_else(|| [].iter())
    }
}

impl BuiltinType {
    /// Returns string representation of the builtin type as defined by KDL
    /// specification
    pub const fn as_str(&self) -> &'static str {
        use BuiltinType::*;
        match self {
            U8 => "u8",
            I8 => "i8",
            U16 => "u16",
            I16 => "i16",
            U32 => "u32",
            I32 => "i32",
            U64 => "u64",
            I64 => "i64",
            Usize => "usize",
            Isize => "isize",
            Base64 => "base64",
        }
    }
    /// Returns `TypeName` structure for the builtin type
    pub const fn as_type(self) -> TypeName {
        TypeName(TypeNameInner::Builtin(self))
    }
}

impl TypeName {
    pub(crate) fn from_string(val: Box<str>) -> TypeName {
        use TypeNameInner::*;

        match BuiltinType::from_str(&val[..]) {
            Ok(b) => TypeName(Builtin(b)),
            _ => TypeName(Custom(val)),
        }
    }
    /// Returns string represenation of the type name
    pub fn as_str(&self) -> &str {
        match &self.0 {
            TypeNameInner::Builtin(t) => t.as_str(),
            TypeNameInner::Custom(t) => t.as_ref(),
        }
    }
    /// Returns `BuiltinType` enum for the type if typename matches builtin
    /// type
    ///
    /// Note: checking for `is_none()` is not forward compatible. In future we
    /// may add additional builtin type. Always use `as_str` for types that
    /// aren't yet builtin.
    pub const fn as_builtin(&self) -> Option<&BuiltinType> {
        match &self.0 {
            TypeNameInner::Builtin(t) => Some(t),
            TypeNameInner::Custom(_) => None,
        }
    }
}

impl FromStr for BuiltinType {
    type Err = ();
    fn from_str(s: &str) -> Result<BuiltinType, ()> {
        use BuiltinType::*;
        match s {
            "u8" => Ok(U8),
            "i8" => Ok(I8),
            "u16" => Ok(U16),
            "i16" => Ok(I16),
            "u32" => Ok(U32),
            "i32" => Ok(I32),
            "u64" => Ok(U64),
            "i64" => Ok(I64),
            "base64" => Ok(Base64),
            _ => Err(())
        }
    }
}

impl FromStr for TypeName {
    type Err = Infallible;
    fn from_str(s: &str) -> Result<TypeName, Infallible> {
        use TypeNameInner::*;
        match BuiltinType::from_str(s) {
            Ok(b) => Ok(TypeName(Builtin(b))),
            Err(()) => Ok(TypeName(Custom(s.into()))),
        }
    }
}

impl std::ops::Deref for TypeName {
    type Target = str;
    fn deref(&self) -> &str {
        self.as_str()
    }
}

impl fmt::Display for TypeName {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_str().fmt(f)
    }
}

impl Into<TypeName> for BuiltinType {
    fn into(self) -> TypeName {
        self.as_type()
    }
}

#[cfg(feature="minicbor")]
mod cbor {
    use super::TypeName;
    use minicbor::{Decoder, Encoder};
    use minicbor::encode::Encode;
    use minicbor::decode::Decode;

    impl<'d> Decode<'d> for TypeName {
        fn decode(d: &mut Decoder<'d>)
            -> Result<Self, minicbor::decode::Error>
        {
            d.str().and_then(|s| s.parse().map_err(|e| match e {}))
        }
    }
    impl Encode for TypeName {
        fn encode<W>(&self, e: &mut Encoder<W>)
            -> Result<(), minicbor::encode::Error<W::Error>>
            where W: minicbor::encode::write::Write
        {
            self.as_str().encode(e)
        }
    }
}