domain 0.12.0

A DNS library for Rust.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
//! Working with dynamically sized types (DSTs).
//!
//! DSTs are types whose size is known at run-time instead of compile-time.
//! The primary examples of this are slices and [`str`].  While Rust provides
//! relatively good support for DSTs (e.g. they can be held by reference like
//! any other type), it has some rough edges.  The standard library tries to
//! paper over these with helpful functions and trait impls, but it does not
//! account for custom DST types.  In particular, [`new::base`] introduces a
//! large number of user-facing DSTs and needs to paper over the same rough
//! edges for all of them.
//!
//! [`new::base`]: crate::new::base
//!
//! ## Coping DSTs
//!
//! Because DSTs cannot be held by value, they must be handled and manipulated
//! through an indirection (a reference or a smart pointer of some kind).
//! Copying a DST into new container (e.g. [`Box`]) requires explicit support
//! from that container type.
//!
//! [`Box`]: https://doc.rust-lang.org/std/boxed/struct.Box.html
//!
//! This module introduces the [`UnsizedCopy`] trait (and a derive macro) that
//! types like [`str`] implement.  Container types that can support copying
//! DSTs implement [`UnsizedCopyFrom`].
//
// TODO: Example

//----------- UnsizedCopy ----------------------------------------------------

/// An extension of [`Copy`] to dynamically sized types.
///
/// This is a generalization of [`Copy`].  It is intended to simplify working
/// with DSTs that support zero-copy parsing techniques (as these are built
/// from byte sequences, they are inherently trivial to copy).
///
/// # Usage
///
/// To copy a type, call [`UnsizedCopy::unsized_copy_into()`] on the DST being
/// copied, or call [`UnsizedCopyFrom::unsized_copy_from()`] on the container
/// type to copy into.  The two function identically.
///
#[cfg_attr(
    feature = "bumpalo",
    doc = "The [`copy_to_bump()`] function is useful for copying data into [`bumpalo`]-based allocations."
)]
///
/// # Safety
///
/// A type `T` can implement `UnsizedCopy` if all of the following hold:
///
/// - It is an aggregate type (`struct`, `enum`, or `union`) and every field
///   implements [`UnsizedCopy`].
///
/// - `T::Alignment` has exactly the same alignment as `T`.
///
/// - `T::ptr_with_addr()` satisfies the documented invariants.
pub unsafe trait UnsizedCopy {
    /// Copy `self` into a new container.
    ///
    /// A new container of the specified type (which is usually inferred) is
    /// allocated, and the contents of `self` are copied into it.  This is a
    /// convenience method that calls [`unsized_copy_from()`].
    ///
    /// [`unsized_copy_from()`]: UnsizedCopyFrom::unsized_copy_from().
    #[inline]
    fn unsized_copy_into<T: UnsizedCopyFrom<Source = Self>>(&self) -> T {
        T::unsized_copy_from(self)
    }

    /// Copy `self` and return it by value.
    ///
    /// This offers equivalent functionality to the regular [`Copy`] trait,
    /// which is also why it has the same [`Sized`] bound.
    #[inline]
    fn copy(&self) -> Self
    where
        Self: Sized,
    {
        // The compiler can't tell that 'Self' is 'Copy', so we're just going
        // to copy it manually.  Hopefully this optimizes fine.

        // SAFETY: 'self' is a valid reference, and is thus safe for reads.
        unsafe { core::ptr::read(self) }
    }

    /// A type with the same alignment as `Self`.
    ///
    /// At the moment, Rust does not provide a way to determine the alignment
    /// of a dynamically sized type at compile-time.  This restriction exists
    /// because trait objects (which count as DSTs, but are not supported by
    /// [`UnsizedCopy`]) have an alignment determined by their implementation
    /// (which can vary at runtime).
    ///
    /// This associated type papers over this limitation, by simply requiring
    /// every implementation of [`UnsizedCopy`] to specify a type with the
    /// same alignment here.  This is used by internal plumbing code to know
    /// the alignment of `Self` at compile-time.
    ///
    /// ## Invariants
    ///
    /// The alignment of `Self::Alignment` must be the same as that of `Self`.
    type Alignment: Sized;

