zenoh_protocol/core/
cowstr.rs

1//
2// Copyright (c) 2023 ZettaScale Technology
3//
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7// which is available at https://www.apache.org/licenses/LICENSE-2.0.
8//
9// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10//
11// Contributors:
12//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>
13//
14use alloc::{borrow::ToOwned, boxed::Box, string::String, vec::Vec};
15use core::{
16    fmt::{Debug, Display, Formatter},
17    num::NonZeroUsize,
18};
19
20enum CowStrInner<'a> {
21    Borrowed(&'a str),
22    Owned { s: Box<str>, capacity: NonZeroUsize },
23}
24pub struct CowStr<'a>(CowStrInner<'a>);
25impl<'a> CowStr<'a> {
26    pub(crate) const fn borrowed(s: &'a str) -> Self {
27        Self(CowStrInner::Borrowed(s))
28    }
29    pub fn as_str(&self) -> &str {
30        self
31    }
32}
33impl<'a> From<alloc::borrow::Cow<'a, str>> for CowStr<'a> {
34    fn from(value: alloc::borrow::Cow<'a, str>) -> Self {
35        match value {
36            alloc::borrow::Cow::Borrowed(s) => CowStr::borrowed(s),
37            alloc::borrow::Cow::Owned(s) => s.into(),
38        }
39    }
40}
41impl<'a> From<&'a str> for CowStr<'a> {
42    fn from(value: &'a str) -> Self {
43        CowStr::borrowed(value)
44    }
45}
46impl From<String> for CowStr<'_> {
47    fn from(s: String) -> Self {
48        if s.is_empty() {
49            CowStr::borrowed("")
50        } else {
51            let capacity = unsafe { NonZeroUsize::new_unchecked(s.capacity()) };
52            Self(CowStrInner::Owned {
53                s: s.into_boxed_str(),
54                capacity,
55            })
56        }
57    }
58}
59impl AsRef<str> for CowStr<'_> {
60    fn as_ref(&self) -> &str {
61        self
62    }
63}
64impl core::ops::Deref for CowStr<'_> {
65    type Target = str;
66    fn deref(&self) -> &Self::Target {
67        match &self.0 {
68            CowStrInner::Borrowed(s) => s,
69            CowStrInner::Owned { s, .. } => s,
70        }
71    }
72}
73impl Clone for CowStr<'_> {
74    fn clone(&self) -> Self {
75        self.as_str().to_owned().into()
76    }
77}
78impl Debug for CowStr<'_> {
79    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
80        f.write_str(self)
81    }
82}
83impl Display for CowStr<'_> {
84    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
85        f.write_str(self)
86    }
87}
88impl PartialEq for CowStr<'_> {
89    fn eq(&self, other: &Self) -> bool {
90        self.as_str() == other.as_str()
91    }
92}
93impl Eq for CowStr<'_> {}
94impl core::ops::Add<&str> for CowStr<'_> {
95    type Output = String;
96    fn add(self, rhs: &str) -> Self::Output {
97        match self.0 {
98            CowStrInner::Borrowed(s) => {
99                let mut ans = String::with_capacity(s.len() + rhs.len());
100                ans.push_str(s);
101                ans.push_str(rhs);
102                ans
103            }
104            CowStrInner::Owned { mut s, capacity } => unsafe {
105                let mut s = String::from_utf8_unchecked(Vec::from_raw_parts(
106                    s.as_mut_ptr(),
107                    s.len(),
108                    capacity.get(),
109                ));
110                s += rhs;
111                s
112            },
113        }
114    }
115}