payjp_types/
expandable.rs1use serde::Serialize;
2
3use crate::Object;
4
5#[derive(Clone, Debug, Serialize)] #[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
12#[serde(untagged)]
13pub enum Expandable<T: Object> {
14 Id(T::Id),
16 Object(Box<T>),
18}
19
20impl<T: Object> Default for Expandable<T>
21where
22 T::Id: Default,
23{
24 fn default() -> Self {
25 Expandable::Id(Default::default())
26 }
27}
28
29impl<T: Object> Expandable<T> {
30 pub fn is_object(&self) -> bool {
32 match self {
33 Expandable::Id(_) => false,
34 Expandable::Object(_) => true,
35 }
36 }
37
38 pub fn as_object(&self) -> Option<&T> {
40 match self {
41 Expandable::Id(_) => None,
42 Expandable::Object(obj) => Some(obj),
43 }
44 }
45
46 pub fn into_object(self) -> Option<T> {
48 match self {
49 Expandable::Id(_) => None,
50 Expandable::Object(obj) => Some(*obj),
51 }
52 }
53
54 pub fn into_id(self) -> T::Id {
56 match self {
57 Expandable::Id(id) => id,
58 Expandable::Object(obj) => obj.into_id(),
59 }
60 }
61
62 pub fn id(&self) -> &T::Id {
64 match self {
65 Expandable::Id(id) => id,
66 Expandable::Object(obj) => obj.id(),
67 }
68 }
69}
70
71#[doc(hidden)]
72mod miniserde {
73 use miniserde::de::{Map, Visitor};
74 use miniserde::json::Value;
75 use miniserde::{make_place, Deserialize};
76
77 use crate::miniserde_helpers::FromValueOpt;
78 use crate::{Expandable, FromCursor, Object};
79 make_place!(Place);
80
81 pub trait MapBuilder {
83 type Out;
84
85 fn deser_default() -> Self;
89
90 fn key(&mut self, k: &str) -> miniserde::Result<&mut dyn Visitor>;
91
92 fn take_out(&mut self) -> Option<Self::Out>
93 where
94 Self::Out: Sized;
95 }
96
97 pub trait ObjectDeser
99 where
100 Self: Sized,
101 {
102 type Builder: MapBuilder<Out = Self>;
103 }
104
105 impl<T> Deserialize for Expandable<T>
106 where
107 T: Object + Deserialize + ObjectDeser,
108 {
109 fn begin(out: &mut Option<Self>) -> &mut dyn Visitor {
110 Place::new(out)
111 }
112 }
113
114 struct ExpandableBuilder<'a, T: ObjectDeser + Object> {
115 out: &'a mut Option<Expandable<T>>,
116 builder: T::Builder,
117 }
118
119 impl<'a, T> Map for ExpandableBuilder<'a, T>
120 where
121 T: ObjectDeser + Object,
122 {
123 fn key(&mut self, k: &str) -> miniserde::Result<&mut dyn Visitor> {
124 self.builder.key(k)
125 }
126
127 fn finish(&mut self) -> miniserde::Result<()> {
128 let finalized = self.builder.take_out().ok_or(miniserde::Error)?;
129 *self.out = Some(Expandable::Object(Box::new(finalized)));
130 Ok(())
131 }
132 }
133
134 impl<T> Visitor for Place<Expandable<T>>
135 where
136 T: Object + ObjectDeser,
137 {
138 fn string(&mut self, s: &str) -> miniserde::Result<()> {
139 let val = T::Id::from_cursor(s).ok_or(miniserde::Error)?;
140 self.out = Some(Expandable::Id(val));
141 Ok(())
142 }
143
144 fn map(&mut self) -> miniserde::Result<Box<dyn Map + '_>> {
145 Ok(Box::new(ExpandableBuilder {
146 out: &mut self.out,
147 builder: T::Builder::deser_default(),
148 }))
149 }
150 }
151
152 impl<T: FromValueOpt + Object> FromValueOpt for Expandable<T> {
153 fn from_value(v: Value) -> Option<Self> {
154 match v {
155 Value::String(id) => Some(Self::Id(T::Id::from_cursor(&id)?)),
156 Value::Object(obj) => {
157 Some(Self::Object(Box::new(T::from_value(Value::Object(obj))?)))
158 }
159 _ => None,
160 }
161 }
162 }
163}
164
165pub use miniserde::{MapBuilder, ObjectDeser};