Coverage Report

Created: 2026-09-28 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/string_cache-0.11.0/src/atom.rs
Line
Count
Source
1
// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
2
// file at the top-level directory of this distribution.
3
//
4
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7
// option. This file may not be copied, modified, or distributed
8
// except according to those terms.
9
10
use crate::dynamic_set::{Entry, dynamic_set};
11
use crate::static_sets::StaticAtomSet;
12
use debug_unreachable::debug_unreachable;
13
14
use std::borrow::Cow;
15
use std::cmp::Ordering::{self, Equal};
16
use std::fmt;
17
use std::hash::{Hash, Hasher};
18
use std::marker::PhantomData;
19
use std::mem;
20
use std::num::NonZeroU64;
21
use std::ops;
22
use std::slice;
23
use std::str;
24
use std::sync::atomic::Ordering::SeqCst;
25
26
const DYNAMIC_TAG: u8 = 0b_00;
27
const INLINE_TAG: u8 = 0b_01; // len in upper nybble
28
const STATIC_TAG: u8 = 0b_10;
29
const TAG_MASK: u64 = 0b_11;
30
31
/// With alignment, a `*const Entry` pointer always has zeroes in its lowest `TAG_BITS` bits
32
const _: () = assert!(mem::align_of::<Entry>() >= TAG_MASK.next_power_of_two() as usize);
33
34
const LEN_OFFSET: u64 = 4;
35
const LEN_MASK: u64 = 0xF0;
36
37
const MAX_INLINE_LEN: usize = 7;
38
const STATIC_SHIFT_BITS: usize = 32;
39
40
/// Represents a string that has been interned.
41
///
42
/// While the type definition for `Atom` indicates that it generic on a particular
43
/// implementation of an atom set, you don't need to worry about this.  Atoms can be static
44
/// and come from a `StaticAtomSet` generated by the `string_cache_codegen` crate, or they
45
/// can be dynamic and created by you on an `EmptyStaticAtomSet`.
46
///
47
/// `Atom` implements `Clone` but not `Copy`, since internally atoms are reference-counted;
48
/// this means that you may need to `.clone()` an atom to keep copies to it in different
49
/// places, or when passing it to a function that takes an `Atom` rather than an `&Atom`.
50
///
51
/// ## Creating an atom at runtime
52
///
53
/// If you use `string_cache_codegen` to generate a precomputed list of atoms, your code
54
/// may then do something like read data from somewhere and extract tokens that need to be
55
/// compared to the atoms.  In this case, you can use `Atom::from(&str)` or
56
/// `Atom::from(String)`.  These create a reference-counted atom which will be
57
/// automatically freed when all references to it are dropped.
58
///
59
/// This means that your application can safely have a loop which tokenizes data, creates
60
/// atoms from the tokens, and compares the atoms to a predefined set of keywords, without
61
/// running the risk of arbitrary memory consumption from creating large numbers of atoms —
62
/// as long as your application does not store clones of the atoms it creates along the
63
/// way.
64
///
65
/// For example, the following is safe and will not consume arbitrary amounts of memory:
66
///
67
/// ```ignore
68
/// let untrusted_data = "large amounts of text ...";
69
///
70
/// for token in untrusted_data.split_whitespace() {
71
///     let atom = Atom::from(token); // interns the string
72
///
73
///     if atom == Atom::from("keyword") {
74
///         // handle that keyword
75
///     } else if atom == Atom::from("another_keyword") {
76
///         // handle that keyword
77
///     } else {
78
///         println!("unknown keyword");
79
///     }
80
/// } // atom is dropped here, so it is not kept around in memory
81
/// ```
82
///
83
/// ## Internal representation
84
///
85
/// An `Atom` is always 64 bits / 8 bytes.
86
/// The least-significant two bits form a tag to distinguish three different representations:
87
///
88
/// * `0b01`: A short string up to 7 bytes, stored inline in most-significant 56 bits.
89
///   Bits #4 to #7 (the upper nibble of the lower byte) are the length of the string.
90
/// * `0b10`: A string part of a statically-known indexed set with [perfect hashing].
91
///   The most-significant 32 bits are the index in the set.
92
/// * `0b00`: For other cases, the entire 64 bits are a heap-allocated pointer
93
///   to an entry in a global hash map.
94
///   Alignment of the allocation ensures the tag bits are indeed zero.
95
///   The entry is atomically reference-counted.
96
///   It is removed from the map and deallocated when its last `Atom` is dropped.
97
///   The map exists so that interning the same string again gives another pointer to the same entry.
98
///
99
/// In all cases, shallow 64-bit equality is equivalent to string equality.
100
///
101
/// [perfect hashing]: https://docs.rs/phf/latest/phf/
102
#[derive(PartialEq, Eq)]
103
// NOTE: Deriving PartialEq requires that a given string must always be interned the same way.
104
pub struct Atom<Static> {
105
    unsafe_data: NonZeroU64,
106
    phantom: PhantomData<Static>,
107
}
108
109
/// Static and inline atoms don’t have any allocated space. Dynamic atoms do but
110
/// are accounted for by [`malloc_size_of_dynamic_set`][crate::malloc_size_of_dynamic_set].
111
#[cfg(feature = "malloc_size_of")]
112
impl<Static: StaticAtomSet> malloc_size_of::MallocSizeOf for Atom<Static> {
113
    fn size_of(&self, _ops: &mut malloc_size_of::MallocSizeOfOps) -> usize {
114
        0
115
    }
116
}
117
118
// FIXME: bound removed from the struct definition before of this error for pack_static:
119
// "error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable"
120
// https://github.com/rust-lang/rust/issues/57563
121
impl<Static> Atom<Static> {
122
    /// For the atom!() macros
123
    #[inline(always)]
124
    #[doc(hidden)]
125
39.2k
    pub const fn pack_static(n: u32) -> Self {
126
39.2k
        Self {
127
39.2k
            unsafe_data: unsafe {
128
39.2k
                // STATIC_TAG ensures this is non-zero
129
39.2k
                NonZeroU64::new_unchecked((STATIC_TAG as u64) | ((n as u64) << STATIC_SHIFT_BITS))
130
39.2k
            },
131
39.2k
            phantom: PhantomData,
132
39.2k
        }
133
39.2k
    }
Unexecuted instantiation: <string_cache::atom::Atom<web_atoms::PrefixStaticSet>>::pack_static
<string_cache::atom::Atom<web_atoms::LocalNameStaticSet>>::pack_static
Line
Count
Source
125
36.2k
    pub const fn pack_static(n: u32) -> Self {
126
36.2k
        Self {
127
36.2k
            unsafe_data: unsafe {
128
36.2k
                // STATIC_TAG ensures this is non-zero
129
36.2k
                NonZeroU64::new_unchecked((STATIC_TAG as u64) | ((n as u64) << STATIC_SHIFT_BITS))
130
36.2k
            },
131
36.2k
            phantom: PhantomData,
132
36.2k
        }
133
36.2k
    }
<string_cache::atom::Atom<web_atoms::NamespaceStaticSet>>::pack_static
Line
Count
Source
125
3.02k
    pub const fn pack_static(n: u32) -> Self {
126
3.02k
        Self {
127
3.02k
            unsafe_data: unsafe {
128
3.02k
                // STATIC_TAG ensures this is non-zero
129
3.02k
                NonZeroU64::new_unchecked((STATIC_TAG as u64) | ((n as u64) << STATIC_SHIFT_BITS))
130
3.02k
            },
131
3.02k
            phantom: PhantomData,
132
3.02k
        }
133
3.02k
    }
Unexecuted instantiation: <string_cache::atom::Atom<_>>::pack_static
134
135
    /// For the atom!() macros
136
    #[inline(always)]
137
    #[doc(hidden)]
138
0
    pub const fn pack_inline(mut n: u64, len: u8) -> Self {
139
0
        if cfg!(target_endian = "big") {
140
0
            // Reverse order of top 7 bytes.
141
0
            // Bottom 8 bits of `n` are zero, and we need that to remain so.
142
0
            // String data is stored in top 7 bytes, tag and length in bottom byte.
143
0
            n = n.to_le() << 8;
144
0
        }
145
146
0
        let data: u64 = (INLINE_TAG as u64) | ((len as u64) << LEN_OFFSET) | n;
147
0
        Self {
148
0
            // INLINE_TAG ensures this is never zero
149
0
            unsafe_data: unsafe { NonZeroU64::new_unchecked(data) },
150
0
            phantom: PhantomData,
151
0
        }
152
0
    }
153
154
9.84M
    fn tag(&self) -> u8 {
155
9.84M
        (self.unsafe_data.get() & TAG_MASK) as u8
156
9.84M
    }
<string_cache::atom::Atom<web_atoms::PrefixStaticSet>>::tag
Line
Count
Source
154
1.08M
    fn tag(&self) -> u8 {
155
1.08M
        (self.unsafe_data.get() & TAG_MASK) as u8
156
1.08M
    }
<string_cache::atom::Atom<web_atoms::LocalNameStaticSet>>::tag
Line
Count
Source
154
4.20M
    fn tag(&self) -> u8 {
155
4.20M
        (self.unsafe_data.get() & TAG_MASK) as u8
156
4.20M
    }
<string_cache::atom::Atom<web_atoms::NamespaceStaticSet>>::tag
Line
Count
Source
154
4.55M
    fn tag(&self) -> u8 {
155
4.55M
        (self.unsafe_data.get() & TAG_MASK) as u8
156
4.55M
    }
Unexecuted instantiation: <string_cache::atom::Atom<_>>::tag
157
158
    /// Assuming DYNAMIC_TAG, return the pointer to `Entry`
159
2.46M
    fn dynamic_ptr(&self) -> *const Entry {
160
2.46M
        std::ptr::with_exposed_provenance(self.unsafe_data.get() as usize)
161
2.46M
    }
<string_cache::atom::Atom<web_atoms::PrefixStaticSet>>::dynamic_ptr
Line
Count
Source
159
131
    fn dynamic_ptr(&self) -> *const Entry {
160
131
        std::ptr::with_exposed_provenance(self.unsafe_data.get() as usize)
161
131
    }
<string_cache::atom::Atom<web_atoms::LocalNameStaticSet>>::dynamic_ptr
Line
Count
Source
159
362k
    fn dynamic_ptr(&self) -> *const Entry {
160
362k
        std::ptr::with_exposed_provenance(self.unsafe_data.get() as usize)
161
362k
    }
<string_cache::atom::Atom<web_atoms::NamespaceStaticSet>>::dynamic_ptr
Line
Count
Source
159
2.10M
    fn dynamic_ptr(&self) -> *const Entry {
160
2.10M
        std::ptr::with_exposed_provenance(self.unsafe_data.get() as usize)
161
2.10M
    }
Unexecuted instantiation: <string_cache::atom::Atom<_>>::dynamic_ptr
162
}
163
164
impl<Static: StaticAtomSet> Atom<Static> {
165
    /// Return the internal representation. For testing.
166
    #[doc(hidden)]
167
1.46M
    pub fn unsafe_data(&self) -> u64 {
168
1.46M
        self.unsafe_data.get()
169
1.46M
    }
<string_cache::atom::Atom<web_atoms::PrefixStaticSet>>::unsafe_data
Line
Count
Source
167
397k
    pub fn unsafe_data(&self) -> u64 {
168
397k
        self.unsafe_data.get()
169
397k
    }
<string_cache::atom::Atom<web_atoms::LocalNameStaticSet>>::unsafe_data
Line
Count
Source
167
767k
    pub fn unsafe_data(&self) -> u64 {
168
767k
        self.unsafe_data.get()
169
767k
    }
<string_cache::atom::Atom<web_atoms::NamespaceStaticSet>>::unsafe_data
Line
Count
Source
167
298k
    pub fn unsafe_data(&self) -> u64 {
168
298k
        self.unsafe_data.get()
169
298k
    }
Unexecuted instantiation: <string_cache::atom::Atom<_>>::unsafe_data
170
171
    /// Return true if this is a static Atom. For testing.
172
    #[doc(hidden)]
173
0
    pub fn is_static(&self) -> bool {
174
0
        self.tag() == STATIC_TAG
175
0
    }
176
177
    /// Return true if this is a dynamic Atom. For testing.
178
    #[doc(hidden)]
179
0
    pub fn is_dynamic(&self) -> bool {
180
0
        self.tag() == DYNAMIC_TAG
181
0
    }
182
183
    /// Return true if this is an inline Atom. For testing.
184
    #[doc(hidden)]
185
0
    pub fn is_inline(&self) -> bool {
186
0
        self.tag() == INLINE_TAG
187
0
    }
188
189
105k
    fn static_index(&self) -> u64 {
190
105k
        self.unsafe_data.get() >> STATIC_SHIFT_BITS
191
105k
    }
Unexecuted instantiation: <string_cache::atom::Atom<web_atoms::PrefixStaticSet>>::static_index
<string_cache::atom::Atom<web_atoms::LocalNameStaticSet>>::static_index
Line
Count
Source
189
53.1k
    fn static_index(&self) -> u64 {
190
53.1k
        self.unsafe_data.get() >> STATIC_SHIFT_BITS
191
53.1k
    }
<string_cache::atom::Atom<web_atoms::NamespaceStaticSet>>::static_index
Line
Count
Source
189
52.7k
    fn static_index(&self) -> u64 {
190
52.7k
        self.unsafe_data.get() >> STATIC_SHIFT_BITS
191
52.7k
    }
Unexecuted instantiation: <string_cache::atom::Atom<_>>::static_index
192
193
    /// Returns a hash of the string
194
    ///
195
    /// For static or dynamic atoms, it is a pre-computed high-quality hash.
196
    ///
197
    /// For inline atoms however (short strings 7 bytes or less),
198
    /// the returned value is the literal inline representation
199
    /// with string bytes packed directly in the `u64` value,
200
    /// which makes it a relatively poor-quality hash if used directly.
201
221k
    pub fn get_hash(&self) -> u64 {
202
221k
        match self.tag() {
203
            DYNAMIC_TAG => {
204
59.3k
                let entry = self.dynamic_ptr();
205
59.3k
                unsafe { (*entry).hash }
206
            }
207
335
            STATIC_TAG => Static::get().hashes[self.static_index() as usize],
208
162k
            INLINE_TAG => self.unsafe_data.get(),
209
0
            _ => unsafe { debug_unreachable!() },
210
        }
211
221k
    }
Unexecuted instantiation: <string_cache::atom::Atom<web_atoms::PrefixStaticSet>>::get_hash
<string_cache::atom::Atom<web_atoms::LocalNameStaticSet>>::get_hash
Line
Count
Source
201
110k
    pub fn get_hash(&self) -> u64 {
202
110k
        match self.tag() {
203
            DYNAMIC_TAG => {
204
7.55k
                let entry = self.dynamic_ptr();
205
7.55k
                unsafe { (*entry).hash }
206
            }
207
225
            STATIC_TAG => Static::get().hashes[self.static_index() as usize],
208
103k
            INLINE_TAG => self.unsafe_data.get(),
209
0
            _ => unsafe { debug_unreachable!() },
210
        }
211
110k
    }
<string_cache::atom::Atom<web_atoms::NamespaceStaticSet>>::get_hash
Line
Count
Source
201
110k
    pub fn get_hash(&self) -> u64 {
202
110k
        match self.tag() {
203
            DYNAMIC_TAG => {
204
51.8k
                let entry = self.dynamic_ptr();
205
51.8k
                unsafe { (*entry).hash }
206
            }
207
110
            STATIC_TAG => Static::get().hashes[self.static_index() as usize],
208
58.9k
            INLINE_TAG => self.unsafe_data.get(),
209
0
            _ => unsafe { debug_unreachable!() },
210
        }
211
110k
    }
Unexecuted instantiation: <string_cache::atom::Atom<_>>::get_hash
212
213
0
    pub fn try_static(string_to_add: &str) -> Option<Self> {
214
0
        Self::try_static_internal(string_to_add).ok()
215
0
    }
216
217
132k
    fn try_static_internal(string_to_add: &str) -> Result<Self, phf_shared::Hashes> {
218
132k
        let static_set = Static::get();
219
132k
        let hash = phf_shared::hash(string_to_add, &static_set.key);
220
132k
        let index = phf_shared::get_index(&hash, static_set.disps, static_set.atoms.len());
221
222
132k
        if static_set.atoms[index as usize] == string_to_add {
223
39.2k
            Ok(Self::pack_static(index))
224
        } else {
225
93.1k
            Err(hash)
226
        }
227
132k
    }
<string_cache::atom::Atom<web_atoms::PrefixStaticSet>>::try_static_internal
Line
Count
Source
217
8
    fn try_static_internal(string_to_add: &str) -> Result<Self, phf_shared::Hashes> {
218
8
        let static_set = Static::get();
219
8
        let hash = phf_shared::hash(string_to_add, &static_set.key);
220
8
        let index = phf_shared::get_index(&hash, static_set.disps, static_set.atoms.len());
221
222
8
        if static_set.atoms[index as usize] == string_to_add {
223
0
            Ok(Self::pack_static(index))
224
        } else {
225
8
            Err(hash)
226
        }
227
8
    }
<string_cache::atom::Atom<web_atoms::LocalNameStaticSet>>::try_static_internal
Line
Count
Source
217
91.1k
    fn try_static_internal(string_to_add: &str) -> Result<Self, phf_shared::Hashes> {
218
91.1k
        let static_set = Static::get();
219
91.1k
        let hash = phf_shared::hash(string_to_add, &static_set.key);
220
91.1k
        let index = phf_shared::get_index(&hash, static_set.disps, static_set.atoms.len());
221
222
91.1k
        if static_set.atoms[index as usize] == string_to_add {
223
36.2k
            Ok(Self::pack_static(index))
224
        } else {
225
54.9k
            Err(hash)
226
        }
227
91.1k
    }
<string_cache::atom::Atom<web_atoms::NamespaceStaticSet>>::try_static_internal
Line
Count
Source
217
41.2k
    fn try_static_internal(string_to_add: &str) -> Result<Self, phf_shared::Hashes> {
218
41.2k
        let static_set = Static::get();
219
41.2k
        let hash = phf_shared::hash(string_to_add, &static_set.key);
220
41.2k
        let index = phf_shared::get_index(&hash, static_set.disps, static_set.atoms.len());
221
222
41.2k
        if static_set.atoms[index as usize] == string_to_add {
223
3.02k
            Ok(Self::pack_static(index))
224
        } else {
225
38.2k
            Err(hash)
226
        }
227
41.2k
    }
Unexecuted instantiation: <string_cache::atom::Atom<_>>::try_static_internal
228
229
    /// Get a reference to the underlying str.
230
    #[inline]
231
1.24M
    pub fn as_str(&self) -> &str {
232
1.24M
        self // auto-deref
233
1.24M
    }
<string_cache::atom::Atom<web_atoms::PrefixStaticSet>>::as_str
Line
Count
Source
231
398k
    pub fn as_str(&self) -> &str {
232
398k
        self // auto-deref
233
398k
    }
<string_cache::atom::Atom<web_atoms::LocalNameStaticSet>>::as_str
Line
Count
Source
231
834k
    pub fn as_str(&self) -> &str {
232
834k
        self // auto-deref
233
834k
    }
<string_cache::atom::Atom<web_atoms::NamespaceStaticSet>>::as_str
Line
Count
Source
231
16.8k
    pub fn as_str(&self) -> &str {
232
16.8k
        self // auto-deref
233
16.8k
    }
Unexecuted instantiation: <string_cache::atom::Atom<_>>::as_str
234
235
    /// Get a reference to the bytes of the underlying str.
236
    #[inline]
237
893k
    pub fn as_bytes(&self) -> &[u8] {
238
893k
        self.as_str().as_bytes()
239
893k
    }
<string_cache::atom::Atom<web_atoms::PrefixStaticSet>>::as_bytes
Line
Count
Source
237
41.7k
    pub fn as_bytes(&self) -> &[u8] {
238
41.7k
        self.as_str().as_bytes()
239
41.7k
    }
<string_cache::atom::Atom<web_atoms::LocalNameStaticSet>>::as_bytes
Line
Count
Source
237
834k
    pub fn as_bytes(&self) -> &[u8] {
238
834k
        self.as_str().as_bytes()
239
834k
    }
<string_cache::atom::Atom<web_atoms::NamespaceStaticSet>>::as_bytes
Line
Count
Source
237
16.8k
    pub fn as_bytes(&self) -> &[u8] {
238
16.8k
        self.as_str().as_bytes()
239
16.8k
    }
Unexecuted instantiation: <string_cache::atom::Atom<_>>::as_bytes
240
}
241
242
impl<Static: StaticAtomSet> Default for Atom<Static> {
243
    #[inline]
244
0
    fn default() -> Self {
245
0
        Atom::pack_inline(0, 0)
246
0
    }
247
}
248
249
impl<Static: StaticAtomSet> Hash for Atom<Static> {
250
    #[inline]
251
221k
    fn hash<H>(&self, state: &mut H)
252
221k
    where
253
221k
        H: Hasher,
254
    {
255
221k
        state.write_u64(self.get_hash())
256
221k
    }
Unexecuted instantiation: <string_cache::atom::Atom<web_atoms::PrefixStaticSet> as core::hash::Hash>::hash::<std::hash::random::DefaultHasher>
<string_cache::atom::Atom<web_atoms::LocalNameStaticSet> as core::hash::Hash>::hash::<std::hash::random::DefaultHasher>
Line
Count
Source
251
110k
    fn hash<H>(&self, state: &mut H)
252
110k
    where
253
110k
        H: Hasher,
254
    {
255
110k
        state.write_u64(self.get_hash())
256
110k
    }
<string_cache::atom::Atom<web_atoms::NamespaceStaticSet> as core::hash::Hash>::hash::<std::hash::random::DefaultHasher>
Line
Count
Source
251
110k
    fn hash<H>(&self, state: &mut H)
252
110k
    where
253
110k
        H: Hasher,
254
    {
255
110k
        state.write_u64(self.get_hash())
256
110k
    }
Unexecuted instantiation: <string_cache::atom::Atom<_> as core::hash::Hash>::hash::<_>
257
}
258
259
impl<'a, Static: StaticAtomSet> From<Cow<'a, str>> for Atom<Static> {
260
869k
    fn from(string_to_add: Cow<'a, str>) -> Self {
261
869k
        let len = string_to_add.len();
262
869k
        if len <= MAX_INLINE_LEN {
263
737k
            let mut data: u64 = (INLINE_TAG as u64) | ((len as u64) << LEN_OFFSET);
264
737k
            {
265
737k
                let dest = inline_atom_slice_mut(&mut data);
266
737k
                dest[..len].copy_from_slice(string_to_add.as_bytes());
267
737k
            }
268
737k
            Atom {
269
737k
                // INLINE_TAG ensures this is never zero
270
737k
                unsafe_data: unsafe { NonZeroU64::new_unchecked(data) },
271
737k
                phantom: PhantomData,
272
737k
            }
273
        } else {
274
132k
            Self::try_static_internal(&string_to_add).unwrap_or_else(|hash| {
275
                // Reconstitute 64-bit `Hash128::h1`
276
                // https://docs.rs/phf_shared/0.14.0/src/phf_shared/lib.rs.html#45-54
277
93.1k
                let hash = (hash.g as u64) << 32 | (hash.f1 as u64);
278
93.1k
                let ptr: std::ptr::NonNull<Entry> = dynamic_set().insert(string_to_add, hash);
279
93.1k
                let data = ptr.as_ptr().expose_provenance() as u64;
280
93.1k
                debug_assert!(0 == data & TAG_MASK);
281
93.1k
                Atom {
282
93.1k
                    // The address of a ptr::NonNull is non-zero
283
93.1k
                    unsafe_data: unsafe { NonZeroU64::new_unchecked(data) },
284
93.1k
                    phantom: PhantomData,
285
93.1k
                }
286
93.1k
            })
<string_cache::atom::Atom<web_atoms::PrefixStaticSet> as core::convert::From<alloc::borrow::Cow<str>>>::from::{closure#0}
Line
Count
Source
274
8
            Self::try_static_internal(&string_to_add).unwrap_or_else(|hash| {
275
                // Reconstitute 64-bit `Hash128::h1`
276
                // https://docs.rs/phf_shared/0.14.0/src/phf_shared/lib.rs.html#45-54
277
8
                let hash = (hash.g as u64) << 32 | (hash.f1 as u64);
278
8
                let ptr: std::ptr::NonNull<Entry> = dynamic_set().insert(string_to_add, hash);
279
8
                let data = ptr.as_ptr().expose_provenance() as u64;
280
8
                debug_assert!(0 == data & TAG_MASK);
281
8
                Atom {
282
8
                    // The address of a ptr::NonNull is non-zero
283
8
                    unsafe_data: unsafe { NonZeroU64::new_unchecked(data) },
284
8
                    phantom: PhantomData,
285
8
                }
286
8
            })
<string_cache::atom::Atom<web_atoms::LocalNameStaticSet> as core::convert::From<alloc::borrow::Cow<str>>>::from::{closure#0}
Line
Count
Source
274
54.9k
            Self::try_static_internal(&string_to_add).unwrap_or_else(|hash| {
275
                // Reconstitute 64-bit `Hash128::h1`
276
                // https://docs.rs/phf_shared/0.14.0/src/phf_shared/lib.rs.html#45-54
277
54.9k
                let hash = (hash.g as u64) << 32 | (hash.f1 as u64);
278
54.9k
                let ptr: std::ptr::NonNull<Entry> = dynamic_set().insert(string_to_add, hash);
279
54.9k
                let data = ptr.as_ptr().expose_provenance() as u64;
280
54.9k
                debug_assert!(0 == data & TAG_MASK);
281
54.9k
                Atom {
282
54.9k
                    // The address of a ptr::NonNull is non-zero
283
54.9k
                    unsafe_data: unsafe { NonZeroU64::new_unchecked(data) },
284
54.9k
                    phantom: PhantomData,
285
54.9k
                }
286
54.9k
            })
<string_cache::atom::Atom<web_atoms::NamespaceStaticSet> as core::convert::From<alloc::borrow::Cow<str>>>::from::{closure#0}
Line
Count
Source
274
38.2k
            Self::try_static_internal(&string_to_add).unwrap_or_else(|hash| {
275
                // Reconstitute 64-bit `Hash128::h1`
276
                // https://docs.rs/phf_shared/0.14.0/src/phf_shared/lib.rs.html#45-54
277
38.2k
                let hash = (hash.g as u64) << 32 | (hash.f1 as u64);
278
38.2k
                let ptr: std::ptr::NonNull<Entry> = dynamic_set().insert(string_to_add, hash);
279
38.2k
                let data = ptr.as_ptr().expose_provenance() as u64;
280
38.2k
                debug_assert!(0 == data & TAG_MASK);
281
38.2k
                Atom {
282
38.2k
                    // The address of a ptr::NonNull is non-zero
283
38.2k
                    unsafe_data: unsafe { NonZeroU64::new_unchecked(data) },
284
38.2k
                    phantom: PhantomData,
285
38.2k
                }
286
38.2k
            })
Unexecuted instantiation: <string_cache::atom::Atom<_> as core::convert::From<alloc::borrow::Cow<str>>>::from::{closure#0}
287
        }
288
869k
    }
<string_cache::atom::Atom<web_atoms::PrefixStaticSet> as core::convert::From<alloc::borrow::Cow<str>>>::from
Line
Count
Source
260
102k
    fn from(string_to_add: Cow<'a, str>) -> Self {
261
102k
        let len = string_to_add.len();
262
102k
        if len <= MAX_INLINE_LEN {
263
102k
            let mut data: u64 = (INLINE_TAG as u64) | ((len as u64) << LEN_OFFSET);
264
102k
            {
265
102k
                let dest = inline_atom_slice_mut(&mut data);
266
102k
                dest[..len].copy_from_slice(string_to_add.as_bytes());
267
102k
            }
268
102k
            Atom {
269
102k
                // INLINE_TAG ensures this is never zero
270
102k
                unsafe_data: unsafe { NonZeroU64::new_unchecked(data) },
271
102k
                phantom: PhantomData,
272
102k
            }
273
        } else {
274
8
            Self::try_static_internal(&string_to_add).unwrap_or_else(|hash| {
275
                // Reconstitute 64-bit `Hash128::h1`
276
                // https://docs.rs/phf_shared/0.14.0/src/phf_shared/lib.rs.html#45-54
277
                let hash = (hash.g as u64) << 32 | (hash.f1 as u64);
278
                let ptr: std::ptr::NonNull<Entry> = dynamic_set().insert(string_to_add, hash);
279
                let data = ptr.as_ptr().expose_provenance() as u64;
280
                debug_assert!(0 == data & TAG_MASK);
281
                Atom {
282
                    // The address of a ptr::NonNull is non-zero
283
                    unsafe_data: unsafe { NonZeroU64::new_unchecked(data) },
284
                    phantom: PhantomData,
285
                }
286
            })
287
        }
288
102k
    }
<string_cache::atom::Atom<web_atoms::LocalNameStaticSet> as core::convert::From<alloc::borrow::Cow<str>>>::from
Line
Count
Source
260
710k
    fn from(string_to_add: Cow<'a, str>) -> Self {
261
710k
        let len = string_to_add.len();
262
710k
        if len <= MAX_INLINE_LEN {
263
619k
            let mut data: u64 = (INLINE_TAG as u64) | ((len as u64) << LEN_OFFSET);
264
619k
            {
265
619k
                let dest = inline_atom_slice_mut(&mut data);
266
619k
                dest[..len].copy_from_slice(string_to_add.as_bytes());
267
619k
            }
268
619k
            Atom {
269
619k
                // INLINE_TAG ensures this is never zero
270
619k
                unsafe_data: unsafe { NonZeroU64::new_unchecked(data) },
271
619k
                phantom: PhantomData,
272
619k
            }
273
        } else {
274
91.1k
            Self::try_static_internal(&string_to_add).unwrap_or_else(|hash| {
275
                // Reconstitute 64-bit `Hash128::h1`
276
                // https://docs.rs/phf_shared/0.14.0/src/phf_shared/lib.rs.html#45-54
277
                let hash = (hash.g as u64) << 32 | (hash.f1 as u64);
278
                let ptr: std::ptr::NonNull<Entry> = dynamic_set().insert(string_to_add, hash);
279
                let data = ptr.as_ptr().expose_provenance() as u64;
280
                debug_assert!(0 == data & TAG_MASK);
281
                Atom {
282
                    // The address of a ptr::NonNull is non-zero
283
                    unsafe_data: unsafe { NonZeroU64::new_unchecked(data) },
284
                    phantom: PhantomData,
285
                }
286
            })
287
        }
288
710k
    }
<string_cache::atom::Atom<web_atoms::NamespaceStaticSet> as core::convert::From<alloc::borrow::Cow<str>>>::from
Line
Count
Source
260
57.1k
    fn from(string_to_add: Cow<'a, str>) -> Self {
261
57.1k
        let len = string_to_add.len();
262
57.1k
        if len <= MAX_INLINE_LEN {
263
15.8k
            let mut data: u64 = (INLINE_TAG as u64) | ((len as u64) << LEN_OFFSET);
264
15.8k
            {
265
15.8k
                let dest = inline_atom_slice_mut(&mut data);
266
15.8k
                dest[..len].copy_from_slice(string_to_add.as_bytes());
267
15.8k
            }
268
15.8k
            Atom {
269
15.8k
                // INLINE_TAG ensures this is never zero
270
15.8k
                unsafe_data: unsafe { NonZeroU64::new_unchecked(data) },
271
15.8k
                phantom: PhantomData,
272
15.8k
            }
273
        } else {
274
41.2k
            Self::try_static_internal(&string_to_add).unwrap_or_else(|hash| {
275
                // Reconstitute 64-bit `Hash128::h1`
276
                // https://docs.rs/phf_shared/0.14.0/src/phf_shared/lib.rs.html#45-54
277
                let hash = (hash.g as u64) << 32 | (hash.f1 as u64);
278
                let ptr: std::ptr::NonNull<Entry> = dynamic_set().insert(string_to_add, hash);
279
                let data = ptr.as_ptr().expose_provenance() as u64;
280
                debug_assert!(0 == data & TAG_MASK);
281
                Atom {
282
                    // The address of a ptr::NonNull is non-zero
283
                    unsafe_data: unsafe { NonZeroU64::new_unchecked(data) },
284
                    phantom: PhantomData,
285
                }
286
            })
287
        }
288
57.1k
    }
Unexecuted instantiation: <string_cache::atom::Atom<_> as core::convert::From<alloc::borrow::Cow<str>>>::from
289
}
290
291
impl<Static: StaticAtomSet> Clone for Atom<Static> {
292
    #[inline(always)]
293
2.44M
    fn clone(&self) -> Self {
294
2.44M
        if self.tag() == DYNAMIC_TAG {
295
863k
            let entry = self.dynamic_ptr();
296
            // SAFETY: `self` is a valid Atom, meaning its `unsafe_data` points to a live `Entry`
297
            // kept alive by `self`'s reference count. We can safely dereference it.
298
863k
            if unsafe { &*entry }.ref_count.fetch_add(1, SeqCst) == isize::MAX {
299
0
                std::process::abort();
300
863k
            }
301
1.58M
        }
302
2.44M
        Atom { ..*self }
303
2.44M
    }
<string_cache::atom::Atom<web_atoms::NamespaceStaticSet> as core::clone::Clone>::clone
Line
Count
Source
293
1.27M
    fn clone(&self) -> Self {
294
1.27M
        if self.tag() == DYNAMIC_TAG {
295
741k
            let entry = self.dynamic_ptr();
296
            // SAFETY: `self` is a valid Atom, meaning its `unsafe_data` points to a live `Entry`
297
            // kept alive by `self`'s reference count. We can safely dereference it.
298
741k
            if unsafe { &*entry }.ref_count.fetch_add(1, SeqCst) == isize::MAX {
299
0
                std::process::abort();
300
741k
            }
301
537k
        }
302
1.27M
        Atom { ..*self }
303
1.27M
    }
<string_cache::atom::Atom<web_atoms::LocalNameStaticSet> as core::clone::Clone>::clone
Line
Count
Source
293
996k
    fn clone(&self) -> Self {
294
996k
        if self.tag() == DYNAMIC_TAG {
295
91.1k
            let entry = self.dynamic_ptr();
296
            // SAFETY: `self` is a valid Atom, meaning its `unsafe_data` points to a live `Entry`
297
            // kept alive by `self`'s reference count. We can safely dereference it.
298
91.1k
            if unsafe { &*entry }.ref_count.fetch_add(1, SeqCst) == isize::MAX {
299
0
                std::process::abort();
300
91.1k
            }
301
905k
        }
302
996k
        Atom { ..*self }
303
996k
    }
Unexecuted instantiation: <string_cache::atom::Atom<web_atoms::LocalNameStaticSet> as core::clone::Clone>::clone
Unexecuted instantiation: <string_cache::atom::Atom<web_atoms::NamespaceStaticSet> as core::clone::Clone>::clone
<string_cache::atom::Atom<web_atoms::PrefixStaticSet> as core::clone::Clone>::clone
Line
Count
Source
293
106k
    fn clone(&self) -> Self {
294
106k
        if self.tag() == DYNAMIC_TAG {
295
27
            let entry = self.dynamic_ptr();
296
            // SAFETY: `self` is a valid Atom, meaning its `unsafe_data` points to a live `Entry`
297
            // kept alive by `self`'s reference count. We can safely dereference it.
298
27
            if unsafe { &*entry }.ref_count.fetch_add(1, SeqCst) == isize::MAX {
299
0
                std::process::abort();
300
27
            }
301
106k
        }
302
106k
        Atom { ..*self }
303
106k
    }
<string_cache::atom::Atom<web_atoms::LocalNameStaticSet> as core::clone::Clone>::clone
Line
Count
Source
293
32.4k
    fn clone(&self) -> Self {
294
32.4k
        if self.tag() == DYNAMIC_TAG {
295
15.8k
            let entry = self.dynamic_ptr();
296
            // SAFETY: `self` is a valid Atom, meaning its `unsafe_data` points to a live `Entry`
297
            // kept alive by `self`'s reference count. We can safely dereference it.
298
15.8k
            if unsafe { &*entry }.ref_count.fetch_add(1, SeqCst) == isize::MAX {
299
0
                std::process::abort();
300
15.8k
            }
301
16.6k
        }
302
32.4k
        Atom { ..*self }
303
32.4k
    }
<string_cache::atom::Atom<web_atoms::NamespaceStaticSet> as core::clone::Clone>::clone
Line
Count
Source
293
32.4k
    fn clone(&self) -> Self {
294
32.4k
        if self.tag() == DYNAMIC_TAG {
295
15.0k
            let entry = self.dynamic_ptr();
296
            // SAFETY: `self` is a valid Atom, meaning its `unsafe_data` points to a live `Entry`
297
            // kept alive by `self`'s reference count. We can safely dereference it.
298
15.0k
            if unsafe { &*entry }.ref_count.fetch_add(1, SeqCst) == isize::MAX {
299
0
                std::process::abort();
300
15.0k
            }
301
17.4k
        }
302
32.4k
        Atom { ..*self }
303
32.4k
    }
Unexecuted instantiation: <string_cache::atom::Atom<_> as core::clone::Clone>::clone
304
}
305
306
impl<Static> Drop for Atom<Static> {
307
    #[inline]
308
5.04M
    fn drop(&mut self) {
309
5.04M
        if self.tag() == DYNAMIC_TAG {
310
956k
            let entry = self.dynamic_ptr();
311
956k
            if unsafe { &*entry }.ref_count.fetch_sub(1, SeqCst) == 1 {
312
31.4k
                drop_slow(self)
313
925k
            }
314
4.09M
        }
315
316
        // Out of line to guide inlining.
317
        #[cold]
318
31.4k
        fn drop_slow<Static>(this: &mut Atom<Static>) {
319
31.4k
            dynamic_set().remove(this.dynamic_ptr().cast_mut());
320
31.4k
        }
<string_cache::atom::Atom<_> as core::ops::drop::Drop>::drop::drop_slow::<web_atoms::PrefixStaticSet>
Line
Count
Source
318
6
        fn drop_slow<Static>(this: &mut Atom<Static>) {
319
6
            dynamic_set().remove(this.dynamic_ptr().cast_mut());
320
6
        }
<string_cache::atom::Atom<_> as core::ops::drop::Drop>::drop::drop_slow::<web_atoms::LocalNameStaticSet>
Line
Count
Source
318
30.6k
        fn drop_slow<Static>(this: &mut Atom<Static>) {
319
30.6k
            dynamic_set().remove(this.dynamic_ptr().cast_mut());
320
30.6k
        }
<string_cache::atom::Atom<_> as core::ops::drop::Drop>::drop::drop_slow::<web_atoms::NamespaceStaticSet>
Line
Count
Source
318
802
        fn drop_slow<Static>(this: &mut Atom<Static>) {
319
802
            dynamic_set().remove(this.dynamic_ptr().cast_mut());
320
802
        }
Unexecuted instantiation: <string_cache::atom::Atom<_> as core::ops::drop::Drop>::drop::drop_slow::<_>
321
5.04M
    }
<string_cache::atom::Atom<web_atoms::PrefixStaticSet> as core::ops::drop::Drop>::drop
Line
Count
Source
308
580k
    fn drop(&mut self) {
309
580k
        if self.tag() == DYNAMIC_TAG {
310
35
            let entry = self.dynamic_ptr();
311
35
            if unsafe { &*entry }.ref_count.fetch_sub(1, SeqCst) == 1 {
312
6
                drop_slow(self)
313
29
            }
314
580k
        }
315
316
        // Out of line to guide inlining.
317
        #[cold]
318
        fn drop_slow<Static>(this: &mut Atom<Static>) {
319
            dynamic_set().remove(this.dynamic_ptr().cast_mut());
320
        }
321
580k
    }
<string_cache::atom::Atom<web_atoms::LocalNameStaticSet> as core::ops::drop::Drop>::drop
Line
Count
Source
308
2.18M
    fn drop(&mut self) {
309
2.18M
        if self.tag() == DYNAMIC_TAG {
310
161k
            let entry = self.dynamic_ptr();
311
161k
            if unsafe { &*entry }.ref_count.fetch_sub(1, SeqCst) == 1 {
312
30.6k
                drop_slow(self)
313
131k
            }
314
2.02M
        }
315
316
        // Out of line to guide inlining.
317
        #[cold]
318
        fn drop_slow<Static>(this: &mut Atom<Static>) {
319
            dynamic_set().remove(this.dynamic_ptr().cast_mut());
320
        }
321
2.18M
    }
<string_cache::atom::Atom<web_atoms::NamespaceStaticSet> as core::ops::drop::Drop>::drop
Line
Count
Source
308
2.27M
    fn drop(&mut self) {
309
2.27M
        if self.tag() == DYNAMIC_TAG {
310
794k
            let entry = self.dynamic_ptr();
311
794k
            if unsafe { &*entry }.ref_count.fetch_sub(1, SeqCst) == 1 {
312
802
                drop_slow(self)
313
794k
            }
314
1.48M
        }
315
316
        // Out of line to guide inlining.
317
        #[cold]
318
        fn drop_slow<Static>(this: &mut Atom<Static>) {
319
            dynamic_set().remove(this.dynamic_ptr().cast_mut());
320
        }
321
2.27M
    }
Unexecuted instantiation: <string_cache::atom::Atom<_> as core::ops::drop::Drop>::drop
322
}
323
324
impl<Static: StaticAtomSet> ops::Deref for Atom<Static> {
325
    type Target = str;
326
327
    #[inline]
328
2.12M
    fn deref(&self) -> &str {
329
        unsafe {
330
2.12M
            match self.tag() {
331
                DYNAMIC_TAG => {
332
556k
                    let entry = self.dynamic_ptr();
333
556k
                    &(*entry).string
334
                }
335
                INLINE_TAG => {
336
1.46M
                    let len = (self.unsafe_data() & LEN_MASK) >> LEN_OFFSET;
337
1.46M
                    debug_assert!(len as usize <= MAX_INLINE_LEN);
338
1.46M
                    let src = inline_atom_slice(&self.unsafe_data);
339
1.46M
                    str::from_utf8_unchecked(src.get_unchecked(..(len as usize)))
340
                }
341
105k
                STATIC_TAG => Static::get().atoms[self.static_index() as usize],
342
0
                _ => debug_unreachable!(),
343
            }
344
        }
345
2.12M
    }
<string_cache::atom::Atom<web_atoms::PrefixStaticSet> as core::ops::deref::Deref>::deref
Line
Count
Source
328
398k
    fn deref(&self) -> &str {
329
        unsafe {
330
398k
            match self.tag() {
331
                DYNAMIC_TAG => {
332
63
                    let entry = self.dynamic_ptr();
333
63
                    &(*entry).string
334
                }
335
                INLINE_TAG => {
336
397k
                    let len = (self.unsafe_data() & LEN_MASK) >> LEN_OFFSET;
337
397k
                    debug_assert!(len as usize <= MAX_INLINE_LEN);
338
397k
                    let src = inline_atom_slice(&self.unsafe_data);
339
397k
                    str::from_utf8_unchecked(src.get_unchecked(..(len as usize)))
340
                }
341
0
                STATIC_TAG => Static::get().atoms[self.static_index() as usize],
342
0
                _ => debug_unreachable!(),
343
            }
344
        }
345
398k
    }
<string_cache::atom::Atom<web_atoms::LocalNameStaticSet> as core::ops::deref::Deref>::deref
Line
Count
Source
328
875k
    fn deref(&self) -> &str {
329
        unsafe {
330
875k
            match self.tag() {
331
                DYNAMIC_TAG => {
332
55.1k
                    let entry = self.dynamic_ptr();
333
55.1k
                    &(*entry).string
334
                }
335
                INLINE_TAG => {
336
767k
                    let len = (self.unsafe_data() & LEN_MASK) >> LEN_OFFSET;
337
767k
                    debug_assert!(len as usize <= MAX_INLINE_LEN);
338
767k
                    let src = inline_atom_slice(&self.unsafe_data);
339
767k
                    str::from_utf8_unchecked(src.get_unchecked(..(len as usize)))
340
                }
341
52.9k
                STATIC_TAG => Static::get().atoms[self.static_index() as usize],
342
0
                _ => debug_unreachable!(),
343
            }
344
        }
345
875k
    }
<string_cache::atom::Atom<web_atoms::NamespaceStaticSet> as core::ops::deref::Deref>::deref
Line
Count
Source
328
852k
    fn deref(&self) -> &str {
329
        unsafe {
330
852k
            match self.tag() {
331
                DYNAMIC_TAG => {
332
501k
                    let entry = self.dynamic_ptr();
333
501k
                    &(*entry).string
334
                }
335
                INLINE_TAG => {
336
298k
                    let len = (self.unsafe_data() & LEN_MASK) >> LEN_OFFSET;
337
298k
                    debug_assert!(len as usize <= MAX_INLINE_LEN);
338
298k
                    let src = inline_atom_slice(&self.unsafe_data);
339
298k
                    str::from_utf8_unchecked(src.get_unchecked(..(len as usize)))
340
                }
341
52.6k
                STATIC_TAG => Static::get().atoms[self.static_index() as usize],
342
0
                _ => debug_unreachable!(),
343
            }
344
        }
345
852k
    }
Unexecuted instantiation: <string_cache::atom::Atom<_> as core::ops::deref::Deref>::deref
346
}
347
348
impl<Static: StaticAtomSet> fmt::Debug for Atom<Static> {
349
    #[inline]
350
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
351
0
        let ty_str = unsafe {
352
0
            match self.tag() {
353
0
                DYNAMIC_TAG => "dynamic",
354
0
                INLINE_TAG => "inline",
355
0
                STATIC_TAG => "static",
356
0
                _ => debug_unreachable!(),
357
            }
358
        };
359
360
0
        write!(f, "Atom('{}' type={})", self, ty_str)
361
0
    }
Unexecuted instantiation: <string_cache::atom::Atom<web_atoms::LocalNameStaticSet> as core::fmt::Debug>::fmt
Unexecuted instantiation: <string_cache::atom::Atom<web_atoms::PrefixStaticSet> as core::fmt::Debug>::fmt
Unexecuted instantiation: <string_cache::atom::Atom<web_atoms::NamespaceStaticSet> as core::fmt::Debug>::fmt
Unexecuted instantiation: <string_cache::atom::Atom<_> as core::fmt::Debug>::fmt
362
}
363
364
impl<Static: StaticAtomSet> PartialOrd for Atom<Static> {
365
    #[inline]
366
0
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
367
0
        Some(self.cmp(other))
368
0
    }
Unexecuted instantiation: <string_cache::atom::Atom<web_atoms::PrefixStaticSet> as core::cmp::PartialOrd>::partial_cmp
Unexecuted instantiation: <string_cache::atom::Atom<web_atoms::LocalNameStaticSet> as core::cmp::PartialOrd>::partial_cmp
Unexecuted instantiation: <string_cache::atom::Atom<web_atoms::NamespaceStaticSet> as core::cmp::PartialOrd>::partial_cmp
Unexecuted instantiation: <string_cache::atom::Atom<_> as core::cmp::PartialOrd>::partial_cmp
369
}
370
371
impl<Static: StaticAtomSet> Ord for Atom<Static> {
372
    #[inline]
373
224k
    fn cmp(&self, other: &Self) -> Ordering {
374
224k
        if self.unsafe_data == other.unsafe_data {
375
46.0k
            return Equal;
376
178k
        }
377
178k
        self.as_str().cmp(other.as_ref())
378
224k
    }
<string_cache::atom::Atom<web_atoms::PrefixStaticSet> as core::cmp::Ord>::cmp
Line
Count
Source
373
224k
    fn cmp(&self, other: &Self) -> Ordering {
374
224k
        if self.unsafe_data == other.unsafe_data {
375
46.0k
            return Equal;
376
178k
        }
377
178k
        self.as_str().cmp(other.as_ref())
378
224k
    }
Unexecuted instantiation: <string_cache::atom::Atom<web_atoms::LocalNameStaticSet> as core::cmp::Ord>::cmp
Unexecuted instantiation: <string_cache::atom::Atom<web_atoms::NamespaceStaticSet> as core::cmp::Ord>::cmp
Unexecuted instantiation: <string_cache::atom::Atom<_> as core::cmp::Ord>::cmp
379
}
380
381
// AsciiExt requires mutating methods, so we just implement the non-mutating ones.
382
// We don't need to implement is_ascii because there's no performance improvement
383
// over the one from &str.
384
impl<Static: StaticAtomSet> Atom<Static> {
385
0
    fn from_mutated_str<F: FnOnce(&mut str)>(s: &str, f: F) -> Self {
386
0
        let mut buffer = [const { mem::MaybeUninit::<u8>::uninit() }; 64];
387
388
0
        if let Some(buffer_prefix) = buffer.get_mut(..s.len()) {
389
0
            let buffer_ptr = buffer_prefix.as_mut_ptr().cast::<u8>();
390
            // SAFETY: `buffer_ptr` points to the `MaybeUninit` array.
391
            // We use `copy_nonoverlapping` to write valid data into it,
392
            // and then create a slice covering ONLY the initialized portion.
393
0
            let as_str = unsafe {
394
0
                buffer_ptr.copy_from_nonoverlapping(s.as_ptr(), s.len());
395
0
                let buffer_slice = slice::from_raw_parts_mut(buffer_ptr, s.len());
396
0
                std::str::from_utf8_unchecked_mut(buffer_slice)
397
            };
398
0
            f(as_str);
399
0
            Atom::from(&*as_str)
400
        } else {
401
0
            let mut string = s.to_owned();
402
0
            f(&mut string);
403
0
            Atom::from(string)
404
        }
405
0
    }
406
407
    /// Like [`to_ascii_uppercase`].
408
    ///
409
    /// [`to_ascii_uppercase`]: https://doc.rust-lang.org/std/ascii/trait.AsciiExt.html#tymethod.to_ascii_uppercase
410
0
    pub fn to_ascii_uppercase(&self) -> Self {
411
0
        for (i, b) in self.bytes().enumerate() {
412
0
            if let b'a'..=b'z' = b {
413
0
                return Atom::from_mutated_str(self, |s| s[i..].make_ascii_uppercase());
414
0
            }
415
        }
416
0
        self.clone()
417
0
    }
418
419
    /// Like [`to_ascii_lowercase`].
420
    ///
421
    /// [`to_ascii_lowercase`]: https://doc.rust-lang.org/std/ascii/trait.AsciiExt.html#tymethod.to_ascii_lowercase
422
0
    pub fn to_ascii_lowercase(&self) -> Self {
423
0
        for (i, b) in self.bytes().enumerate() {
424
0
            if let b'A'..=b'Z' = b {
425
0
                return Atom::from_mutated_str(self, |s| s[i..].make_ascii_lowercase());
426
0
            }
427
        }
428
0
        self.clone()
429
0
    }
430
431
    /// Like [`eq_ignore_ascii_case`].
432
    ///
433
    /// [`eq_ignore_ascii_case`]: https://doc.rust-lang.org/std/ascii/trait.AsciiExt.html#tymethod.eq_ignore_ascii_case
434
0
    pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
435
0
        (self == other) || self.eq_str_ignore_ascii_case(other)
436
0
    }
437
438
    /// Like [`eq_ignore_ascii_case`], but takes an unhashed string as `other`.
439
    ///
440
    /// [`eq_ignore_ascii_case`]: https://doc.rust-lang.org/std/ascii/trait.AsciiExt.html#tymethod.eq_ignore_ascii_case
441
0
    pub fn eq_str_ignore_ascii_case(&self, other: &str) -> bool {
442
0
        self.as_str().eq_ignore_ascii_case(other)
443
0
    }
444
}
445
446
#[inline(always)]
447
1.46M
fn inline_atom_slice(x: &NonZeroU64) -> &[u8] {
448
1.46M
    let x: *const NonZeroU64 = x;
449
1.46M
    let mut data = x as *const u8;
450
    // All except the lowest byte, which is first in little-endian, last in big-endian.
451
1.46M
    if cfg!(target_endian = "little") {
452
1.46M
        data = unsafe { data.offset(1) };
453
1.46M
    }
454
1.46M
    let len = 7;
455
1.46M
    unsafe { slice::from_raw_parts(data, len) }
456
1.46M
}
457
458
#[inline(always)]
459
737k
fn inline_atom_slice_mut(x: &mut u64) -> &mut [u8] {
460
737k
    let x: *mut u64 = x;
461
737k
    let mut data = x as *mut u8;
462
    // All except the lowest byte, which is first in little-endian, last in big-endian.
463
737k
    if cfg!(target_endian = "little") {
464
737k
        data = unsafe { data.offset(1) };
465
737k
    }
466
737k
    let len = 7;
467
737k
    unsafe { slice::from_raw_parts_mut(data, len) }
468
737k
}