    /// Change the address of a pointer to `Self`.
    ///
    /// `Self` may be a DST, which means that references (and pointers) to it
    /// store metadata alongside the usual memory address.  For example, the
    /// metadata for a slice type is its length.  In order to construct a new
    /// instance of `Self` (as is done by copying), a new pointer must be
    /// created, and the appropriate metadata must be inserted.
    ///
    /// At the moment, Rust does not provide a way to examine this metadata
    /// for an arbitrary type.  This method papers over this limitation, and
    /// provides a way to copy the metadata from an existing pointer while
    /// changing the pointer address.
    ///
    /// # Implementing
    ///
    /// Most users will derive [`UnsizedCopy`] and so don't need to worry
    /// about this.  In any case, when Rust builds in support for extracting
    /// metadata, this function will gain a default implementation, and will
    /// eventually be deprecated.
    ///
    /// For manual implementations for unsized types:
    ///
    /// ```no_run
    /// # use domain::utils::dst::UnsizedCopy;
    /// #
    /// pub struct Foo {
    ///     a: i32,
    ///     b: [u8],
    /// }
    ///
    /// unsafe impl UnsizedCopy for Foo {
    ///     // We would like to write 'Alignment = Self' here, but we can't
    ///     // because 'Self' is not 'Sized'.  However, 'Self' is a 'struct'
    ///     // using 'repr(Rust)'; the following tuple (which implicitly also
    ///     // uses 'repr(Rust)') has the same alignment as it.
    ///     type Alignment = (i32, u8);
    ///
    ///     fn ptr_with_addr(&self, addr: *const ()) -> *const Self {
    ///         // Delegate to the same function on the last field.
    ///         //
    ///         // Rust knows that 'Self' has the same metadata as '[u8]',
    ///         // and so permits casting pointers between those types.
    ///         self.b.ptr_with_addr(addr) as *const Self
    ///     }
    /// }
    /// ```
    ///
    /// For manual implementations for sized types:
    ///
    /// ```no_run
    /// # use domain::utils::dst::UnsizedCopy;
    /// #
    /// pub struct Foo {
    ///     a: i32,
    ///     b: Option<f64>,
    /// }
    ///
    /// unsafe impl UnsizedCopy for Foo {
    ///     // Because 'Foo' is a sized type, we can use it here directly.
    ///     type Alignment = Self;
    ///
    ///     fn ptr_with_addr(&self, addr: *const ()) -> *const Self {
    ///         // Since 'Self' is 'Sized', there is no metadata.
    ///         addr.cast::<Self>()
    ///     }
    /// }
    /// ```
    ///
    /// # Invariants
    ///
    /// For the statement `let result = Self::ptr_with_addr(ptr, addr);`, the
    /// following always hold:
    ///
    /// - `result as usize == addr as usize`.
    /// - `core::ptr::metadata(result) == core::ptr::metadata(ptr)`.
    ///
    /// It is undefined behaviour for an implementation of [`UnsizedCopy`] to
    /// break these invariants.
    fn ptr_with_addr(&self, addr: *const ()) -> *const Self;
}

/// Deriving [`UnsizedCopy`] automatically.
///
/// [`UnsizedCopy`] can be derived on any aggregate type.  `enum`s and
/// `union`s are inherently [`Sized`] types, and [`UnsizedCopy`] will simply
/// require every field to implement [`Copy`] on them.  For `struct`s, all but
/// the last field need to implement [`Copy`]; the last field needs to
/// implement [`UnsizedCopy`].
///
/// Here's a simple example:
///
/// ```no_run
/// # use domain::utils::dst::UnsizedCopy;
/// struct Foo<T: ?Sized> {
///     a: u32,
///     b: Bar<T>,
/// }
///
/// # struct Bar<T: ?Sized> { data: T }
///
/// // The generated impl with 'derive(UnsizedCopy)':
/// unsafe impl<T: ?Sized> UnsizedCopy for Foo<T>
/// where
///     u32: Copy,
///     Bar<T>: UnsizedCopy,
/// {
///     // This type has the same alignment as 'Foo<T>'.
///     type Alignment = (u32, <Bar<T> as UnsizedCopy>::Alignment);
///
///     fn ptr_with_addr(&self, addr: *const ()) -> *const Self {
///         self.b.ptr_with_addr(addr) as *const Self
///     }
/// }
/// ```
pub use domain_macros::UnsizedCopy;

macro_rules! impl_primitive_unsized_copy {
    ($($type:ty),+) => {
        $(unsafe impl UnsizedCopy for $type {
            type Alignment = Self;

            fn ptr_with_addr(&self, addr: *const ()) -> *const Self {
                addr.cast::<Self>()
            }
        })+
    };
}

