Skip to content

Commit 72dc70d

Browse files
committed
Add support for str and &[mut] str
1 parent 5a3d850 commit 72dc70d

File tree

2 files changed

+63
-12
lines changed

2 files changed

+63
-12
lines changed

src/lib.rs

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ unsafe impl Abomonation for bool { }
336336
unsafe impl Abomonation for () { }
337337

338338
unsafe impl Abomonation for char { }
339+
unsafe impl Abomonation for str { }
339340

340341
unsafe impl Abomonation for ::std::time::Duration { }
341342

@@ -480,26 +481,63 @@ array_abomonate!(30);
480481
array_abomonate!(31);
481482
array_abomonate!(32);
482483

483-
unsafe impl Abomonation for String {
484+
unsafe impl Abomonation for &'_ str {
484485
unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
485486
write.write_all(self.as_bytes())
486487
}
487488

489+
#[inline]
490+
unsafe fn exhume<'a>(self_: NonNull<Self>, bytes: &'a mut [u8]) -> Option<&'a mut [u8]> {
491+
// FIXME: This (briefly) constructs an &str to invalid data, which is UB.
492+
// I'm not sure if this can be fully resolved without relying on &str implementation details.
493+
let self_len = self_.as_ref().len();
494+
let (s, rest) = exhume_str_ref(self_len, bytes)?;
495+
self_.as_ptr().write(s);
496+
Some(rest)
497+
}
498+
499+
fn extent(&self) -> usize {
500+
self.len()
501+
}
502+
}
503+
504+
unsafe impl Abomonation for &'_ mut str {
505+
unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
506+
<&str>::entomb(&self.as_ref(), write)
507+
}
508+
509+
#[inline]
510+
unsafe fn exhume<'a>(self_: NonNull<Self>, bytes: &'a mut [u8]) -> Option<&'a mut [u8]> {
511+
// FIXME: This (briefly) constructs an &mut str to invalid data, which is UB.
512+
// I'm not sure if this can be fully resolved without relying on &str implementation details.
513+
let self_len = self_.as_ref().len();
514+
let (s, rest) = exhume_str_ref(self_len, bytes)?;
515+
self_.as_ptr().write(s);
516+
Some(rest)
517+
}
518+
519+
fn extent(&self) -> usize {
520+
<&str>::extent(&self.as_ref())
521+
}
522+
}
523+
524+
unsafe impl Abomonation for String {
525+
unsafe fn entomb<W: Write>(&self, write: &mut W) -> IOResult<()> {
526+
<&str>::entomb(&self.as_ref(), write)
527+
}
528+
488529
#[inline]
489530
unsafe fn exhume<'a>(self_: NonNull<Self>, bytes: &'a mut [u8]) -> Option<&'a mut [u8]> {
490531
// FIXME: This (briefly) constructs an &String to invalid data, which is UB.
491532
// I'm not sure if this can be fully resolved without relying on String implementation details.
492533
let self_len = self_.as_ref().len();
493-
if self_len > bytes.len() { None }
494-
else {
495-
let (mine, rest) = bytes.split_at_mut(self_len);
496-
self_.as_ptr().write(String::from_raw_parts(mine.as_mut_ptr(), self_len, self_len));
497-
Some(rest)
498-
}
534+
let (s, rest) = exhume_str_ref(self_len, bytes)?;
535+
self_.as_ptr().write(String::from_raw_parts(s.as_mut_ptr(), s.len(), s.len()));
536+
Some(rest)
499537
}
500538

501539
fn extent(&self) -> usize {
502-
self.len()
540+
<&str>::extent(&self.as_ref())
503541
}
504542
}
505543

@@ -618,6 +656,15 @@ unsafe fn exhume_ptr<'a, T: Abomonation>(bytes: &'a mut [u8]) -> Option<(NonNull
618656
}
619657
}
620658

