zvariant/
maybe.rs

1use serde::ser::{Serialize, Serializer};
2use std::fmt::Display;
3
4use crate::{value_display_fmt, Error, Signature, Type, Value};
5
6/// A helper type to wrap `Option<T>` (GVariant's Maybe type) in [`Value`].
7///
8/// API is provided to convert from, and to `Option<T>`.
9///
10/// [`Value`]: enum.Value.html
11#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
12pub struct Maybe<'a> {
13    value: Box<Option<Value<'a>>>,
14    signature: Signature,
15}
16
17impl<'a> Maybe<'a> {
18    /// Get a reference to underlying value.
19    pub fn inner(&self) -> &Option<Value<'a>> {
20        &self.value
21    }
22
23    /// Create a new Just (Some) `Maybe`.
24    pub fn just(value: Value<'a>) -> Self {
25        let value_signature = value.value_signature().clone();
26        let signature = Signature::maybe(value_signature);
27        Self {
28            signature,
29            value: Box::new(Some(value)),
30        }
31    }
32
33    pub(crate) fn just_full_signature(value: Value<'a>, signature: &Signature) -> Self {
34        Self {
35            signature: signature.clone(),
36            value: Box::new(Some(value)),
37        }
38    }
39
40    /// Create a new Nothing (None) `Maybe`, given the signature of the type.
41    pub fn nothing(value_signature: &Signature) -> Self {
42        let signature = Signature::maybe(value_signature.clone());
43        Self {
44            signature,
45            value: Box::new(None),
46        }
47    }
48
49    pub(crate) fn nothing_full_signature(signature: &Signature) -> Self {
50        Self {
51            signature: signature.clone(),
52            value: Box::new(None),
53        }
54    }
55
56    /// Get the inner value as a concrete type
57    pub fn get<T>(&'a self) -> core::result::Result<Option<T>, Error>
58    where
59        T: ?Sized + TryFrom<&'a Value<'a>>,
60        <T as TryFrom<&'a Value<'a>>>::Error: Into<crate::Error>,
61    {
62        self.value
63            .as_ref()
64            .as_ref()
65            .map(|v| v.downcast_ref())
66            .transpose()
67    }
68
69    /// Get the signature of `Maybe`.
70    pub fn signature(&self) -> &Signature {
71        &self.signature
72    }
73
74    /// Get the signature of the potential value in the `Maybe`.
75    pub fn value_signature(&self) -> &Signature {
76        match self.signature() {
77            Signature::Maybe(signature) => signature,
78            _ => unreachable!("Invalid `Maybe` signature"),
79        }
80    }
81
82    pub(crate) fn try_to_owned(&self) -> crate::Result<Maybe<'static>> {
83        Ok(Maybe {
84            value: Box::new(
85                self.value
86                    .as_ref()
87                    .as_ref()
88                    .map(|v| v.try_to_owned().map(Into::into))
89                    .transpose()?,
90            ),
91            signature: self.signature.clone(),
92        })
93    }
94
95    /// Attempt to clone `self`.
96    pub fn try_clone(&self) -> Result<Self, crate::Error> {
97        Ok(Maybe {
98            value: Box::new(
99                self.value
100                    .as_ref()
101                    .as_ref()
102                    .map(|v| v.try_clone().map(Into::into))
103                    .transpose()?,
104            ),
105            signature: self.signature.clone(),
106        })
107    }
108}
109
110impl Display for Maybe<'_> {
111    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112        maybe_display_fmt(self, f, true)
113    }
114}
115
116pub(crate) fn maybe_display_fmt(
117    maybe: &Maybe<'_>,
118    f: &mut std::fmt::Formatter<'_>,
119    type_annotate: bool,
120) -> std::fmt::Result {
121    if type_annotate {
122        write!(f, "@{} ", maybe.signature())?;
123    }
124
125    let (last_inner, depth) = {
126        let mut curr = maybe.inner();
127        let mut depth = 0;
128
129        while let Some(Value::Maybe(child_maybe)) = curr {
130            curr = child_maybe.inner();
131            depth += 1;
132        }
133
134        (curr, depth)
135    };
136
137    if let Some(last_inner) = last_inner {
138        // There are no Nothings, so print out the inner value with no prefixes.
139        value_display_fmt(last_inner, f, false)?;
140    } else {
141        // One of the maybes was Nothing, so print out the right number of justs.
142        for _ in 0..depth {
143            f.write_str("just ")?;
144        }
145        f.write_str("nothing")?;
146    }
147
148    Ok(())
149}
150
151impl<'a, T> From<Option<T>> for Maybe<'a>
152where
153    T: Type + Into<Value<'a>>,
154{
155    fn from(value: Option<T>) -> Self {
156        value
157            .map(|v| Self::just(Value::new(v)))
158            .unwrap_or_else(|| Self::nothing(T::SIGNATURE))
159    }
160}
161
162impl<'a, T> From<&Option<T>> for Maybe<'a>
163where
164    T: Type + Into<Value<'a>> + Clone,
165{
166    fn from(value: &Option<T>) -> Self {
167        value
168            .as_ref()
169            .map(|v| Self::just(Value::new(v.clone())))
170            .unwrap_or_else(|| Self::nothing(T::SIGNATURE))
171    }
172}
173
174impl<'a> Serialize for Maybe<'a> {
175    fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
176    where
177        S: Serializer,
178    {
179        match &*self.value {
180            Some(value) => value.serialize_value_as_some(serializer),
181            None => serializer.serialize_none(),
182        }
183    }
184}