mod binary;
mod map;
mod number;
mod option;
mod seq;
mod text;
pub mod tags;
use crate::{
std::{
borrow::Borrow,
fmt,
hash::{Hash, Hasher},
marker::PhantomData,
},
Result, Stream, Value,
};
#[cfg(feature = "alloc")]
use crate::std::string::String;
pub(crate) use self::number::*;
pub use self::{binary::*, text::*};
pub struct Label<'computed> {
value_computed: *const str,
backing_field_static: Option<&'static str>,
#[cfg(feature = "alloc")]
backing_field_owned: Option<String>,
_marker: PhantomData<&'computed str>,
}
unsafe impl<'computed> Send for Label<'computed> { }
unsafe impl<'computed> Sync for Label<'computed> { }
#[cfg(not(feature = "alloc"))]
impl<'computed> Clone for Label<'computed> {
fn clone(&self) -> Self {
Label {
value_computed: self.value_computed,
backing_field_static: self.backing_field_static,
_marker: PhantomData,
}
}
}
impl<'computed> Label<'computed> {
pub const fn new(label: &'static str) -> Self {
Label {
value_computed: label as *const str,
backing_field_static: Some(label),
#[cfg(feature = "alloc")]
backing_field_owned: None,
_marker: PhantomData,
}
}
pub const fn new_computed(label: &'computed str) -> Self {
Label {
value_computed: label as *const str,
backing_field_static: None,
#[cfg(feature = "alloc")]
backing_field_owned: None,
_marker: PhantomData,
}
}
pub const fn as_str(&self) -> &str {
unsafe { &*self.value_computed }
}
pub const fn as_static_str(&self) -> Option<&'static str> {
self.backing_field_static
}
}
impl<'a, 'b> PartialEq<Label<'b>> for Label<'a> {
fn eq(&self, other: &Label<'b>) -> bool {
self.as_str() == other.as_str()
}
}
impl<'a> Eq for Label<'a> {}
impl<'a> Hash for Label<'a> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_str().hash(state)
}
}
impl<'a> Borrow<str> for Label<'a> {
fn borrow(&self) -> &str {
self.as_str()
}
}
impl<'a> fmt::Debug for Label<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Label").field(&self.as_str()).finish()
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct Tag {
id: u64,
data: &'static str,
}
impl Tag {
pub const fn new(data: &'static str) -> Self {
const fn compute_id(bytes: &[u8]) -> u64 {
const K: u64 = 0x517cc1b727220a95u64;
let mut hash = 0u64;
let mut b = 0;
while b + 8 <= bytes.len() {
let i = [
bytes[b + 0],
bytes[b + 1],
bytes[b + 2],
bytes[b + 3],
bytes[b + 4],
bytes[b + 5],
bytes[b + 6],
bytes[b + 7],
];
let i = u64::from_ne_bytes(i);
hash = (hash.rotate_left(5) ^ i).wrapping_mul(K);
b += 8;
}
if b + 4 <= bytes.len() {
let i = [bytes[b + 0], bytes[b + 1], bytes[b + 2], bytes[b + 3]];
let i = u32::from_ne_bytes(i) as u64;
hash = (hash.rotate_left(5) ^ i).wrapping_mul(K);
b += 4;
}
if b + 2 <= bytes.len() {
let i = [bytes[b + 0], bytes[b + 1]];
let i = u16::from_ne_bytes(i) as u64;
hash = (hash.rotate_left(5) ^ i).wrapping_mul(K);
b += 2;
}
if b + 1 <= bytes.len() {
let i = bytes[b + 0] as u64;
hash = (hash.rotate_left(5) ^ i).wrapping_mul(K);
}
hash
}
Tag {
id: compute_id(data.as_bytes()),
data,
}
}
}
impl fmt::Debug for Tag {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Tag").field(&self.data).finish()
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Index(usize);
impl Index {
pub const fn new(index: usize) -> Self {
Index(index)
}
pub const fn new_u32(index: u32) -> Self {
Index(index as usize)
}
pub const fn to_usize(&self) -> Option<usize> {
Some(self.0)
}
pub const fn to_u32(&self) -> Option<u32> {
if self.0 <= u32::MAX as usize {
Some(self.0 as u32)
} else {
None
}
}
}
impl fmt::Debug for Index {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Index").field(&self.0).finish()
}
}
impl Value for () {
fn stream<'sval, S: Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> Result {
stream.tag(Some(&tags::RUST_UNIT), None, None)
}
}
impl Value for bool {
fn stream<'sval, S: Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> Result {
stream.bool(*self)
}
fn to_bool(&self) -> Option<bool> {
Some(*self)
}
}
#[cfg(feature = "alloc")]
mod alloc_support {
use super::*;
use crate::std::string::String;
impl<'computed> Clone for Label<'computed> {
fn clone(&self) -> Self {
if let Some(ref owned) = self.backing_field_owned {
Label::new_owned(owned.clone())
} else {
Label {
value_computed: self.value_computed,
backing_field_static: self.backing_field_static,
backing_field_owned: None,
_marker: PhantomData,
}
}
}
}
impl<'computed> Label<'computed> {
pub fn to_owned(&self) -> Label<'static> {
if let Some(backing_field_static) = self.backing_field_static {
Label::new(backing_field_static)
} else {
Label::new_owned(self.as_str().into())
}
}
}
impl Label<'static> {
pub fn new_owned(label: String) -> Self {
Label {
value_computed: label.as_str() as *const str,
backing_field_static: None,
backing_field_owned: Some(label),
_marker: PhantomData,
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn label_send_sync() {
fn assert<T: Send + Sync>() {}
assert::<Label>();
}
#[test]
fn label_static() {
let label = Label::new("a");
assert_eq!("a", label.as_static_str().unwrap());
assert_eq!("a", label.as_str());
}
#[test]
fn label_computed() {
let label = Label::new_computed("a");
assert!(label.as_static_str().is_none());
assert_eq!("a", label.as_str());
}
#[test]
fn label_eq() {
let a = Label::new("a");
let b = Label::new_computed("a");
let c = Label::new("b");
assert_eq!(a, b);
assert_ne!(a, c);
}
#[test]
fn label_clone() {
let a = Label::new("a");
let b = a.clone();
assert_eq!(a.value_computed, b.value_computed);
assert_eq!(a.backing_field_static, b.backing_field_static);
}
#[test]
fn index() {
let small = Index::new(1);
let large = Index::new(usize::MAX);
if usize::MAX > (u32::MAX as usize) {
assert!(large.to_u32().is_none());
}
assert_eq!(1, small.to_u32().unwrap());
}
#[test]
fn index_eq() {
let a = Index::new(1);
let b = Index::new_u32(1);
let c = Index::new(2);
assert_eq!(a, b);
assert_ne!(a, c);
}
#[test]
fn tag_eq() {
let a = Tag::new("a");
let b = Tag::new("a");
let c = Tag::new("b");
assert_eq!(a.id, b.id);
assert_ne!(a.id, c.id);
assert_eq!(a, b);
assert_ne!(a, c);
}
#[test]
fn tag_match() {
const A: Tag = Tag::new("a");
let a = Tag::new("a");
match a {
A => (),
_ => panic!("unexpected tag `{:?}`", a),
}
}
#[cfg(feature = "alloc")]
mod alloc_support {
use crate::data::*;
#[test]
fn label_owned() {
let label = Label::new_owned(String::from("a"));
assert!(label.as_static_str().is_none());
assert_eq!("a", label.as_str());
}
#[test]
fn label_owned_clone() {
let a = Label::new_owned(String::from("a"));
let b = a.clone();
assert_ne!(
a.backing_field_owned.as_ref().unwrap().as_ptr(),
b.backing_field_owned.as_ref().unwrap().as_ptr()
);
}
}
}