659+
// Common subset of "exhume" for all &str-like types
660+
unsafe fn exhume_str_ref<'a>(length: usize, bytes: &'a mut [u8]) -> Option<(&'a mut str, &'a mut [u8])> {
661+
if length > bytes.len() { None }
662+
else {
663+
let (mine, rest) = bytes.split_at_mut(length);
664+
Some((std::str::from_utf8_unchecked_mut(mine), rest))
665+
}
666+
}
667+
621668
mod network {
622669
use Abomonation;
623670
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6, IpAddr, Ipv4Addr, Ipv6Addr};

tests/tests.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ use std::fmt::Debug;
1616
#[test] fn test_string_pass() { _test_pass(vec![format!("grawwwwrr!"); 1024]); }
1717
#[test] fn test_vec_u_s_pass() { _test_pass(vec![vec![(0u64, format!("grawwwwrr!")); 32]; 32]); }
1818
#[test] fn test_ref_u64_pass() { _test_pass(vec![Some(&42u64); 1024]); }
19+
#[test] fn test_str_pass() { _test_pass(vec![&"grawwwwrr!"; 1024]); }
1920

2021
#[test] fn test_u64_fail() { _test_fail(vec![0u64; 1024]); }
2122
#[test] fn test_u128_fail() { _test_fail(vec![0u128; 1024]); }
2223
#[test] fn test_string_fail() { _test_fail(vec![format!("grawwwwrr!"); 1024]); }
2324
#[test] fn test_vec_u_s_fail() { _test_fail(vec![vec![(0u64, format!("grawwwwrr!")); 32]; 32]); }
2425
#[test] fn test_ref_u64_fail() { _test_fail(vec![Some(&42u64); 1024]); }
26+
#[test] fn test_str_fail() { _test_fail(vec![&"grawwwwrr!"; 1024]); }
2527

2628
#[test] fn test_array_size() { _test_size(vec![[0, 1, 2]; 1024]); }
2729
#[test] fn test_opt_vec_size() { _test_size(vec![Some(vec![0,1,2]), None]); }
@@ -34,6 +36,7 @@ use std::fmt::Debug;
3436
#[test] fn test_string_size() { _test_size(vec![format!("grawwwwrr!"); 1024]); }
3537
#[test] fn test_vec_u_s_size() { _test_size(vec![vec![(0u64, format!("grawwwwrr!")); 32]; 32]); }
3638
#[test] fn test_ref_u64_size() { _test_size(vec![Some(&42u64); 1024]); }
39+
#[test] fn test_str_size() { _test_size(vec![&"grawwwwrr!"; 1024]); }
3740

3841
#[test]
3942
fn test_phantom_data_for_non_abomonatable_type() {
@@ -67,18 +70,19 @@ fn _test_size<T: Abomonation>(record: T) {
6770

6871

6972
#[derive(Debug, Eq, PartialEq)]
70-
struct MyStruct {
73+
struct MyStruct<'a> {
7174
a: String,
7275
b: u64,
7376
c: Vec<u8>,
77+
d: &'a str,
7478
}
7579

76-
unsafe_abomonate!(MyStruct : a, b, c);
80+
unsafe_abomonate!(MyStruct<'_> : a, b, c, d);
7781

7882
#[test]
7983
fn test_macro() {
8084
// create some test data out of abomonation-approved types
81-
let record = MyStruct{ a: "test".to_owned(), b: 0, c: vec![0, 1, 2] };
85+
let record = MyStruct{ a: "test".to_owned(), b: 0, c: vec![0, 1, 2], d: &"grawwwwrr!" };
8286

8387
// encode vector into a Vec<u8>
8488
let mut bytes = Vec::new();
@@ -94,7 +98,7 @@ fn test_macro() {
9498
#[test]
9599
fn test_macro_size() {
96100
// create some test data out of abomonation-approved types
97-
let record = MyStruct{ a: "test".to_owned(), b: 0, c: vec![0, 1, 2] };
101+
let record = MyStruct{ a: "test".to_owned(), b: 0, c: vec![0, 1, 2], d: &"grawwwwrr!" };
98102

99103
// encode vector into a Vec<u8>
100104
let mut bytes = Vec::new();

0 commit comments

Comments
 (0)