]>
git.proxmox.com Git - rustc.git/blob - vendor/pulldown-cmark-0.7.2/src/strings.rs
1 use std
::borrow
::{Borrow, ToOwned}
;
2 use std
::convert
::{AsRef, TryFrom}
;
4 use std
::hash
::{Hash, Hasher}
;
6 use std
::str::from_utf8
;
8 const MAX_INLINE_STR_LEN
: usize = 3 * std
::mem
::size_of
::<isize>() - 1;
10 /// Returned when trying to convert a `&str` into a `InlineStr`
11 /// but it fails because it doesn't fit.
13 pub struct StringTooLongError
;
15 /// An inline string that can contain almost three words
17 #[derive(Debug, Clone, Copy, Eq)]
18 pub struct InlineStr
{
19 inner
: [u8; MAX_INLINE_STR_LEN
],
22 impl<'a
> AsRef
<str> for InlineStr
{
23 fn as_ref(&self) -> &str {
28 impl Hash
for InlineStr
{
29 fn hash
<H
: Hasher
>(&self, state
: &mut H
) {
30 self.deref().hash(state
);
34 impl From
<char> for InlineStr
{
35 fn from(c
: char) -> Self {
36 let mut inner
= [0u8; MAX_INLINE_STR_LEN
];
37 c
.encode_utf8(&mut inner
);
38 inner
[MAX_INLINE_STR_LEN
- 1] = c
.len_utf8() as u8;
43 impl<'a
> std
::cmp
::PartialEq
<InlineStr
> for InlineStr
{
44 fn eq(&self, other
: &InlineStr
) -> bool
{
45 self.deref() == other
.deref()
49 impl TryFrom
<&str> for InlineStr
{
50 type Error
= StringTooLongError
;
52 fn try_from(s
: &str) -> Result
<InlineStr
, StringTooLongError
> {
54 if len
< MAX_INLINE_STR_LEN
{
55 let mut inner
= [0u8; MAX_INLINE_STR_LEN
];
56 inner
[..len
].copy_from_slice(s
.as_bytes());
57 inner
[MAX_INLINE_STR_LEN
- 1] = len
as u8;
60 Err(StringTooLongError
)
65 impl Deref
for InlineStr
{
68 fn deref(&self) -> &str {
69 let len
= self.inner
[MAX_INLINE_STR_LEN
- 1] as usize;
70 from_utf8(&self.inner
[..len
]).unwrap()
74 impl fmt
::Display
for InlineStr
{
75 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
76 write
!(f
, "{}", self.as_ref())
80 /// A copy-on-write string that can be owned, borrowed
83 /// It is three words long.
86 /// An owned, immutable string.
88 /// A borrowed string.
90 /// A short inline string.
94 impl<'a
> AsRef
<str> for CowStr
<'a
> {
95 fn as_ref(&self) -> &str {
100 impl<'a
> Hash
for CowStr
<'a
> {
101 fn hash
<H
: Hasher
>(&self, state
: &mut H
) {
102 self.deref().hash(state
);
106 impl<'a
> std
::clone
::Clone
for CowStr
<'a
> {
107 fn clone(&self) -> Self {
109 CowStr
::Boxed(s
) => match InlineStr
::try_from(&**s
) {
110 Ok(inline
) => CowStr
::Inlined(inline
),
111 Err(..) => CowStr
::Boxed(s
.clone()),
113 CowStr
::Borrowed(s
) => CowStr
::Borrowed(s
),
114 CowStr
::Inlined(s
) => CowStr
::Inlined(*s
),
119 impl<'a
> std
::cmp
::PartialEq
<CowStr
<'a
>> for CowStr
<'a
> {
120 fn eq(&self, other
: &CowStr
) -> bool
{
121 self.deref() == other
.deref()
125 impl<'a
> From
<&'a
str> for CowStr
<'a
> {
126 fn from(s
: &'a
str) -> Self {
131 impl<'a
> From
<String
> for CowStr
<'a
> {
132 fn from(s
: String
) -> Self {
133 CowStr
::Boxed(s
.into_boxed_str())
137 impl<'a
> From
<char> for CowStr
<'a
> {
138 fn from(c
: char) -> Self {
139 CowStr
::Inlined(c
.into())
143 impl<'a
> Deref
for CowStr
<'a
> {
146 fn deref(&self) -> &str {
148 CowStr
::Boxed(ref b
) => &*b
,
149 CowStr
::Borrowed(b
) => b
,
150 CowStr
::Inlined(ref s
) => s
.deref(),
155 impl<'a
> Borrow
<str> for CowStr
<'a
> {
156 fn borrow(&self) -> &str {
161 impl<'a
> CowStr
<'a
> {
162 pub fn into_string(self) -> String
{
164 CowStr
::Boxed(b
) => b
.into(),
165 CowStr
::Borrowed(b
) => b
.to_owned(),
166 CowStr
::Inlined(s
) => s
.deref().to_owned(),
171 impl<'a
> fmt
::Display
for CowStr
<'a
> {
172 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
173 write
!(f
, "{}", self.as_ref())
178 mod test_special_string
{
182 fn inlinestr_ascii() {
183 let s
: InlineStr
= 'a'
.into();
184 assert_eq
!("a", s
.deref());
188 fn inlinestr_unicode() {
189 let s
: InlineStr
= '🍔'
.into();
190 assert_eq
!("🍔", s
.deref());
195 let size
= std
::mem
::size_of
::<CowStr
>();
196 let word_size
= std
::mem
::size_of
::<isize>();
197 assert_eq
!(3 * word_size
, size
);
201 fn cowstr_char_to_string() {
203 let smort
: CowStr
= c
.into();
204 let owned
: String
= smort
.to_string();
205 let expected
= "藏".to_owned();
206 assert_eq
!(expected
, owned
);
210 fn max_inline_str_len_atleast_five() {
211 // we need 4 bytes to store a char and then one more to store
213 assert
!(MAX_INLINE_STR_LEN
>= 5);
217 #[cfg(target_pointer_width = "64")]
218 fn inlinestr_fits_twentytwo() {
219 let s
= "0123456789abcdefghijkl";
220 let stack_str
= InlineStr
::try_from(s
).unwrap();
221 assert_eq
!(stack_str
.deref(), s
);
225 #[cfg(target_pointer_width = "64")]
226 fn inlinestr_not_fits_twentythree() {
227 let s
= "0123456789abcdefghijklm";
228 let _stack_str
= InlineStr
::try_from(s
).unwrap_err();
232 #[cfg(target_pointer_width = "64")]
233 fn small_boxed_str_clones_to_stack() {
234 let s
= "0123456789abcde".to_owned();
235 let smort
: CowStr
= s
.into();
236 let smort_clone
= smort
.clone();
238 if let CowStr
::Inlined(..) = smort_clone
{
240 panic
!("Expected a Inlined variant!");