impl_primitive_unsized_copy!((), bool, char);
impl_primitive_unsized_copy!(u8, u16, u32, u64, u128, usize);
impl_primitive_unsized_copy!(i8, i16, i32, i64, i128, isize);
impl_primitive_unsized_copy!(f32, f64);

unsafe impl<T: ?Sized> UnsizedCopy for &T {
    type Alignment = Self;

    fn ptr_with_addr(&self, addr: *const ()) -> *const Self {
        addr.cast::<Self>()
    }
}

unsafe impl UnsizedCopy for str {
    // 'str' has no alignment.
    type Alignment = u8;

    fn ptr_with_addr(&self, addr: *const ()) -> *const Self {
        // NOTE: The Rust Reference indicates that 'str' has the same layout
        // as '[u8]' [1].  This is also the most natural layout for it.  Since
        // there's no way to construct a '*const str' from raw parts, we will
        // just construct a raw slice and transmute it.
        //
        // [1]: https://doc.rust-lang.org/reference/type-layout.html#str-layout

        self.as_bytes().ptr_with_addr(addr) as *const Self
    }
}

unsafe impl<T: UnsizedCopy> UnsizedCopy for [T] {
    type Alignment = T;

    fn ptr_with_addr(&self, addr: *const ()) -> *const Self {
        core::ptr::slice_from_raw_parts(addr.cast::<T>(), self.len())
    }
}

unsafe impl<T: UnsizedCopy, const N: usize> UnsizedCopy for [T; N] {
    type Alignment = T;

    fn ptr_with_addr(&self, addr: *const ()) -> *const Self {
        addr.cast::<Self>()
    }
}

macro_rules! impl_unsized_copy_tuple {
    ($($type:ident),*; $last:ident) => {
        unsafe impl<$($type: Copy,)* $last: ?Sized + UnsizedCopy>
        UnsizedCopy for ($($type,)* $last,) {
            type Alignment = ($($type,)* <$last>::Alignment,);

            fn ptr_with_addr(&self, addr: *const ()) -> *const Self {
                let (.., last) = self;
                last.ptr_with_addr(addr) as *const Self
            }
        }
    };
}

impl_unsized_copy_tuple!(; A);
impl_unsized_copy_tuple!(A; B);
impl_unsized_copy_tuple!(A, B; C);
impl_unsized_copy_tuple!(A, B, C; D);
impl_unsized_copy_tuple!(A, B, C, D; E);
impl_unsized_copy_tuple!(A, B, C, D, E; F);
impl_unsized_copy_tuple!(A, B, C, D, E, F; G);
impl_unsized_copy_tuple!(A, B, C, D, E, F, G; H);
impl_unsized_copy_tuple!(A, B, C, D, E, F, G, H; I);
impl_unsized_copy_tuple!(A, B, C, D, E, F, G, H, I; J);
impl_unsized_copy_tuple!(A, B, C, D, E, F, G, H, I, J; K);
impl_unsized_copy_tuple!(A, B, C, D, E, F, G, H, I, J, K; L);

//----------- UnsizedCopyFrom ------------------------------------------------

/// A container type that can be copied into.
pub trait UnsizedCopyFrom: Sized {
    /// The source type to copy from.
    type Source: ?Sized + UnsizedCopy;

    /// Create a new `Self` by copying the given value.
    fn unsized_copy_from(value: &Self::Source) -> Self;
}

#[cfg(feature = "std")]
impl<T: ?Sized + UnsizedCopy> UnsizedCopyFrom for std::boxed::Box<T> {
    type Source = T;

    fn unsized_copy_from(value: &Self::Source) -> Self {
        use std::alloc;

        let layout = alloc::Layout::for_value(value);
        let ptr = unsafe { alloc::alloc(layout) };
        if ptr.is_null() {
            alloc::handle_alloc_error(layout);
        }
        let src = value as *const _ as *const u8;
        unsafe { core::ptr::copy_nonoverlapping(src, ptr, layout.size()) };
        let ptr = value.ptr_with_addr(ptr.cast()).cast_mut();
        unsafe { std::boxed::Box::from_raw(ptr) }
    }
}

#[cfg(feature = "std")]
impl<T: ?Sized + UnsizedCopy> UnsizedCopyFrom for std::rc::Rc<T> {
    type Source = T;

