Skip to main content

ron/value/
raw.rs

1// Inspired by David Tolnay's serde-rs
2// https://github.com/serde-rs/json/blob/master/src/raw.rs
3// Licensed under either of Apache License, Version 2.0 or MIT license at your option.
4
5use alloc::{borrow::ToOwned, boxed::Box, format, string::String};
6use core::{fmt, ops::Range};
7
8use serde::{de, ser, Deserialize, Serialize};
9
10use crate::{
11    error::{Error, SpannedResult},
12    options::Options,
13};
14
15// NOTE: Keep synchronised with fuzz/arbitrary::typed_data::RAW_VALUE_TOKEN
16pub(crate) const RAW_VALUE_TOKEN: &str = "$ron::private::RawValue";
17
18#[allow(clippy::module_name_repetitions)]
19#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
20#[repr(transparent)]
21pub struct RawValue {
22    ron: str,
23}
24
25#[allow(unsafe_code)]
26impl RawValue {
27    fn from_borrowed_str(ron: &str) -> &Self {
28        // Safety: RawValue is a transparent newtype around str
29        unsafe { &*(ron as *const str as *const RawValue) }
30    }
31
32    fn from_boxed_str(ron: Box<str>) -> Box<Self> {
33        // Safety: RawValue is a transparent newtype around str
34        unsafe { core::mem::transmute::<Box<str>, Box<RawValue>>(ron) }
35    }
36
37    fn into_boxed_str(raw_value: Box<Self>) -> Box<str> {
38        // Safety: RawValue is a transparent newtype around str
39        unsafe { core::mem::transmute::<Box<RawValue>, Box<str>>(raw_value) }
40    }
41
42    #[allow(clippy::expect_used)]
43    fn trim_range(ron: &str) -> Range<usize> {
44        fn trim_range_inner(ron: &str) -> Result<Range<usize>, Error> {
45            let mut deserializer = crate::Deserializer::from_str(ron).map_err(Error::from)?;
46
47            deserializer.parser.skip_ws()?;
48            let start_offset = ron.len() - deserializer.parser.src().len();
49
50            let _ = serde::de::IgnoredAny::deserialize(&mut deserializer)?;
51
52            deserializer.parser.skip_ws()?;
53            let end_offset = deserializer.parser.pre_ws_src().len();
54
55            Ok(start_offset..(ron.len() - end_offset))
56        }
57
58        trim_range_inner(ron).expect("RawValue must contain valid ron")
59    }
60}
61
62impl Clone for Box<RawValue> {
63    fn clone(&self) -> Self {
64        (**self).to_owned()
65    }
66}
67
68impl ToOwned for RawValue {
69    type Owned = Box<RawValue>;
70
71    fn to_owned(&self) -> Self::Owned {
72        RawValue::from_boxed_str(self.ron.to_owned().into_boxed_str())
73    }
74}
75
76impl fmt::Debug for RawValue {
77    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78        f.debug_tuple("RawValue")
79            .field(&format_args!("{}", &self.ron))
80            .finish()
81    }
82}
83
84impl fmt::Display for RawValue {
85    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86        f.write_str(&self.ron)
87    }
88}
89
90impl RawValue {
91    /// Get the inner raw RON string, which is guaranteed to contain valid RON.
92    #[must_use]
93    pub fn get_ron(&self) -> &str {
94        &self.ron
95    }
96
97    /// Helper function to validate a RON string and turn it into a
98    /// [`RawValue`].
99    pub fn from_ron(ron: &str) -> SpannedResult<&Self> {
100        let mut deserializer = crate::Deserializer::from_str(ron)?;
101
102        // raw values can be used everywhere but extensions cannot
103        if !deserializer.extensions().is_empty() {
104            return Err(deserializer.span_error(Error::Message(String::from(
105                "ron::value::RawValue cannot enable extensions",
106            ))));
107        }
108
109        // neither can global attributes like `#![type = ".."]`
110        if deserializer.parser.global_attributes {
111            return Err(deserializer.span_error(Error::Message(String::from(
112                "ron::value::RawValue cannot contain attributes",
113            ))));
114        }
115
116        let _ = de::Deserializer::deserialize_newtype_struct(
117            &mut deserializer,
118            RAW_VALUE_TOKEN,
119            de::IgnoredAny,
120        )
121        .map_err(|e| deserializer.span_error(e))?;
122
123        deserializer.end().map_err(|e| deserializer.span_error(e))?;
124
125        Ok(Self::from_borrowed_str(ron))
126    }
127
128    /// Helper function to validate a RON string and turn it into a
129    /// [`RawValue`].
130    pub fn from_boxed_ron(ron: Box<str>) -> SpannedResult<Box<Self>> {
131        match Self::from_ron(&ron) {
132            Ok(_) => Ok(Self::from_boxed_str(ron)),
133            Err(err) => Err(err),
134        }
135    }
136
137    /// Helper function to deserialize the inner RON string into `T`.
138    pub fn into_rust<'de, T: Deserialize<'de>>(&'de self) -> SpannedResult<T> {
139        Options::default().from_str(&self.ron)
140    }
141
142    /// Helper function to serialize `value` into a RON string.
143    pub fn from_rust<T: Serialize>(value: &T) -> Result<Box<Self>, Error> {
144        let ron = Options::default().to_string(value)?;
145
146        Ok(RawValue::from_boxed_str(ron.into_boxed_str()))
147    }
148}
149
150impl RawValue {
151    #[must_use]
152    /// Trims any leadning and trailing whitespace off the raw RON string,
153    /// including whitespace characters and comments.
154    pub fn trim(&self) -> &Self {
155        Self::from_borrowed_str(&self.ron[RawValue::trim_range(&self.ron)])
156    }
157
158    #[must_use]
159    /// Trims any leadning and trailing whitespace off the boxed raw RON string,
160    /// including whitespace characters and comments.
161    pub fn trim_boxed(self: Box<Self>) -> Box<Self> {
162        let trim_range = RawValue::trim_range(&self.ron);
163        let mut boxed_ron = RawValue::into_boxed_str(self).into_string();
164        boxed_ron.truncate(trim_range.end);
165        boxed_ron.drain(..trim_range.start);
166        RawValue::from_boxed_str(boxed_ron.into_boxed_str())
167    }
168}
169
170impl From<Box<RawValue>> for Box<str> {
171    fn from(raw_value: Box<RawValue>) -> Self {
172        RawValue::into_boxed_str(raw_value)
173    }
174}
175
176impl Serialize for RawValue {
177    fn serialize<S: ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
178        serializer.serialize_newtype_struct(RAW_VALUE_TOKEN, &self.ron)
179    }
180}
181
182impl<'de: 'a, 'a> Deserialize<'de> for &'a RawValue {
183    fn deserialize<D: de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
184        struct ReferenceVisitor;
185
186        impl<'de> de::Visitor<'de> for ReferenceVisitor {
187            type Value = &'de RawValue;
188
189            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
190                // This error message only shows up with foreign Deserializers
191                write!(formatter, "any valid borrowed RON-value-string")
192            }
193
194            fn visit_borrowed_str<E: de::Error>(self, ron: &'de str) -> Result<Self::Value, E> {
195                match RawValue::from_ron(ron) {
196                    Ok(raw_value) => Ok(raw_value),
197                    Err(err) => Err(de::Error::custom(format!("invalid RON value at {}", err))),
198                }
199            }
200
201            fn visit_newtype_struct<D: de::Deserializer<'de>>(
202                self,
203                deserializer: D,
204            ) -> Result<Self::Value, D::Error> {
205                deserializer.deserialize_str(self)
206            }
207        }
208
209        deserializer.deserialize_newtype_struct(RAW_VALUE_TOKEN, ReferenceVisitor)
210    }
211}
212
213impl<'de> Deserialize<'de> for Box<RawValue> {
214    fn deserialize<D: de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
215        struct BoxedVisitor;
216
217        impl<'de> de::Visitor<'de> for BoxedVisitor {
218            type Value = Box<RawValue>;
219
220            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
221                // This error message only shows up with foreign Deserializers
222                write!(formatter, "any valid RON-value-string")
223            }
224
225            fn visit_str<E: de::Error>(self, ron: &str) -> Result<Self::Value, E> {
226                match RawValue::from_ron(ron) {
227                    Ok(raw_value) => Ok(raw_value.to_owned()),
228                    Err(err) => Err(de::Error::custom(format!("invalid RON value at {}", err))),
229                }
230            }
231
232            fn visit_string<E: de::Error>(self, ron: String) -> Result<Self::Value, E> {
233                match RawValue::from_boxed_ron(ron.into_boxed_str()) {
234                    Ok(raw_value) => Ok(raw_value),
235                    Err(err) => Err(de::Error::custom(format!("invalid RON value at {}", err))),
236                }
237            }
238
239            fn visit_newtype_struct<D: de::Deserializer<'de>>(
240                self,
241                deserializer: D,
242            ) -> Result<Self::Value, D::Error> {
243                deserializer.deserialize_string(self)
244            }
245        }
246
247        deserializer.deserialize_newtype_struct(RAW_VALUE_TOKEN, BoxedVisitor)
248    }
249}