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
//! A crate providing generalised value traits for working with
//! `JSONesque` values.
#![warn(unused_extern_crates)]
#![cfg_attr(feature = "portable", feature(portable_simd))]
#![deny(
    clippy::all,
    clippy::unwrap_used,
    clippy::unnecessary_unwrap,
    clippy::pedantic,
    missing_docs
)]
// We might want to revisit inline_always
#![allow(clippy::module_name_repetitions)]

#[cfg(all(feature = "128bit", feature = "c-abi"))]
compile_error!(
    "Combining the features `128bit` and `c-abi` is impossible because i128's \
    ABI is unstable (see \
    https://github.com/rust-lang/unsafe-code-guidelines/issues/119). Please \
    use only one of them in order to compile this crate. If you don't know \
    where this error is coming from, it's possible that you depend on \
    value-trait twice indirectly, once with the `c-abi` feature, and once with \
    the `128bit` feature, and that they have been merged by Cargo."
);

use std::borrow::Cow;
use std::fmt;

mod array;
/// Traits for serializing JSON
pub mod generator;
mod impls;
mod node;
mod object;
mod option;
/// Prelude for traits
pub mod prelude;

/// Traits that provide basic interactions, they do have no auto-implementations
pub mod base;

/// Traits that have derived implementations relying on `base` traitsa
pub mod derived;

pub use node::StaticNode;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// An access error for `ValueType`
pub enum AccessError {
    /// An access attempt to a Value was made under the
    /// assumption that it is an Object - the Value however
    /// wasn't.
    NotAnObject,
    /// An access attempt to a Value was made under the
    /// assumption that it is an Array - the Value however
    /// wasn't.
    NotAnArray,
}

#[cfg(not(tarpaulin_include))]
impl fmt::Display for AccessError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::NotAnArray => write!(f, "The value is not an array"),
            Self::NotAnObject => write!(f, "The value is not an object"),
        }
    }
}
impl std::error::Error for AccessError {}

/// Extended types that have no native representation in JSON
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExtendedValueType {
    /// A 32 bit signed integer value
    I32,
    /// A 16 bit signed integer value
    I16,
    /// A 8 bit signed integer value
    I8,
    /// A 32 bit unsigned integer value
    U32,
    /// A 16 bit unsigned integer value
    U16,
    /// A 8 bit unsigned integer value
    U8,
    /// A useize value
    Usize,
    /// A 32 bit floating point value
    F32,
    /// A single utf-8 character
    Char,
    /// Not a value at all
    None,
}

impl Default for ExtendedValueType {
    fn default() -> Self {
        Self::None
    }
}

impl fmt::Display for ExtendedValueType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::I32 => write!(f, "i32"),
            Self::I16 => write!(f, "i16"),
            Self::I8 => write!(f, "i8"),
            Self::U32 => write!(f, "u32"),
            Self::U16 => write!(f, "u16"),
            Self::U8 => write!(f, "u8"),
            Self::Usize => write!(f, "usize"),
            Self::F32 => write!(f, "f32"),
            Self::Char => write!(f, "char"),
            Self::None => write!(f, "none"),
        }
    }
}

/// Types of JSON values
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ValueType {
    /// null
    Null,
    /// a boolean
    Bool,
    /// a signed integer type
    I64,
    /// a 128 bit signed integer
    I128,
    /// a unsigned integer type
    U64,
    /// a 128 bit unsigned integer
    U128,
    /// a float type
    F64,
    /// a string type
    String,
    /// an array
    Array,
    /// an object
    Object,
    /// Extended types that do not have a real representation in JSON
    Extended(ExtendedValueType),
    #[cfg(feature = "custom-types")]
    /// a custom type
    Custom(&'static str),
}
impl fmt::Display for ValueType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Null => write!(f, "null"),
            Self::Bool => write!(f, "bool"),
            Self::I64 => write!(f, "i64"),
            Self::I128 => write!(f, "i128"),
            Self::U64 => write!(f, "u64"),
            Self::U128 => write!(f, "u128"),
            Self::F64 => write!(f, "f64"),
            Self::String => write!(f, "string"),
            Self::Array => write!(f, "array"),
            Self::Object => write!(f, "object"),
            Self::Extended(ty) => write!(f, "{ty}"),
            #[cfg(feature = "custom-types")]
            Self::Custom(name) => write!(f, "{name}"),
        }
    }
}

impl Default for ValueType {
    fn default() -> Self {
        Self::Null
    }
}

#[allow(clippy::trait_duplication_in_bounds)] // This is a bug From<()> is counted as duplicate
/// Support of builder methods for traits.
pub trait ValueBuilder<'input>:
    Default
    + From<StaticNode>
    + From<i8>
    + From<i16>
    + From<i32>
    + From<i64>
    + From<u8>
    + From<u16>
    + From<u32>
    + From<u64>
    + From<f32>
    + From<f64>
    + From<bool>
    + From<()>
    + From<String>
    + From<&'input str>
    + From<Cow<'input, str>>
{
    /// Returns an empty array with a given capacity
    fn array_with_capacity(capacity: usize) -> Self;
    /// Returns an empty object with a given capacity
    fn object_with_capacity(capacity: usize) -> Self;
    /// Returns an empty array
    #[must_use]
    fn array() -> Self {
        Self::array_with_capacity(0)
    }
    /// Returns an empty object
    #[must_use]
    fn object() -> Self {
        Self::object_with_capacity(0)
    }
    /// Returns anull value
    fn null() -> Self;
}

/// A type error thrown by the `try_*` functions
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TryTypeError {
    /// The expected value type
    pub expected: ValueType,
    /// The actual value type
    pub got: ValueType,
}

impl std::fmt::Display for TryTypeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Expected type {}, got {}", self.expected, self.got)
    }
}

impl std::error::Error for TryTypeError {}

// /// The `Value` exposes common interface for values, this allows using both/// `BorrowedValue` and `OwnedValue` nearly interchangeable
// pub trait Value:
//     Sized
//     + Index<usize>
//     + PartialEq<i8>
//     + PartialEq<i16>
//     + PartialEq<i32>
//     + PartialEq<i64>
//     + PartialEq<i128>
//     + PartialEq<u8>
//     + PartialEq<u16>
//     + PartialEq<u32>
//     + PartialEq<u64>
//     + PartialEq<u128>
//     + PartialEq<f32>
//     + PartialEq<f64>
//     + PartialEq<String>
//     + PartialEq<bool>
//     + PartialEq<()>
//     + derived::ValueTryAsScalar
//     + base::ValueAsContainer
// {
// }