oco_ref/
lib.rs

1//! This module contains the `Oco` (Owned Clones Once) smart pointer,
2//! which is used to store immutable references to values.
3//! This is useful for storing, for example, strings.
4
5use serde::{de::DeserializeOwned, Deserialize, Serialize};
6use std::{
7    borrow::{Borrow, Cow},
8    ffi::{CStr, OsStr},
9    fmt,
10    hash::Hash,
11    ops::{Add, Deref},
12    path::Path,
13    sync::Arc,
14};
15
16/// "Owned Clones Once" - a smart pointer that can be either a reference,
17/// an owned value, or a reference counted pointer. This is useful for
18/// storing immutable values, such as strings, in a way that is cheap to
19/// clone and pass around.
20///
21/// The `Clone` implementation is amortized `O(1)`. Cloning the [`Oco::Borrowed`]
22/// variant simply copies the references (`O(1)`). Cloning the [`Oco::Counted`]
23/// variant increments a reference count (`O(1)`). Cloning the [`Oco::Owned`]
24/// variant upgrades it to [`Oco::Counted`], which requires an `O(n)` clone of the
25/// data, but all subsequent clones will be `O(1)`.
26pub enum Oco<'a, T: ?Sized + ToOwned + 'a> {
27    /// A static reference to a value.
28    Borrowed(&'a T),
29    /// A reference counted pointer to a value.
30    Counted(Arc<T>),
31    /// An owned value.
32    Owned(<T as ToOwned>::Owned),
33}
34
35impl<'a, T: ?Sized + ToOwned> Oco<'a, T> {
36    /// Converts the value into an owned value.
37    pub fn into_owned(self) -> <T as ToOwned>::Owned {
38        match self {
39            Oco::Borrowed(v) => v.to_owned(),
40            Oco::Counted(v) => v.as_ref().to_owned(),
41            Oco::Owned(v) => v,
42        }
43    }
44
45    /// Checks if the value is [`Oco::Borrowed`].
46    /// # Examples
47    /// ```
48    /// # use std::sync::Arc;
49    /// # use oco_ref::Oco;
50    /// assert!(Oco::<str>::Borrowed("Hello").is_borrowed());
51    /// assert!(!Oco::<str>::Counted(Arc::from("Hello")).is_borrowed());
52    /// assert!(!Oco::<str>::Owned("Hello".to_string()).is_borrowed());
53    /// ```
54    pub const fn is_borrowed(&self) -> bool {
55        matches!(self, Oco::Borrowed(_))
56    }
57
58    /// Checks if the value is [`Oco::Counted`].
59    /// # Examples
60    /// ```
61    /// # use std::sync::Arc;
62    /// # use oco_ref::Oco;
63    /// assert!(Oco::<str>::Counted(Arc::from("Hello")).is_counted());
64    /// assert!(!Oco::<str>::Borrowed("Hello").is_counted());
65    /// assert!(!Oco::<str>::Owned("Hello".to_string()).is_counted());
66    /// ```
67    pub const fn is_counted(&self) -> bool {
68        matches!(self, Oco::Counted(_))
69    }
70
71    /// Checks if the value is [`Oco::Owned`].
72    /// # Examples
73    /// ```
74    /// # use std::sync::Arc;
75    /// # use oco_ref::Oco;
76    /// assert!(Oco::<str>::Owned("Hello".to_string()).is_owned());
77    /// assert!(!Oco::<str>::Borrowed("Hello").is_owned());
78    /// assert!(!Oco::<str>::Counted(Arc::from("Hello")).is_owned());
79    /// ```
80    pub const fn is_owned(&self) -> bool {
81        matches!(self, Oco::Owned(_))
82    }
83}
84
85impl<T: ?Sized + ToOwned> Deref for Oco<'_, T> {
86    type Target = T;
87
88    fn deref(&self) -> &T {
89        match self {
90            Oco::Borrowed(v) => v,
91            Oco::Owned(v) => v.borrow(),
92            Oco::Counted(v) => v,
93        }
94    }
95}
96
97impl<T: ?Sized + ToOwned> Borrow<T> for Oco<'_, T> {
98    #[inline(always)]
99    fn borrow(&self) -> &T {
100        self.deref()
101    }
102}
103
104impl<T: ?Sized + ToOwned> AsRef<T> for Oco<'_, T> {
105    #[inline(always)]
106    fn as_ref(&self) -> &T {
107        self.deref()
108    }
109}
110
111impl AsRef<Path> for Oco<'_, str> {
112    #[inline(always)]
113    fn as_ref(&self) -> &Path {
114        self.as_str().as_ref()
115    }
116}
117
118impl AsRef<Path> for Oco<'_, OsStr> {
119    #[inline(always)]
120    fn as_ref(&self) -> &Path {
121        self.as_os_str().as_ref()
122    }
123}
124
125// --------------------------------------
126// pub fn as_{slice}(&self) -> &{slice}
127// --------------------------------------
128
129impl Oco<'_, str> {
130    /// Returns a `&str` slice of this [`Oco`].
131    /// # Examples
132    /// ```
133    /// # use oco_ref::Oco;
134    /// let oco = Oco::<str>::Borrowed("Hello");
135    /// let s: &str = oco.as_str();
136    /// assert_eq!(s, "Hello");
137    /// ```
138    #[inline(always)]
139    pub fn as_str(&self) -> &str {
140        self
141    }
142}
143
144impl Oco<'_, CStr> {
145    /// Returns a `&CStr` slice of this [`Oco`].
146    /// # Examples
147    /// ```
148    /// # use oco_ref::Oco;
149    /// use std::ffi::CStr;
150    ///
151    /// let oco =
152    ///     Oco::<CStr>::Borrowed(CStr::from_bytes_with_nul(b"Hello\0").unwrap());
153    /// let s: &CStr = oco.as_c_str();
154    /// assert_eq!(s, CStr::from_bytes_with_nul(b"Hello\0").unwrap());
155    /// ```
156    #[inline(always)]
157    pub fn as_c_str(&self) -> &CStr {
158        self
159    }
160}
161
162impl Oco<'_, OsStr> {
163    /// Returns a `&OsStr` slice of this [`Oco`].
164    /// # Examples
165    /// ```
166    /// # use oco_ref::Oco;
167    /// use std::ffi::OsStr;
168    ///
169    /// let oco = Oco::<OsStr>::Borrowed(OsStr::new("Hello"));
170    /// let s: &OsStr = oco.as_os_str();
171    /// assert_eq!(s, OsStr::new("Hello"));
172    /// ```
173    #[inline(always)]
174    pub fn as_os_str(&self) -> &OsStr {
175        self
176    }
177}
178
179impl Oco<'_, Path> {
180    /// Returns a `&Path` slice of this [`Oco`].
181    /// # Examples
182    /// ```
183    /// # use oco_ref::Oco;
184    /// use std::path::Path;
185    ///
186    /// let oco = Oco::<Path>::Borrowed(Path::new("Hello"));
187    /// let s: &Path = oco.as_path();
188    /// assert_eq!(s, Path::new("Hello"));
189    /// ```
190    #[inline(always)]
191    pub fn as_path(&self) -> &Path {
192        self
193    }
194}
195
196impl<T> Oco<'_, [T]>
197where
198    [T]: ToOwned,
199{
200    /// Returns a `&[T]` slice of this [`Oco`].
201    /// # Examples
202    /// ```
203    /// # use oco_ref::Oco;
204    /// let oco = Oco::<[u8]>::Borrowed(b"Hello");
205    /// let s: &[u8] = oco.as_slice();
206    /// assert_eq!(s, b"Hello");
207    /// ```
208    #[inline(always)]
209    pub fn as_slice(&self) -> &[T] {
210        self
211    }
212}
213
214impl<'a, T> Clone for Oco<'a, T>
215where
216    T: ?Sized + ToOwned + 'a,
217    for<'b> Arc<T>: From<&'b T>,
218{
219    /// Returns a new [`Oco`] with the same value as this one.
220    /// If the value is [`Oco::Owned`], this will convert it into
221    /// [`Oco::Counted`], so that the next clone will be O(1).
222    /// # Examples
223    /// [`String`] :
224    /// ```
225    /// # use oco_ref::Oco;
226    /// let oco = Oco::<str>::Owned("Hello".to_string());
227    /// let oco2 = oco.clone();
228    /// assert_eq!(oco, oco2);
229    /// assert!(oco2.is_counted());
230    /// ```
231    /// [`Vec`] :
232    /// ```
233    /// # use oco_ref::Oco;
234    /// let oco = Oco::<[u8]>::Owned(b"Hello".to_vec());
235    /// let oco2 = oco.clone();
236    /// assert_eq!(oco, oco2);
237    /// assert!(oco2.is_counted());
238    /// ```
239    fn clone(&self) -> Self {
240        match self {
241            Self::Borrowed(v) => Self::Borrowed(v),
242            Self::Counted(v) => Self::Counted(Arc::clone(v)),
243            Self::Owned(v) => Self::Counted(Arc::from(v.borrow())),
244        }
245    }
246}
247
248impl<'a, T> Oco<'a, T>
249where
250    T: ?Sized + ToOwned + 'a,
251    for<'b> Arc<T>: From<&'b T>,
252{
253    /// Clones the value with inplace conversion into [`Oco::Counted`] if it
254    /// was previously [`Oco::Owned`].
255    /// # Examples
256    /// ```
257    /// # use oco_ref::Oco;
258    /// let mut oco1 = Oco::<str>::Owned("Hello".to_string());
259    /// let oco2 = oco1.clone_inplace();
260    /// assert_eq!(oco1, oco2);
261    /// assert!(oco1.is_counted());
262    /// assert!(oco2.is_counted());
263    /// ```
264    pub fn clone_inplace(&mut self) -> Self {
265        match &*self {
266            Self::Borrowed(v) => Self::Borrowed(v),
267            Self::Counted(v) => Self::Counted(Arc::clone(v)),
268            Self::Owned(v) => {
269                let rc = Arc::from(v.borrow());
270                *self = Self::Counted(rc.clone());
271                Self::Counted(rc)
272            }
273        }
274    }
275
276    /// Converts the value into its cheaply-clonable form in place.
277    /// In other words, if it is currently [`Oco::Owned`], converts into [`Oco::Counted`]
278    /// in an `O(n)` operation, so that all future clones are `O(1)`.
279    ///
280    /// # Examples
281    /// ```
282    /// # use oco_ref::Oco;
283    /// let mut oco = Oco::<str>::Owned("Hello".to_string());
284    /// oco.upgrade_inplace();
285    /// assert!(oco.is_counted());
286    /// ```
287    pub fn upgrade_inplace(&mut self) {
288        if let Self::Owned(v) = &*self {
289            let rc = Arc::from(v.borrow());
290            *self = Self::Counted(rc);
291        }
292    }
293}
294
295impl<T: ?Sized> Default for Oco<'_, T>
296where
297    T: ToOwned,
298    T::Owned: Default,
299{
300    fn default() -> Self {
301        Oco::Owned(T::Owned::default())
302    }
303}
304
305impl<'a, 'b, A: ?Sized, B: ?Sized> PartialEq<Oco<'b, B>> for Oco<'a, A>
306where
307    A: PartialEq<B>,
308    A: ToOwned,
309    B: ToOwned,
310{
311    fn eq(&self, other: &Oco<'b, B>) -> bool {
312        **self == **other
313    }
314}
315
316impl<T: ?Sized + ToOwned + Eq> Eq for Oco<'_, T> {}
317
318impl<'a, 'b, A: ?Sized, B: ?Sized> PartialOrd<Oco<'b, B>> for Oco<'a, A>
319where
320    A: PartialOrd<B>,
321    A: ToOwned,
322    B: ToOwned,
323{
324    fn partial_cmp(&self, other: &Oco<'b, B>) -> Option<std::cmp::Ordering> {
325        (**self).partial_cmp(&**other)
326    }
327}
328
329impl<T: ?Sized + Ord> Ord for Oco<'_, T>
330where
331    T: ToOwned,
332{
333    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
334        (**self).cmp(&**other)
335    }
336}
337
338impl<T: ?Sized + Hash> Hash for Oco<'_, T>
339where
340    T: ToOwned,
341{
342    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
343        (**self).hash(state)
344    }
345}
346
347impl<T: ?Sized + fmt::Debug> fmt::Debug for Oco<'_, T>
348where
349    T: ToOwned,
350{
351    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352        (**self).fmt(f)
353    }
354}
355
356impl<T: ?Sized + fmt::Display> fmt::Display for Oco<'_, T>
357where
358    T: ToOwned,
359{
360    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
361        (**self).fmt(f)
362    }
363}
364
365impl<'a, T: ?Sized> From<&'a T> for Oco<'a, T>
366where
367    T: ToOwned,
368{
369    fn from(v: &'a T) -> Self {
370        Oco::Borrowed(v)
371    }
372}
373
374impl<'a, T: ?Sized> From<Cow<'a, T>> for Oco<'a, T>
375where
376    T: ToOwned,
377{
378    fn from(v: Cow<'a, T>) -> Self {
379        match v {
380            Cow::Borrowed(v) => Oco::Borrowed(v),
381            Cow::Owned(v) => Oco::Owned(v),
382        }
383    }
384}
385
386impl<'a, T: ?Sized> From<Oco<'a, T>> for Cow<'a, T>
387where
388    T: ToOwned,
389{
390    fn from(value: Oco<'a, T>) -> Self {
391        match value {
392            Oco::Borrowed(v) => Cow::Borrowed(v),
393            Oco::Owned(v) => Cow::Owned(v),
394            Oco::Counted(v) => Cow::Owned(v.as_ref().to_owned()),
395        }
396    }
397}
398
399impl<T: ?Sized> From<Arc<T>> for Oco<'_, T>
400where
401    T: ToOwned,
402{
403    fn from(v: Arc<T>) -> Self {
404        Oco::Counted(v)
405    }
406}
407
408impl<T: ?Sized> From<Box<T>> for Oco<'_, T>
409where
410    T: ToOwned,
411{
412    fn from(v: Box<T>) -> Self {
413        Oco::Counted(v.into())
414    }
415}
416
417impl From<String> for Oco<'_, str> {
418    fn from(v: String) -> Self {
419        Oco::Owned(v)
420    }
421}
422
423impl From<Oco<'_, str>> for String {
424    fn from(v: Oco<'_, str>) -> Self {
425        match v {
426            Oco::Borrowed(v) => v.to_owned(),
427            Oco::Counted(v) => v.as_ref().to_owned(),
428            Oco::Owned(v) => v,
429        }
430    }
431}
432
433impl<T> From<Vec<T>> for Oco<'_, [T]>
434where
435    [T]: ToOwned<Owned = Vec<T>>,
436{
437    fn from(v: Vec<T>) -> Self {
438        Oco::Owned(v)
439    }
440}
441
442impl<'a, T, const N: usize> From<&'a [T; N]> for Oco<'a, [T]>
443where
444    [T]: ToOwned,
445{
446    fn from(v: &'a [T; N]) -> Self {
447        Oco::Borrowed(v)
448    }
449}
450
451impl<'a> From<Oco<'a, str>> for Oco<'a, [u8]> {
452    fn from(v: Oco<'a, str>) -> Self {
453        match v {
454            Oco::Borrowed(v) => Oco::Borrowed(v.as_bytes()),
455            Oco::Owned(v) => Oco::Owned(v.into_bytes()),
456            Oco::Counted(v) => Oco::Counted(v.into()),
457        }
458    }
459}
460
461/// Error returned from `Oco::try_from` for unsuccessful
462/// conversion from `Oco<'_, [u8]>` to `Oco<'_, str>`.
463#[derive(Debug, Clone, thiserror::Error)]
464#[error("invalid utf-8 sequence: {_0}")]
465pub enum FromUtf8Error {
466    /// Error for conversion of [`Oco::Borrowed`] and [`Oco::Counted`] variants
467    /// (`&[u8]` to `&str`).
468    #[error("{_0}")]
469    StrFromBytes(
470        #[source]
471        #[from]
472        std::str::Utf8Error,
473    ),
474    /// Error for conversion of [`Oco::Owned`] variant (`Vec<u8>` to `String`).
475    #[error("{_0}")]
476    StringFromBytes(
477        #[source]
478        #[from]
479        std::string::FromUtf8Error,
480    ),
481}
482
483macro_rules! impl_slice_eq {
484    ([$($g:tt)*] $((where $($w:tt)+))?, $lhs:ty, $rhs: ty) => {
485        impl<$($g)*> PartialEq<$rhs> for $lhs
486        $(where
487            $($w)*)?
488        {
489            #[inline]
490            fn eq(&self, other: &$rhs) -> bool {
491                PartialEq::eq(&self[..], &other[..])
492            }
493        }
494
495        impl<$($g)*> PartialEq<$lhs> for $rhs
496        $(where
497            $($w)*)?
498        {
499            #[inline]
500            fn eq(&self, other: &$lhs) -> bool {
501                PartialEq::eq(&self[..], &other[..])
502            }
503        }
504    };
505}
506
507impl_slice_eq!([], Oco<'_, str>, str);
508impl_slice_eq!(['a, 'b], Oco<'a, str>, &'b str);
509impl_slice_eq!([], Oco<'_, str>, String);
510impl_slice_eq!(['a, 'b], Oco<'a, str>, Cow<'b, str>);
511
512impl_slice_eq!([T: PartialEq] (where [T]: ToOwned), Oco<'_, [T]>, [T]);
513impl_slice_eq!(['a, 'b, T: PartialEq] (where [T]: ToOwned), Oco<'a, [T]>, &'b [T]);
514impl_slice_eq!([T: PartialEq] (where [T]: ToOwned), Oco<'_, [T]>, Vec<T>);
515impl_slice_eq!(['a, 'b, T: PartialEq] (where [T]: ToOwned), Oco<'a, [T]>, Cow<'b, [T]>);
516
517impl<'a, 'b> Add<&'b str> for Oco<'a, str> {
518    type Output = Oco<'static, str>;
519
520    fn add(self, rhs: &'b str) -> Self::Output {
521        Oco::Owned(String::from(self) + rhs)
522    }
523}
524
525impl<'a, 'b> Add<Cow<'b, str>> for Oco<'a, str> {
526    type Output = Oco<'static, str>;
527
528    fn add(self, rhs: Cow<'b, str>) -> Self::Output {
529        Oco::Owned(String::from(self) + rhs.as_ref())
530    }
531}
532
533impl<'a, 'b> Add<Oco<'b, str>> for Oco<'a, str> {
534    type Output = Oco<'static, str>;
535
536    fn add(self, rhs: Oco<'b, str>) -> Self::Output {
537        Oco::Owned(String::from(self) + rhs.as_ref())
538    }
539}
540
541impl<'a> FromIterator<Oco<'a, str>> for String {
542    fn from_iter<T: IntoIterator<Item = Oco<'a, str>>>(iter: T) -> Self {
543        iter.into_iter().fold(String::new(), |mut acc, item| {
544            acc.push_str(item.as_ref());
545            acc
546        })
547    }
548}
549
550impl<'a, T> Deserialize<'a> for Oco<'static, T>
551where
552    T: ?Sized + ToOwned + 'a,
553    T::Owned: DeserializeOwned,
554{
555    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
556    where
557        D: serde::Deserializer<'a>,
558    {
559        <T::Owned>::deserialize(deserializer).map(Oco::Owned)
560    }
561}
562
563impl<'a, T> Serialize for Oco<'a, T>
564where
565    T: ?Sized + ToOwned + 'a,
566    for<'b> &'b T: Serialize,
567{
568    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
569    where
570        S: serde::Serializer,
571    {
572        self.as_ref().serialize(serializer)
573    }
574}
575
576#[cfg(test)]
577mod tests {
578    use super::*;
579
580    #[test]
581    fn debug_fmt_should_display_quotes_for_strings() {
582        let s: Oco<str> = Oco::Borrowed("hello");
583        assert_eq!(format!("{:?}", s), "\"hello\"");
584        let s: Oco<str> = Oco::Counted(Arc::from("hello"));
585        assert_eq!(format!("{:?}", s), "\"hello\"");
586    }
587
588    #[test]
589    fn partial_eq_should_compare_str_to_str() {
590        let s: Oco<str> = Oco::Borrowed("hello");
591        assert_eq!(s, "hello");
592        assert_eq!("hello", s);
593        assert_eq!(s, String::from("hello"));
594        assert_eq!(String::from("hello"), s);
595        assert_eq!(s, Cow::from("hello"));
596        assert_eq!(Cow::from("hello"), s);
597    }
598
599    #[test]
600    fn partial_eq_should_compare_slice_to_slice() {
601        let s: Oco<[i32]> = Oco::Borrowed([1, 2, 3].as_slice());
602        assert_eq!(s, [1, 2, 3].as_slice());
603        assert_eq!([1, 2, 3].as_slice(), s);
604        assert_eq!(s, vec![1, 2, 3]);
605        assert_eq!(vec![1, 2, 3], s);
606        assert_eq!(s, Cow::<'_, [i32]>::Borrowed(&[1, 2, 3]));
607        assert_eq!(Cow::<'_, [i32]>::Borrowed(&[1, 2, 3]), s);
608    }
609
610    #[test]
611    fn add_should_concatenate_strings() {
612        let s: Oco<str> = Oco::Borrowed("hello");
613        assert_eq!(s.clone() + " world", "hello world");
614        assert_eq!(s.clone() + Cow::from(" world"), "hello world");
615        assert_eq!(s + Oco::from(" world"), "hello world");
616    }
617
618    #[test]
619    fn as_str_should_return_a_str() {
620        let s: Oco<str> = Oco::Borrowed("hello");
621        assert_eq!(s.as_str(), "hello");
622        let s: Oco<str> = Oco::Counted(Arc::from("hello"));
623        assert_eq!(s.as_str(), "hello");
624    }
625
626    #[test]
627    fn as_slice_should_return_a_slice() {
628        let s: Oco<[i32]> = Oco::Borrowed([1, 2, 3].as_slice());
629        assert_eq!(s.as_slice(), [1, 2, 3].as_slice());
630        let s: Oco<[i32]> = Oco::Counted(Arc::from([1, 2, 3]));
631        assert_eq!(s.as_slice(), [1, 2, 3].as_slice());
632    }
633
634    #[test]
635    fn default_for_str_should_return_an_empty_string() {
636        let s: Oco<str> = Default::default();
637        assert!(s.is_empty());
638    }
639
640    #[test]
641    fn default_for_slice_should_return_an_empty_slice() {
642        let s: Oco<[i32]> = Default::default();
643        assert!(s.is_empty());
644    }
645
646    #[test]
647    fn default_for_any_option_should_return_none() {
648        let s: Oco<Option<i32>> = Default::default();
649        assert!(s.is_none());
650    }
651
652    #[test]
653    fn cloned_owned_string_should_make_counted_str() {
654        let s: Oco<str> = Oco::Owned(String::from("hello"));
655        assert!(s.clone().is_counted());
656    }
657
658    #[test]
659    fn cloned_borrowed_str_should_make_borrowed_str() {
660        let s: Oco<str> = Oco::Borrowed("hello");
661        assert!(s.clone().is_borrowed());
662    }
663
664    #[test]
665    fn cloned_counted_str_should_make_counted_str() {
666        let s: Oco<str> = Oco::Counted(Arc::from("hello"));
667        assert!(s.clone().is_counted());
668    }
669
670    #[test]
671    fn cloned_inplace_owned_string_should_make_counted_str_and_become_counted()
672    {
673        let mut s: Oco<str> = Oco::Owned(String::from("hello"));
674        assert!(s.clone_inplace().is_counted());
675        assert!(s.is_counted());
676    }
677
678    #[test]
679    fn cloned_inplace_borrowed_str_should_make_borrowed_str_and_remain_borrowed(
680    ) {
681        let mut s: Oco<str> = Oco::Borrowed("hello");
682        assert!(s.clone_inplace().is_borrowed());
683        assert!(s.is_borrowed());
684    }
685
686    #[test]
687    fn cloned_inplace_counted_str_should_make_counted_str_and_remain_counted() {
688        let mut s: Oco<str> = Oco::Counted(Arc::from("hello"));
689        assert!(s.clone_inplace().is_counted());
690        assert!(s.is_counted());
691    }
692
693    #[test]
694    fn serialization_works() {
695        let s = serde_json::to_string(&Oco::Borrowed("foo"))
696            .expect("should serialize string");
697        assert_eq!(s, "\"foo\"");
698    }
699
700    #[test]
701    fn deserialization_works() {
702        let s: Oco<str> = serde_json::from_str("\"bar\"")
703            .expect("should deserialize from string");
704        assert_eq!(s, Oco::from(String::from("bar")));
705    }
706}