Skip to content

Commit c4cd632

Browse files
committed
FEAT: Use a separate union 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" and visible in the user API.
1 parent 784ccc9 commit c4cd632

File tree

3 files changed

+128
-39
lines changed

3 files changed

+128
-39
lines changed

src/array_string.rs

Lines changed: 83 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use std::borrow::Borrow;
22
use std::cmp;
33
use std::fmt;
44
use std::hash::{Hash, Hasher};
5-
use std::mem;
65
use std::ptr;
76
use std::ops::{Deref, DerefMut};
87
use std::str;
@@ -17,6 +16,8 @@ use char::encode_utf8;
1716
#[cfg(feature="serde-1")]
1817
use serde::{Serialize, Deserialize, Serializer, Deserializer};
1918

19+
use super::MaybeUninitCopy;
20+
2021
/// A string with a fixed capacity.
2122
///
2223
/// The `ArrayString` is a string backed by a fixed size array. It keeps track
@@ -25,20 +26,25 @@ use serde::{Serialize, Deserialize, Serializer, Deserializer};
2526
/// The string is a contiguous value that you can store directly on the stack
2627
/// if needed.
2728
#[derive(Copy)]
28-
pub struct ArrayString<A: Array<Item=u8>> {
29-
// FIXME: Use Copyable union for xs when we can
30-
xs: A,
29+
pub struct ArrayString<A>
30+
where A: Array<Item=u8> + Copy
31+
{
32+
xs: MaybeUninitCopy<A>,
3133
len: A::Index,
3234
}
3335

34-
impl<A: Array<Item=u8>> Default for ArrayString<A> {
36+
impl<A> Default for ArrayString<A>
37+
where A: Array<Item=u8> + Copy
38+
{
3539
/// Return an empty `ArrayString`
3640
fn default() -> ArrayString<A> {
3741
ArrayString::new()
3842
}
3943
}
4044

41-
impl<A: Array<Item=u8>> ArrayString<A> {
45+
impl<A> ArrayString<A>
46+
where A: Array<Item=u8> + Copy
47+
{
4248
/// Create a new empty `ArrayString`.
4349
///
4450
/// Capacity is inferred from the type parameter.
@@ -54,8 +60,7 @@ impl<A: Array<Item=u8>> ArrayString<A> {
5460
pub fn new() -> ArrayString<A> {
5561
unsafe {
5662
ArrayString {
57-
// FIXME: Use Copyable union for xs when we can
58-
xs: mem::zeroed(),
63+
xs: MaybeUninitCopy::uninitialized(),
5964
len: Index::from(0),
6065
}
6166
}
@@ -91,11 +96,12 @@ impl<A: Array<Item=u8>> ArrayString<A> {
9196
/// let string = ArrayString::from_byte_string(b"hello world").unwrap();
9297
/// ```
9398
pub fn from_byte_string(b: &A) -> Result<Self, Utf8Error> {
94-
let mut arraystr = Self::new();
95-
let s = try!(str::from_utf8(b.as_slice()));
96-
let _result = arraystr.try_push_str(s);
97-
debug_assert!(_result.is_ok());
98-
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+
})
99105
}
100106

101107
/// Return the capacity of the `ArrayString`.
@@ -213,7 +219,7 @@ impl<A: Array<Item=u8>> ArrayString<A> {
213219
return Err(CapacityError::new(s));
214220
}
215221
unsafe {
216-
let dst = self.xs.as_mut_ptr().offset(self.len() as isize);
222+
let dst = self.xs.ptr_mut().offset(self.len() as isize);
217223
let src = s.as_ptr();
218224
ptr::copy_nonoverlapping(src, dst, s.len());
219225
let newl = self.len() + s.len();
@@ -307,8 +313,8 @@ impl<A: Array<Item=u8>> ArrayString<A> {
307313
let next = idx + ch.len_utf8();
308314
let len = self.len();
309315
unsafe {
310-
ptr::copy(self.xs.as_ptr().offset(next as isize),
311-
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),
312318
len - next);
313319
self.set_len(len - (next - idx));
314320
}
@@ -342,75 +348,99 @@ impl<A: Array<Item=u8>> ArrayString<A> {
342348

343349
/// Return a mutable slice of the whole string’s buffer
344350
unsafe fn raw_mut_bytes(&mut self) -> &mut [u8] {
345-
slice::from_raw_parts_mut(self.xs.as_mut_ptr(), self.capacity())
351+
slice::from_raw_parts_mut(self.xs.ptr_mut(), self.capacity())
346352
}
347353
}
348354

349-
impl<A: Array<Item=u8>> Deref for ArrayString<A> {
355+
impl<A> Deref for ArrayString<A>
356+
where A: Array<Item=u8> + Copy
357+
{
350358
type Target = str;
351359
#[inline]
352360
fn deref(&self) -> &str {
353361
unsafe {
354-
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());
355363
str::from_utf8_unchecked(sl)
356364
}
357365
}
358366
}
359367

360-
impl<A: Array<Item=u8>> DerefMut for ArrayString<A> {
368+
impl<A> DerefMut for ArrayString<A>
369+
where A: Array<Item=u8> + Copy
370+
{
361371
#[inline]
362372
fn deref_mut(&mut self) -> &mut str {
363373
unsafe {
364-
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());
365375
str::from_utf8_unchecked_mut(sl)
366376
}
367377
}
368378
}
369379

370-
impl<A: Array<Item=u8>> PartialEq for ArrayString<A> {
380+
impl<A> PartialEq for ArrayString<A>
381+
where A: Array<Item=u8> + Copy
382+
{
371383
fn eq(&self, rhs: &Self) -> bool {
372384
**self == **rhs
373385
}
374386
}
375387

376-
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+
{
377391
fn eq(&self, rhs: &str) -> bool {
378392
&**self == rhs
379393
}
380394
}
381395

382-
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+
{
383399
fn eq(&self, rhs: &ArrayString<A>) -> bool {
384400
self == &**rhs
385401
}
386402
}
387403

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

390-
impl<A: Array<Item=u8>> Hash for ArrayString<A> {
408+
impl<A> Hash for ArrayString<A>
409+
where A: Array<Item=u8> + Copy
410+
{
391411
fn hash<H: Hasher>(&self, h: &mut H) {
392412
(**self).hash(h)
393413
}
394414
}
395415

396-
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+
{
397419
fn borrow(&self) -> &str { self }
398420
}
399421

400-
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+
{
401425
fn as_ref(&self) -> &str { self }
402426
}
403427

404-
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+
{
405431
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) }
406432
}
407433

408-
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+
{
409437
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) }
410438
}
411439

412440
/// `Write` appends written data to the end of the string.
413-
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+
{
414444
fn write_char(&mut self, c: char) -> fmt::Result {
415445
self.try_push(c).map_err(|_| fmt::Error)
416446
}
@@ -420,7 +450,9 @@ impl<A: Array<Item=u8>> fmt::Write for ArrayString<A> {
420450
}
421451
}
422452

423-
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+
{
424456
fn clone(&self) -> ArrayString<A> {
425457
*self
426458
}
@@ -431,7 +463,9 @@ impl<A: Array<Item=u8> + Copy> Clone for ArrayString<A> {
431463
}
432464
}
433465

434-
impl<A: Array<Item=u8>> PartialOrd for ArrayString<A> {
466+
impl<A> PartialOrd for ArrayString<A>
467+
where A: Array<Item=u8> + Copy
468+
{
435469
fn partial_cmp(&self, rhs: &Self) -> Option<cmp::Ordering> {
436470
(**self).partial_cmp(&**rhs)
437471
}
@@ -441,7 +475,9 @@ impl<A: Array<Item=u8>> PartialOrd for ArrayString<A> {
441475
fn ge(&self, rhs: &Self) -> bool { **self >= **rhs }
442476
}
443477

444-
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+
{
445481
fn partial_cmp(&self, rhs: &str) -> Option<cmp::Ordering> {
446482
(**self).partial_cmp(rhs)
447483
}
@@ -451,7 +487,9 @@ impl<A: Array<Item=u8>> PartialOrd<str> for ArrayString<A> {
451487
fn ge(&self, rhs: &str) -> bool { &**self >= rhs }
452488
}
453489

454-
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+
{
455493
fn partial_cmp(&self, rhs: &ArrayString<A>) -> Option<cmp::Ordering> {
456494
self.partial_cmp(&**rhs)
457495
}
@@ -461,15 +499,19 @@ impl<A: Array<Item=u8>> PartialOrd<ArrayString<A>> for str {
461499
fn ge(&self, rhs: &ArrayString<A>) -> bool { self >= &**rhs }
462500
}
463501

464-
impl<A: Array<Item=u8>> Ord for ArrayString<A> {
502+
impl<A> Ord for ArrayString<A>
503+
where A: Array<Item=u8> + Copy
504+
{
465505
fn cmp(&self, rhs: &Self) -> cmp::Ordering {
466506
(**self).cmp(&**rhs)
467507
}
468508
}
469509

470510
#[cfg(feature="serde-1")]
471511
/// Requires crate feature `"serde-1"`
472-
impl<A: Array<Item=u8>> Serialize for ArrayString<A> {
512+
impl<A> Serialize for ArrayString<A>
513+
where A: Array<Item=u8> + Copy
514+
{
473515
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
474516
where S: Serializer
475517
{
@@ -479,7 +521,9 @@ impl<A: Array<Item=u8>> Serialize for ArrayString<A> {
479521

480522
#[cfg(feature="serde-1")]
481523
/// Requires crate feature `"serde-1"`
482-
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+
{
483527
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
484528
where D: Deserializer<'de>
485529
{
@@ -488,7 +532,7 @@ impl<'de, A: Array<Item=u8>> Deserialize<'de> for ArrayString<A> {
488532

489533
struct ArrayStringVisitor<A: Array<Item=u8>>(PhantomData<A>);
490534

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

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

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ mod maybe_uninit;
5656
#[path="maybe_uninit_nodrop.rs"]
5757
mod maybe_uninit;
5858

59+
mod maybe_uninit_copy;
60+
5961
use maybe_uninit::MaybeUninit;
62+
use maybe_uninit_copy::MaybeUninitCopy;
6063

6164
#[cfg(feature="serde-1")]
6265
use serde::{Serialize, Deserialize, Serializer, Deserializer};

src/maybe_uninit_copy.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
2+
use array::Array;
3+
4+
#[derive(Copy, Clone)]
5+
pub union MaybeUninitCopy<T>
6+
where T: Copy
7+
{
8+
empty: (),
9+
value: T,
10+
}
11+
12+
impl<T> MaybeUninitCopy<T>
13+
where T: Copy
14+
{
15+
/// Create a new MaybeUninit with uninitialized interior
16+
pub unsafe fn uninitialized() -> Self {
17+
Self { empty: () }
18+
}
19+
20+
/// Create a new MaybeUninit from the value `v`.
21+
pub fn from(value: T) -> Self {
22+
Self { value }
23+
}
24+
25+
// Raw pointer casts written so that we don't reference or access the
26+
// uninitialized interior value
27+
28+
/// Return a raw pointer to the start of the interior array
29+
pub fn ptr(&self) -> *const T::Item
30+
where T: Array
31+
{
32+
self as *const _ as *const T::Item
33+
}
34+
35+
/// Return a mut raw pointer to the start of the interior array
36+
pub fn ptr_mut(&mut self) -> *mut T::Item
37+
where T: Array
38+
{
39+
self as *mut _ as *mut T::Item
40+
}
41+
}
42+

0 commit comments

Comments
 (0)