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
//! Components of a JSON API document.

mod convert;
mod ident;
mod link;
mod object;
mod relationship;
mod specification;

mod error;

use std::iter::FromIterator;

use serde::de::DeserializeOwned;
use serde::ser::Serialize;

use sealed::Sealed;
use value::{Key, Map, Set, Value};

pub use self::convert::*;
pub use self::error::{ErrorObject, ErrorSource};
pub use self::ident::Identifier;
pub use self::link::Link;
pub use self::object::{NewObject, Object};
pub use self::relationship::Relationship;
pub use self::specification::{JsonApi, Version};

/// A marker trait used to indicate that a type can be the primary data for a
/// document.
pub trait PrimaryData: DeserializeOwned + Sealed + Serialize {
    #[doc(hidden)]
    fn flatten(self, &Set<Object>) -> Value;
}

/// Represents a compound JSON API document.
///
/// For more information, check out the *[document structure]* section of the JSON API
/// specification.
///
/// [document structure]: https://goo.gl/CXTNmt
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(bound = "T: PrimaryData", untagged)]
pub enum Document<T: PrimaryData> {
    /// Does not contain errors.
    Ok {
        /// The primary data of the document. For more information, check out the
        /// *[top level]* section of the JSON API specification.
        ///
        /// [top level]: https://goo.gl/fQdYgo
        data: Data<T>,

        /// Included resources, resolved from the `include` query parameter of a client
        /// request.
        #[serde(default, skip_serializing_if = "Set::is_empty")]
        included: Set<Object>,

        /// Information about this implementation of the specification that the
        /// document was created with. For more information, check out the *[JSON API
        /// object]* section of the JSON API specification.
        ///
        /// [JSON API object]: https://goo.gl/hZUcEt
        #[serde(default)]
        jsonapi: JsonApi,

        /// Contains relevant links. If this value of this field is empty, it will not be
        /// serialized. For more information, check out the *[links]* section of the JSON
        /// API specification.
        ///
        /// [links]: https://goo.gl/E4E6Vt
        #[serde(default, skip_serializing_if = "Map::is_empty")]
        links: Map<Key, Link>,

        /// Non-standard meta information. If this value of this field is empty, it will
        /// not be serialized. For more information, check out the *[meta
        /// information]* section of the JSON API specification.
        ///
        /// [meta information]: https://goo.gl/LyrGF8
        #[serde(default, skip_serializing_if = "Map::is_empty")]
        meta: Map,
    },

    /// Contains 1 or more error(s).
    Err {
        errors: Vec<ErrorObject>,

        #[serde(default)]
        jsonapi: JsonApi,

        #[serde(default, skip_serializing_if = "Map::is_empty")]
        links: Map<Key, Link>,

        #[serde(default, skip_serializing_if = "Map::is_empty")]
        meta: Map,
    },
}

impl<T: PrimaryData> Document<T> {
    /// Returns `true` if the document does not contain any errors.
    pub fn is_ok(&self) -> bool {
        match *self {
            Document::Ok { .. } => true,
            Document::Err { .. } => false,
        }
    }

    /// Returns `true` if the document contains 1 or more error(s).
    pub fn is_err(&self) -> bool {
        match *self {
            Document::Ok { .. } => true,
            Document::Err { .. } => false,
        }
    }
}

/// Describes the data of a document or resource linkage.
///
/// For more information, check out the *[top level]* section of the JSON API
/// specification.
///
/// [top level]: https://goo.gl/fQdYgo
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(bound = "T: PrimaryData", untagged)]
pub enum Data<T: PrimaryData> {
    /// A collection of `T`. Used for requests that target resource collections.
    Collection(Vec<T>),

    /// An optional `T`. Used for requests that target single resources.
    Member(Box<Option<T>>),
}

impl<T: PrimaryData> From<Option<T>> for Data<T> {
    fn from(value: Option<T>) -> Self {
        Data::Member(Box::new(value))
    }
}

impl<T: PrimaryData> From<Vec<T>> for Data<T> {
    fn from(value: Vec<T>) -> Self {
        Data::Collection(value)
    }
}

impl<T: PrimaryData> From<T> for Data<T> {
    fn from(value: T) -> Self {
        Data::Member(Box::new(Some(value)))
    }
}

impl<T: PrimaryData> FromIterator<T> for Data<T> {
    fn from_iter<I>(iter: I) -> Self
    where
        I: IntoIterator<Item = T>,
    {
        Data::Collection(Vec::from_iter(iter))
    }
}