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