Skip to content

Commit 97eb3fd

Browse files
committed
FEAT: Use a separate, and hopefully sound MaybeUninitCopy for ArrayString
This is the "real" union solution, and ArrayString can use it since its backing array is Copy. Unfortunately, we'll have to use the Copy bound on the type, making it "viral".
1 parent 7e991da commit 97eb3fd

File tree

3 files changed

+125
-44
lines changed

3 files changed

+125
-44
lines changed

src/array_string.rs

Lines changed: 83 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use char::encode_utf8;
1616
#[cfg(feature="serde-1")]
1717
use serde::{Serialize, Deserialize, Serializer, Deserializer};
1818

19+
use super::MaybeUninitCopy;
20+
1921
/// A string with a fixed capacity.
2022
///
2123
/// The `ArrayString` is a string backed by a fixed size array. It keeps track
@@ -24,19 +26,25 @@ use serde::{Serialize, Deserialize, Serializer, Deserializer};
2426
/// The string is a contiguous value that you can store directly on the stack
2527
/// if needed.
2628
#[derive(Copy)]
27-
pub struct ArrayString<A: Array<Item=u8>> {
28-
xs: A,
29+
pub struct ArrayString<A>
30+
where A: Array<Item=u8> + Copy
31+
{
32+
xs: MaybeUninitCopy<A>,
2933
len: A::Index,
3034
}
3135

32-
impl<A: Array<Item=u8>> Default for ArrayString<A> {
36+
impl<A> Default for ArrayString<A>
37+
where A: Array<Item=u8> + Copy
38+
{
3339
/// Return an empty `ArrayString`
3440
fn default() -> ArrayString<A> {
3541
ArrayString::new()
3642
}
3743
}
3844

39-
impl<A: Array<Item=u8>> ArrayString<A> {
45+
impl<A> ArrayString<A>
46+
where A: Array<Item=u8> + Copy
47+
{
4048
/// Create a new empty `ArrayString`.
4149
///
4250
/// Capacity is inferred from the type parameter.
@@ -52,7 +60,7 @@ impl<A: Array<Item=u8>> ArrayString<A> {
5260
pub fn new() -> ArrayString<A> {
5361
unsafe {
5462
ArrayString {
55-
xs: ::new_array(),
63+
xs: MaybeUninitCopy::uninitialized(),
5664
len: Index::from(0),
5765
}
5866
}
@@ -88,11 +96,12 @@ impl<A: Array<Item=u8>> ArrayString<A> {
8896
/// let string = ArrayString::from_byte_string(b"hello world").unwrap();
8997
/// ```
9098
pub fn from_byte_string(b: &A) -> Result<Self, Utf8Error> {
91-
let mut arraystr = Self::new();
92-
let s = try!(str::from_utf8(b.as_slice()));
93-
let _result = arraystr.try_push_str(s);
94-
debug_assert!(_result.is_ok());
95-
Ok(arraystr)
99+
let len = str::from_utf8(b.as_slice())?.len();
100+
debug_assert_eq!(len, A::capacity());
101+
Ok(ArrayString {
102+
xs: MaybeUninitCopy::from(*b),
103+
len: Index::from(A::capacity()),
104+
})
96105
}
97106

98107
/// Return the capacity of the `ArrayString`.
@@ -210,7 +219,7 @@ impl<A: Array<Item=u8>> ArrayString<A> {
210219
return Err(CapacityError::new(s));
211220
}
212221
unsafe {
213-
let dst = self.xs.as_mut_ptr().offset(self.len() as isize);
222+
let dst = self.xs.ptr_mut().offset(self.len() as isize);
214223
let src = s.as_ptr();
215224
ptr::copy_nonoverlapping(src, dst, s.len());
216225
let newl = self.len() + s.len();
@@ -304,8 +313,8 @@ impl<A: Array<Item=u8>> ArrayString<A> {
304313
let next = idx + ch.len_utf8();
305314
let len = self.len();
306315
unsafe {
307-
ptr::copy(self.xs.as_ptr().offset(next as isize),
308-
self.xs.as_mut_ptr().offset(idx as isize),
316+
ptr::copy(self.xs.ptr().offset(next as isize),
317+
self.xs.ptr_mut().offset(idx as isize),
309318
len - next);
310319
self.set_len(len - (next - idx));
311320
}
@@ -339,75 +348,99 @@ impl<A: Array<Item=u8>> ArrayString<A> {
339348

340349
/// Return a mutable slice of the whole string’s buffer
341350
unsafe fn raw_mut_bytes(&mut self) -> &mut [u8] {
342-
slice::from_raw_parts_mut(self.xs.as_mut_ptr(), self.capacity())
351+
slice::from_raw_parts_mut(self.xs.ptr_mut(), self.capacity())
343352
}
344353
}
345354

346-
impl<A: Array<Item=u8>> Deref for ArrayString<A> {
355+
impl<A> Deref for ArrayString<A>
356+
where A: Array<Item=u8> + Copy
357+
{
347358
type Target = str;
348359
#[inline]
349360
fn deref(&self) -> &str {
350361
unsafe {
351-
let sl = slice::from_raw_parts(self.xs.as_ptr(), self.len.to_usize());
362+
let sl = slice::from_raw_parts(self.xs.ptr(), self.len.to_usize());
352363
str::from_utf8_unchecked(sl)
353364
}
354365
}
355366
}
356367

357-
impl<A: Array<Item=u8>> DerefMut for ArrayString<A> {
368+
impl<A> DerefMut for ArrayString<A>
369+
where A: Array<Item=u8> + Copy
370+
{
358371
#[inline]
359372
fn deref_mut(&mut self) -> &mut str {
360373
unsafe {
361-
let sl = slice::from_raw_parts_mut(self.xs.as_mut_ptr(), self.len.to_usize());
374+
let sl = slice::from_raw_parts_mut(self.xs.ptr_mut(), self.len.to_usize());
362375
str::from_utf8_unchecked_mut(sl)
363376
}
364377
}
365378
}
366379

367-
impl<A: Array<Item=u8>> PartialEq for ArrayString<A> {
380+
impl<A> PartialEq for ArrayString<A>
381+
where A: Array<Item=u8> + Copy
382+
{
368383
fn eq(&self, rhs: &Self) -> bool {
369384
**self == **rhs
370385
}
371386
}
372387

373-
impl<A: Array<Item=u8>> PartialEq<str> for ArrayString<A> {
388+
impl<A> PartialEq<str> for ArrayString<A>
389+
where A: Array<Item=u8> + Copy
390+
{
374391
fn eq(&self, rhs: &str) -> bool {
375392
&**self == rhs
376393
}
377394
}
378395

379-
impl<A: Array<Item=u8>> PartialEq<ArrayString<A>> for str {
396+
impl<A> PartialEq<ArrayString<A>> for str
397+
where A: Array<Item=u8> + Copy
398+
{
380399
fn eq(&self, rhs: &ArrayString<A>) -> bool {
381400
self == &**rhs
382401
}
383402
}
384403

385-
impl<A: Array<Item=u8>> Eq for ArrayString<A> { }
404+
impl<A> Eq for ArrayString<A>
405+
where A: Array<Item=u8> + Copy
406+
{ }
386407

387-
impl<A: Array<Item=u8>> Hash for ArrayString<A> {
408+
impl<A> Hash for ArrayString<A>
409+
where A: Array<Item=u8> + Copy
410+
{
388411
fn hash<H: Hasher>(&self, h: &mut H) {
389412
(**self).hash(h)
390413
}
391414
}
392415

393-
impl<A: Array<Item=u8>> Borrow<str> for ArrayString<A> {
416+
impl<A> Borrow<str> for ArrayString<A>
417+
where A: Array<Item=u8> + Copy
418+
{
394419
fn borrow(&self) -> &str { self }
395420
}
396421

397-
impl<A: Array<Item=u8>> AsRef<str> for ArrayString<A> {
422+
impl<A> AsRef<str> for ArrayString<A>
423+
where A: Array<Item=u8> + Copy
424+
{
398425
fn as_ref(&self) -> &str { self }
399426
}
400427

401-
impl<A: Array<Item=u8>> fmt::Debug for ArrayString<A> {
428+
impl<A> fmt::Debug for ArrayString<A>
429+
where A: Array<Item=u8> + Copy
430+
{
402431
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) }
403432
}
404433

405-
impl<A: Array<Item=u8>> fmt::Display for ArrayString<A> {
434+
impl<A> fmt::Display for ArrayString<A>
435+
where A: Array<Item=u8> + Copy
436+
{
406437
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) }
407438
}
408439

409440
/// `Write` appends written data to the end of the string.
410-
impl<A: Array<Item=u8>> fmt::Write for ArrayString<A> {
441+
impl<A> fmt::Write for ArrayString<A>
442+
where A: Array<Item=u8> + Copy
443+
{
411444
fn write_char(&mut self, c: char) -> fmt::Result {
412445
self.try_push(c).map_err(|_| fmt::Error)
413446
}
@@ -417,7 +450,9 @@ impl<A: Array<Item=u8>> fmt::Write for ArrayString<A> {
417450
}
418451
}
419452

420-
impl<A: Array<Item=u8> + Copy> Clone for ArrayString<A> {
453+
impl<A> Clone for ArrayString<A>
454+
where A: Array<Item=u8> + Copy
455+
{
421456
fn clone(&self) -> ArrayString<A> {
422457
*self
423458
}
@@ -428,7 +463,9 @@ impl<A: Array<Item=u8> + Copy> Clone for ArrayString<A> {
428463
}
429464
}
430465

431-
impl<A: Array<Item=u8>> PartialOrd for ArrayString<A> {
466+
impl<A> PartialOrd for ArrayString<A>
467+
where A: Array<Item=u8> + Copy
468+
{
432469
fn partial_cmp(&self, rhs: &Self) -> Option<cmp::Ordering> {
433470
(**self).partial_cmp(&**rhs)
434471
}
@@ -438,7 +475,9 @@ impl<A: Array<Item=u8>> PartialOrd for ArrayString<A> {
438475
fn ge(&self, rhs: &Self) -> bool { **self >= **rhs }
439476
}
440477

441-
impl<A: Array<Item=u8>> PartialOrd<str> for ArrayString<A> {
478+
impl<A> PartialOrd<str> for ArrayString<A>
479+
where A: Array<Item=u8> + Copy
480+
{
442481
fn partial_cmp(&self, rhs: &str) -> Option<cmp::Ordering> {
443482
(**self).partial_cmp(rhs)
444483
}
@@ -448,7 +487,9 @@ impl<A: Array<Item=u8>> PartialOrd<str> for ArrayString<A> {
448487
fn ge(&self, rhs: &str) -> bool { &**self >= rhs }
449488
}
450489

451-
impl<A: Array<Item=u8>> PartialOrd<ArrayString<A>> for str {
490+
impl<A> PartialOrd<ArrayString<A>> for str
491+
where A: Array<Item=u8> + Copy
492+
{
452493
fn partial_cmp(&self, rhs: &ArrayString<A>) -> Option<cmp::Ordering> {
453494
self.partial_cmp(&**rhs)
454495
}
@@ -458,15 +499,19 @@ impl<A: Array<Item=u8>> PartialOrd<ArrayString<A>> for str {
458499
fn ge(&self, rhs: &ArrayString<A>) -> bool { self >= &**rhs }
459500
}
460501

461-
impl<A: Array<Item=u8>> Ord for ArrayString<A> {
502+
impl<A> Ord for ArrayString<A>
503+
where A: Array<Item=u8> + Copy
504+
{
462505
fn cmp(&self, rhs: &Self) -> cmp::Ordering {
463506
(**self).cmp(&**rhs)
464507
}
465508
}
466509

467510
#[cfg(feature="serde-1")]
468511
/// Requires crate feature `"serde-1"`
469-
impl<A: Array<Item=u8>> Serialize for ArrayString<A> {
512+
impl<A> Serialize for ArrayString<A>
513+
where A: Array<Item=u8> + Copy
514+
{
470515
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
471516
where S: Serializer
472517
{
@@ -476,7 +521,9 @@ impl<A: Array<Item=u8>> Serialize for ArrayString<A> {
476521

477522
#[cfg(feature="serde-1")]
478523
/// Requires crate feature `"serde-1"`
479-
impl<'de, A: Array<Item=u8>> Deserialize<'de> for ArrayString<A> {
524+
impl<'de, A> Deserialize<'de> for ArrayString<A>
525+
where A: Array<Item=u8> + Copy
526+
{
480527
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
481528
where D: Deserializer<'de>
482529
{
@@ -485,7 +532,7 @@ impl<'de, A: Array<Item=u8>> Deserialize<'de> for ArrayString<A> {
485532

486533
struct ArrayStringVisitor<A: Array<Item=u8>>(PhantomData<A>);
487534

488-
impl<'de, A: Array<Item=u8>> Visitor<'de> for ArrayStringVisitor<A> {
535+
impl<'de, A: Copy + Array<Item=u8>> Visitor<'de> for ArrayStringVisitor<A> {
489536
type Value = ArrayString<A>;
490537

491538
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {

src/lib.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ use std::io;
4848

4949
mod maybe_uninit;
5050
use maybe_uninit::MaybeUninit;
51+
use maybe_uninit::MaybeUninitCopy;
5152

5253
#[cfg(feature="serde-1")]
5354
use serde::{Serialize, Deserialize, Serializer, Deserializer};
@@ -65,14 +66,6 @@ pub use array_string::ArrayString;
6566
pub use errors::CapacityError;
6667

6768

68-
unsafe fn new_array<A: Array>() -> A {
69-
// Note: Returning an uninitialized value here only works
70-
// if we can be sure the data is never used. The nullable pointer
71-
// inside enum optimization conflicts with this this for example,
72-
// so we need to be extra careful. See `NoDrop` enum.
73-
mem::uninitialized()
74-
}
75-
7669
/// A vector with a fixed capacity.
7770
///
7871
/// The `ArrayVec` is a vector backed by a fixed size array. It keeps track of

src/maybe_uninit.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,47 @@ impl<T> MaybeUninit<T> {
4242
}
4343

4444

45+
/// This is like MaybeUninit, we can do it properly for T: Copy
46+
#[repr(C)]
47+
#[derive(Copy, Clone)]
48+
pub union MaybeUninitCopy<T>
49+
where T: Copy
50+
{
51+
empty: (),
52+
value: T,
53+
}
54+
55+
impl<T> MaybeUninitCopy<T>
56+
where T: Copy
57+
{
58+
/// Create a new MaybeUninit with uninitialized interior
59+
pub unsafe fn uninitialized() -> Self {
60+
Self { empty: () }
61+
}
62+
63+
/// Create a new MaybeUninit from the value `v`.
64+
pub fn from(value: T) -> Self {
65+
Self { value }
66+
}
67+
68+
// Raw pointer casts written so that we don't reference or access the
69+
// uninitialized interior value
70+
71+
/// Return a raw pointer to the start of the interior array
72+
pub fn ptr(&self) -> *const T::Item
73+
where T: Array
74+
{
75+
self as *const _ as *const T::Item
76+
}
77+
78+
/// Return a mut raw pointer to the start of the interior array
79+
pub fn ptr_mut(&mut self) -> *mut T::Item
80+
where T: Array
81+
{
82+
self as *mut _ as *mut T::Item
83+
}
84+
}
85+
4586

4687
#[test]
4788
fn test_offset() {

0 commit comments

Comments
 (0)