]>
git.proxmox.com Git - rustc.git/blob - vendor/pulldown-cmark/src/strings.rs
2 use std
::borrow
::{ToOwned, Borrow}
;
3 use std
::str::from_utf8
;
4 use std
::hash
::{Hash, Hasher}
;
5 use std
::convert
::AsRef
;
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 #[derive(Debug, Clone, Copy, Eq)]
16 pub struct InlineStr
{
17 inner
: [u8; MAX_INLINE_STR_LEN
],
20 impl<'a
> AsRef
<str> for InlineStr
{
21 fn as_ref(&self) -> &str {
26 impl Hash
for InlineStr
{
27 fn hash
<H
: Hasher
>(&self, state
: &mut H
) {
28 self.deref().hash(state
);
32 impl From
<char> for InlineStr
{
33 fn from(c
: char) -> Self {
34 let mut inner
= [0u8; MAX_INLINE_STR_LEN
];
35 c
.encode_utf8(&mut inner
);
36 inner
[MAX_INLINE_STR_LEN
- 1] = c
.len_utf8() as u8;
41 impl<'a
> std
::cmp
::PartialEq
<InlineStr
> for InlineStr
{
42 fn eq(&self, other
: &InlineStr
) -> bool
{
43 self.deref() == other
.deref()
47 // This could be an implementation of TryFrom<&str>
48 // when that trait is stabilized.
50 pub fn try_from_str(s
: &str) -> Result
<InlineStr
, StringTooLongError
> {
52 if len
< MAX_INLINE_STR_LEN
{
53 let mut inner
= [0u8; MAX_INLINE_STR_LEN
];
54 inner
[..len
].copy_from_slice(s
.as_bytes());
55 inner
[MAX_INLINE_STR_LEN
- 1] = len
as u8;
58 Err(StringTooLongError
)
63 impl Deref
for InlineStr
{
66 fn deref(&self) -> &str {
67 let len
= self.inner
[MAX_INLINE_STR_LEN
- 1] as usize;
68 from_utf8(&self.inner
[..len
]).unwrap()
72 impl fmt
::Display
for InlineStr
{
73 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
74 write
!(f
, "{}", self.as_ref())
85 impl<'a
> AsRef
<str> for CowStr
<'a
> {
86 fn as_ref(&self) -> &str {
91 impl<'a
> Hash
for CowStr
<'a
> {
92 fn hash
<H
: Hasher
>(&self, state
: &mut H
) {
93 self.deref().hash(state
);
97 impl<'a
> std
::clone
::Clone
for CowStr
<'a
> {
98 fn clone(&self) -> Self {
100 CowStr
::Boxed(s
) if s
.len() < MAX_INLINE_STR_LEN
101 => CowStr
::Inlined(InlineStr
::try_from_str(&**s
).unwrap()),
102 CowStr
::Boxed(s
) => CowStr
::Boxed(s
.clone()),
103 CowStr
::Borrowed(s
) => CowStr
::Borrowed(s
),
104 CowStr
::Inlined(s
) => CowStr
::Inlined(*s
),
109 impl<'a
> std
::cmp
::PartialEq
<CowStr
<'a
>> for CowStr
<'a
> {
110 fn eq(&self, other
: &CowStr
) -> bool
{
111 self.deref() == other
.deref()
115 impl<'a
> From
<&'a
str> for CowStr
<'a
> {
116 fn from(s
: &'a
str) -> Self {
121 impl<'a
> From
<String
> for CowStr
<'a
> {
122 fn from(s
: String
) -> Self {
123 CowStr
::Boxed(s
.into_boxed_str())
127 impl<'a
> From
<char> for CowStr
<'a
> {
128 fn from(c
: char) -> Self {
129 CowStr
::Inlined(c
.into())
133 impl<'a
> Deref
for CowStr
<'a
> {
136 fn deref(&self) -> &str {
138 CowStr
::Boxed(ref b
) => &*b
,
139 CowStr
::Borrowed(b
) => b
,
140 CowStr
::Inlined(ref s
) => s
.deref(),
145 impl<'a
> Borrow
<str> for CowStr
<'a
> {
146 fn borrow(&self) -> &str {
151 impl<'a
> CowStr
<'a
> {
152 pub fn into_string(self) -> String
{
154 CowStr
::Boxed(b
) => b
.into(),
155 CowStr
::Borrowed(b
) => b
.to_owned(),
156 CowStr
::Inlined(s
) => s
.deref().to_owned(),
161 impl<'a
> fmt
::Display
for CowStr
<'a
> {
162 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
163 write
!(f
, "{}", self.as_ref())
168 mod test_special_string
{
172 fn inlinestr_ascii() {
173 let s
: InlineStr
= 'a'
.into();
174 assert_eq
!("a", s
.deref());
178 fn inlinestr_unicode() {
179 let s
: InlineStr
= '🍔'
.into();
180 assert_eq
!("🍔", s
.deref());
185 let size
= std
::mem
::size_of
::<CowStr
>();
186 let word_size
= std
::mem
::size_of
::<isize>();
187 assert_eq
!(3 * word_size
, size
);
191 fn cowstr_char_to_string() {
193 let smort
: CowStr
= c
.into();
194 let owned
: String
= smort
.to_string();
195 let expected
= "藏".to_owned();
196 assert_eq
!(expected
, owned
);
200 fn max_inline_str_len_atleast_five() {
201 // we need 4 bytes to store a char and then one more to store
203 assert
!(MAX_INLINE_STR_LEN
>= 5);
207 #[cfg(target_pointer_width = "64")]
208 fn inlinestr_fits_twentytwo() {
209 let s
= "0123456789abcdefghijkl";
210 let stack_str
= InlineStr
::try_from_str(s
).unwrap();
211 assert_eq
!(stack_str
.deref(), s
);
215 #[cfg(target_pointer_width = "64")]
216 fn inlinestr_not_fits_twentythree() {
217 let s
= "0123456789abcdefghijklm";
218 let _stack_str
= InlineStr
::try_from_str(s
).unwrap_err();
222 #[cfg(target_pointer_width = "64")]
223 fn small_boxed_str_clones_to_stack() {
224 let s
= "0123456789abcde".to_owned();
225 let smort
: CowStr
= s
.into();
226 let smort_clone
= smort
.clone();
228 if let CowStr
::Inlined(..) = smort_clone {}
else {
229 panic
!("Expected a Inlined variant!");