#![feature(shared, core_intrinsics, alloc, heap_api, unique, try_from)]
extern crate alloc;
#[cfg(feature = "serde")]
extern crate serde;
#[cfg(all(test, feature = "serde"))]
extern crate serde_test;
use std::sync::atomic;
use std::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
use std::borrow;
use std::fmt;
use std::cmp::Ordering;
use std::mem::{size_of, align_of};
use std::intrinsics::abort;
use std::mem;
use std::ops::Deref;
use std::ptr::{self, Shared};
use std::hash::{Hash, Hasher};
use std::{isize, usize};
use std::convert::From;
use alloc::heap;
const MAX_REFCOUNT: usize = (isize::MAX) as usize;
pub struct ArcCStr {
ptr: Shared<u8>,
}
use std::ffi::FromBytesWithNulError;
unsafe impl Send for ArcCStr {}
unsafe impl Sync for ArcCStr {}
use std::convert::TryFrom;
impl<'a> TryFrom<&'a [u8]> for ArcCStr {
type Error = FromBytesWithNulError;
fn try_from(b: &'a [u8]) -> Result<Self, Self::Error> {
unsafe { ArcCStr::from_raw_cstr_no_nul(b) }
}
}
impl<'a> TryFrom<&'a str> for ArcCStr {
type Error = FromBytesWithNulError;
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
unsafe { ArcCStr::from_raw_cstr_no_nul(s.as_bytes()) }
}
}
impl TryFrom<String> for ArcCStr {
type Error = FromBytesWithNulError;
fn try_from(s: String) -> Result<Self, Self::Error> {
unsafe { ArcCStr::from_raw_cstr_no_nul(s.as_bytes()) }
}
}
use std::ffi::CString;
impl From<CString> for ArcCStr {
fn from(s: CString) -> Self {
unsafe { ArcCStr::from_raw_cstr_no_nul_unchecked(s.to_bytes()) }
}
}
use std::ffi::CStr;
impl<'a> From<&'a CStr> for ArcCStr {
fn from(s: &'a CStr) -> Self {
unsafe { ArcCStr::from_raw_cstr_no_nul_unchecked(s.to_bytes()) }
}
}
impl ArcCStr {
unsafe fn from_raw_cstr_no_nul(buf: &[u8]) -> Result<Self, FromBytesWithNulError> {
if buf.iter().any(|&b| b == 0) {
CStr::from_bytes_with_nul(&[0, 0])?;
}
Ok(Self::from_raw_cstr_no_nul_unchecked(buf))
}
unsafe fn from_raw_cstr_no_nul_unchecked(buf: &[u8]) -> Self {
let aus = size_of::<atomic::AtomicUsize>();
let aual = align_of::<atomic::AtomicUsize>();
let sz = aus + buf.len() + 1;
let mut s = ptr::Unique::new(heap::allocate(sz, aual));
let cstr = s.as_ptr().offset(aus as isize);
{
let atom: &mut atomic::AtomicUsize = mem::transmute(s.as_mut());
atom.store(1, SeqCst);
}
ptr::copy_nonoverlapping(buf.as_ptr(), cstr, buf.len());
*cstr.offset(buf.len() as isize) = 0u8;
ArcCStr { ptr: Shared::new(s.as_ptr().offset(0)) }
}
#[inline]
pub fn strong_count(this: &Self) -> usize {
this.atomic().load(SeqCst)
}
#[inline]
fn atomic(&self) -> &atomic::AtomicUsize {
unsafe { mem::transmute(self.ptr.as_ptr().as_ref().unwrap()) }
}
#[inline(never)]
unsafe fn drop_slow(&mut self) {
atomic::fence(Acquire);
let blen = self.to_bytes_with_nul().len();
heap::deallocate(self.ptr.as_ptr().offset(0) as *mut _,
size_of::<atomic::AtomicUsize>() + blen,
align_of::<atomic::AtomicUsize>())
}
#[inline]
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
unsafe { this.ptr.as_ptr().offset(0) == other.ptr.as_ptr().offset(0) }
}
}
impl Clone for ArcCStr {
#[inline]
fn clone(&self) -> ArcCStr {
let old_size = self.atomic().fetch_add(1, Relaxed);
if old_size > MAX_REFCOUNT {
unsafe {
abort();
}
}
ArcCStr { ptr: self.ptr }
}
}
impl Deref for ArcCStr {
type Target = CStr;
#[inline]
fn deref(&self) -> &Self::Target {
let aus = size_of::<atomic::AtomicUsize>() as isize;
unsafe { CStr::from_ptr(mem::transmute(self.ptr.as_ptr().offset(aus))) }
}
}
impl Drop for ArcCStr {
#[inline]
fn drop(&mut self) {
if self.atomic().fetch_sub(1, Release) != 1 {
return;
}
atomic::fence(Acquire);
unsafe {
self.drop_slow();
}
}
}
impl PartialEq for ArcCStr {
fn eq(&self, other: &ArcCStr) -> bool {
*(*self) == *(*other)
}
fn ne(&self, other: &ArcCStr) -> bool {
*(*self) != *(*other)
}
}
impl PartialOrd for ArcCStr {
fn partial_cmp(&self, other: &ArcCStr) -> Option<Ordering> {
(**self).partial_cmp(&**other)
}
fn lt(&self, other: &ArcCStr) -> bool {
*(*self) < *(*other)
}
fn le(&self, other: &ArcCStr) -> bool {
*(*self) <= *(*other)
}
fn gt(&self, other: &ArcCStr) -> bool {
*(*self) > *(*other)
}
fn ge(&self, other: &ArcCStr) -> bool {
*(*self) >= *(*other)
}
}
impl Ord for ArcCStr {
fn cmp(&self, other: &ArcCStr) -> Ordering {
(**self).cmp(&**other)
}
}
impl Eq for ArcCStr {}
impl fmt::Debug for ArcCStr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl fmt::Pointer for ArcCStr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Pointer::fmt(&self.ptr.as_ptr(), f)
}
}
impl Hash for ArcCStr {
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state)
}
}
impl borrow::Borrow<CStr> for ArcCStr {
fn borrow(&self) -> &CStr {
&*self
}
}
impl AsRef<CStr> for ArcCStr {
fn as_ref(&self) -> &CStr {
&**self
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for ArcCStr {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer
{
use std::slice;
let aus = size_of::<atomic::AtomicUsize>();
let len = self.to_bytes().len();
let bytes = unsafe { slice::from_raw_parts(self.ptr.as_ptr().offset(aus as isize), len) };
serializer.serialize_bytes(bytes)
}
}
struct ArcCStrVisitor;
impl<'de> serde::de::Visitor<'de> for ArcCStrVisitor {
type Value = ArcCStr;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a C-style string with no nulls as serialized bytes")
}
#[inline]
fn visit_bytes<E>(self, v: &[u8]) -> Result<ArcCStr, E>
where E: serde::de::Error
{
let s = unsafe { ArcCStr::from_raw_cstr_no_nul(v) };
let err = "a null-terminated, UTF-encoded string with no internal nulls";
s.map_err(|_| serde::de::Error::invalid_value(serde::de::Unexpected::Bytes(v), &err))
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for ArcCStr {
fn deserialize<D>(deserializer: D) -> Result<ArcCStr, D::Error>
where D: serde::Deserializer<'de>
{
deserializer.deserialize_bytes(ArcCStrVisitor)
}
}
#[cfg(test)]
mod tests {
use std::clone::Clone;
use std::sync::mpsc::channel;
use std::thread;
use super::ArcCStr;
use std::convert::TryFrom;
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn manually_share_arc() {
let v = "0123456789";
let arc_v = ArcCStr::try_from(v).unwrap();
let (tx, rx) = channel();
let _t = thread::spawn(move || {
let arc_v: ArcCStr = rx.recv().unwrap();
assert_eq!((*arc_v).to_bytes()[3], b'3');
});
tx.send(arc_v.clone()).unwrap();
assert_eq!((*arc_v).to_bytes()[2], b'2');
assert_eq!((*arc_v).to_bytes()[4], b'4');
}
#[test]
fn show_arc() {
let a = ArcCStr::try_from("foo").unwrap();
assert_eq!(format!("{:?}", a), "\"foo\"");
}
#[test]
fn test_from_string() {
let foo_arc = ArcCStr::try_from(format!("foo")).unwrap();
assert!("foo" == foo_arc.to_string_lossy());
}
#[test]
fn test_ptr_eq() {
let five = ArcCStr::try_from("5").unwrap();
let same_five = five.clone();
let other_five = ArcCStr::try_from("5").unwrap();
assert!(ArcCStr::ptr_eq(&five, &same_five));
assert!(!ArcCStr::ptr_eq(&five, &other_five));
}
#[test]
fn test_from_invalid() {
assert!(ArcCStr::try_from("5\05").is_err());
assert!(ArcCStr::try_from("5\05".to_string()).is_err());
assert!(ArcCStr::try_from(&b"5\05"[..]).is_err());
}
#[test]
fn test_back_to_str() {
assert!(ArcCStr::try_from(&b"a"[..]).unwrap().to_str().is_ok(),
"valid ASCII");
assert!(ArcCStr::try_from(&b"\xc3\xb1"[..])
.unwrap()
.to_str()
.is_ok(),
"valid 2 Octet Sequence");
assert!(ArcCStr::try_from(&b"\xc3\x28"[..])
.unwrap()
.to_str()
.is_err(),
"invalid 2 Octet Sequence");
assert!(ArcCStr::try_from(&b"\xa0\xa1"[..])
.unwrap()
.to_str()
.is_err(),
"invalid Sequence Identifier");
assert!(ArcCStr::try_from(&b"\xe2\x82\xa1"[..])
.unwrap()
.to_str()
.is_ok(),
"valid 3 Octet Sequence");
assert!(ArcCStr::try_from(&b"\xe2\x28\xa1"[..])
.unwrap()
.to_str()
.is_err(),
"invalid 3 Octet Sequence (in 2nd Octet)");
assert!(ArcCStr::try_from(&b"\xe2\x82\x28"[..])
.unwrap()
.to_str()
.is_err(),
"invalid 3 Octet Sequence (in 3rd Octet)");
assert!(ArcCStr::try_from(&b"\xf0\x90\x8c\xbc"[..])
.unwrap()
.to_str()
.is_ok(),
"valid 4 Octet Sequence");
assert!(ArcCStr::try_from(&b"\xf0\x28\x8c\xbc"[..])
.unwrap()
.to_str()
.is_err(),
"invalid 4 Octet Sequence (in 2nd Octet)");
assert!(ArcCStr::try_from(&b"\xf0\x90\x28\xbc"[..])
.unwrap()
.to_str()
.is_err(),
"invalid 4 Octet Sequence (in 3rd Octet)");
assert!(ArcCStr::try_from(&b"\xf0\x28\x8c\x28"[..])
.unwrap()
.to_str()
.is_err(),
"invalid 4 Octet Sequence (in 4th Octet)");
}
#[test]
#[cfg(feature = "serde")]
fn test_serde() {
use serde_test::{Token, assert_tokens};
let five = ArcCStr::try_from("5").unwrap();
assert_tokens(&five, &[Token::Bytes(b"5")]);
let non = ArcCStr::try_from("").unwrap();
assert_tokens(&non, &[Token::Bytes(b"")]);
}
}