    fn unsized_copy_from(value: &Self::Source) -> Self {
        use core::mem::MaybeUninit;

        /// A [`u8`] with a custom alignment.
        #[derive(Copy, Clone)]
        #[repr(C)]
        struct AlignedU8<T>([T; 0], u8);

        // TODO(1.82): Use 'Rc::new_uninit_slice()'.
        // 'impl FromIterator for Rc' describes performance characteristics.
        // For efficiency, the iterator should implement 'TrustedLen', which
        // is (currently) a nightly-only trait.  However, we can use the
        // existing 'std' types which happen to implement it.
        let size = core::mem::size_of_val(value);
        let rc: std::rc::Rc<[MaybeUninit<AlignedU8<T::Alignment>>]> =
            (0..size).map(|_| MaybeUninit::uninit()).collect();

        let src = value as *const _ as *const u8;
        let dst = std::rc::Rc::into_raw(rc).cast_mut();
        // SAFETY: 'rc' was just constructed and has never been copied.  Thus,
        //   its contents can be mutated without violating any references.
        unsafe { core::ptr::copy_nonoverlapping(src, dst.cast(), size) };

        let ptr = value.ptr_with_addr(dst.cast());
        unsafe { std::rc::Rc::from_raw(ptr) }
    }
}

#[cfg(feature = "std")]
impl<T: ?Sized + UnsizedCopy> UnsizedCopyFrom for std::sync::Arc<T> {
    type Source = T;

    fn unsized_copy_from(value: &Self::Source) -> Self {
        use core::mem::MaybeUninit;

        /// A [`u8`] with a custom alignment.
        #[derive(Copy, Clone)]
        #[repr(C)]
        struct AlignedU8<T>([T; 0], u8);

        // TODO(1.82): Use 'Arc::new_uninit_slice()'.
        // 'impl FromIterator for Arc' describes performance characteristics.
        // For efficiency, the iterator should implement 'TrustedLen', which
        // is (currently) a nightly-only trait.  However, we can use the
        // existing 'std' types which happen to implement it.
        let size = core::mem::size_of_val(value);
        let arc: std::sync::Arc<[MaybeUninit<AlignedU8<T::Alignment>>]> =
            (0..size).map(|_| MaybeUninit::uninit()).collect();

        let src = value as *const _ as *const u8;
        let dst = std::sync::Arc::into_raw(arc).cast_mut();
        // SAFETY: 'arc' was just constructed and has never been copied.  Thus,
        //   its contents can be mutated without violating any references.
        unsafe { core::ptr::copy_nonoverlapping(src, dst.cast(), size) };

        let ptr = value.ptr_with_addr(dst.cast());
        unsafe { std::sync::Arc::from_raw(ptr) }
    }
}

#[cfg(feature = "std")]
impl<T: UnsizedCopy> UnsizedCopyFrom for std::vec::Vec<T> {
    type Source = [T];

    fn unsized_copy_from(value: &Self::Source) -> Self {
        // We can't use 'impl From<&[T]> for Vec<T>', because that requires
        // 'T' to implement 'Clone'.  We could reuse the 'UnsizedCopyFrom'
        // impl for 'Box', but a manual implementation is probably better.

        let mut this = Self::with_capacity(value.len());
        let src = value.as_ptr();
        let dst = this.spare_capacity_mut() as *mut _ as *mut T;
        unsafe { core::ptr::copy_nonoverlapping(src, dst, value.len()) };
        // SAFETY: The first 'value.len()' elements are now initialized.
        unsafe { this.set_len(value.len()) };
        this
    }
}

#[cfg(feature = "std")]
impl UnsizedCopyFrom for std::string::String {
    type Source = str;

    fn unsized_copy_from(value: &Self::Source) -> Self {
        value.into()
    }
}

//----------- copy_to_bump ---------------------------------------------------

/// Copy a value into a [`Bump`] allocator.
///
/// This works with [`UnsizedCopy`] values, which extends [`Bump`]'s native
/// functionality.
///
/// [`Bump`]: bumpalo::Bump
#[cfg(feature = "bumpalo")]
#[allow(clippy::mut_from_ref)] // using a memory allocator
pub fn copy_to_bump<'a, T: ?Sized + UnsizedCopy>(
    value: &T,
    bump: &'a bumpalo::Bump,
) -> &'a mut T {
    let layout = std::alloc::Layout::for_value(value);
    let ptr = bump.alloc_layout(layout).as_ptr();
    let src = value as *const _ as *const u8;
    unsafe { core::ptr::copy_nonoverlapping(src, ptr, layout.size()) };
    let ptr = value.ptr_with_addr(ptr.cast()).cast_mut();
    unsafe { &mut *ptr }
}