Skip to content

Commit

Permalink
Merge pull request #8 from Aderinom/master
Browse files Browse the repository at this point in the history
Decreased Enum Size by Boxing, Changed Map to use HashMap internally, Added ByteList for STRING_EXT
  • Loading branch information
sile committed Sep 23, 2023
2 parents c52cd3b + c617f4a commit 21c83b4
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 51 deletions.
30 changes: 17 additions & 13 deletions src/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,14 +162,10 @@ impl<R: io::Read> Decoder<R> {
Ok(Term::from(List::nil()))
}
fn decode_string_ext(&mut self) -> DecodeResult {
let size = self.reader.read_u16::<BigEndian>()? as usize;
let mut elements = Vec::with_capacity(size);
for _ in 0..size {
elements.push(Term::from(FixInteger::from(i32::from(
self.reader.read_u8()?,
))));
}
Ok(Term::from(List::from(elements)))
let size = self.reader.read_u16::<BigEndian>()? as usize;
let mut bytes = vec![0; size];
self.reader.read_exact(&mut bytes)?;
Ok(Term::from(ByteList::from(bytes)))
}
fn decode_list_ext(&mut self) -> DecodeResult {
let count = self.reader.read_u32::<BigEndian>()? as usize;
Expand Down Expand Up @@ -202,13 +198,13 @@ impl<R: io::Read> Decoder<R> {
}
fn decode_map_ext(&mut self) -> DecodeResult {
let count = self.reader.read_u32::<BigEndian>()? as usize;
let mut entries = Vec::with_capacity(count);
let mut map = HashMap::<Term,Term>::new();
for _ in 0..count {
let k = self.decode_term()?;
let v = self.decode_term()?;
entries.push((k, v));
map.insert(k, v);
}
Ok(Term::from(Map::from(entries)))
Ok(Term::from(Map::from(map)))
}
fn decode_binary_ext(&mut self) -> DecodeResult {
let size = self.reader.read_u32::<BigEndian>()? as usize;
Expand Down Expand Up @@ -465,6 +461,7 @@ impl<W: io::Write> Encoder<W> {
Term::ImproperList(ref x) => self.encode_improper_list(x),
Term::Tuple(ref x) => self.encode_tuple(x),
Term::Map(ref x) => self.encode_map(x),
Term::ByteList(ref x) => self.encode_byte_list(x.bytes.as_slice())
}
}
fn encode_nil(&mut self) -> EncodeResult {
Expand Down Expand Up @@ -525,13 +522,20 @@ impl<W: io::Write> Encoder<W> {
}
fn encode_map(&mut self, x: &Map) -> EncodeResult {
self.writer.write_u8(MAP_EXT)?;
self.writer.write_u32::<BigEndian>(x.entries.len() as u32)?;
for &(ref k, ref v) in &x.entries {
self.writer.write_u32::<BigEndian>(x.map.len() as u32)?;
for (k, v) in x.map.iter() {
self.encode_term(k)?;
self.encode_term(v)?;
}
Ok(())
}
fn encode_byte_list(&mut self, x: &[u8]) -> EncodeResult{
self.writer.write_u8(STRING_EXT)?;
self.writer.write_u16::<BigEndian>(x.len() as u16)?;
self.writer.write_all(x)?;

Ok(())
}
fn encode_binary(&mut self, x: &Binary) -> EncodeResult {
self.writer.write_u8(BINARY_EXT)?;
self.writer.write_u32::<BigEndian>(x.bytes.len() as u32)?;
Expand Down
25 changes: 22 additions & 3 deletions src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ impl_term_try_as_ref!(List);
impl_term_try_as_ref!(ImproperList);
impl_term_try_as_ref!(Tuple);
impl_term_try_as_ref!(Map);
impl_term_try_as_ref!(ByteList);

macro_rules! impl_term_try_into {
($to:ident) => {
Expand All @@ -56,21 +57,39 @@ macro_rules! impl_term_try_into {
}
};
}
macro_rules! impl_term_try_into_boxed {
($to:ident) => {
impl TryInto<$to> for Term {
type Error = Self;

fn try_into(self) -> Result<$to, Self>
where
Self: Sized,
{
match self {
Term::$to(x) => Ok(*x),
_ => Err(self),
}
}
}
};
}
impl_term_try_into!(Atom);
impl_term_try_into!(FixInteger);
impl_term_try_into!(BigInteger);
impl_term_try_into!(Float);
impl_term_try_into!(Pid);
impl_term_try_into!(Port);
impl_term_try_into!(Reference);
impl_term_try_into!(ExternalFun);
impl_term_try_into!(InternalFun);
impl_term_try_into_boxed!(Reference);
impl_term_try_into_boxed!(ExternalFun);
impl_term_try_into_boxed!(InternalFun);
impl_term_try_into!(Binary);
impl_term_try_into!(BitBinary);
impl_term_try_into!(List);
impl_term_try_into!(ImproperList);
impl_term_try_into!(Tuple);
impl_term_try_into!(Map);
impl_term_try_into!(ByteList);

pub trait AsOption {
fn as_option(&self) -> Option<&Self>;
Expand Down
117 changes: 104 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
//! - [Erlang External Term Format](http://erlang.org/doc/apps/erts/erl_ext_dist.html)
//!
use num::bigint::BigInt;
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;
use std::io;

mod codec;
Expand All @@ -50,11 +52,12 @@ pub enum Term {
Float(Float),
Pid(Pid),
Port(Port),
Reference(Reference),
ExternalFun(ExternalFun),
InternalFun(InternalFun),
Reference(Box<Reference>),
ExternalFun(Box<ExternalFun>),
InternalFun(Box<InternalFun>),
Binary(Binary),
BitBinary(BitBinary),
ByteList(ByteList),
List(List),
ImproperList(ImproperList),
Tuple(Tuple),
Expand Down Expand Up @@ -92,6 +95,7 @@ impl fmt::Display for Term {
Term::InternalFun(ref x) => x.fmt(f),
Term::Binary(ref x) => x.fmt(f),
Term::BitBinary(ref x) => x.fmt(f),
Term::ByteList(ref x) => x.fmt(f),
Term::List(ref x) => x.fmt(f),
Term::ImproperList(ref x) => x.fmt(f),
Term::Tuple(ref x) => x.fmt(f),
Expand Down Expand Up @@ -131,17 +135,17 @@ impl From<Port> for Term {
}
impl From<Reference> for Term {
fn from(x: Reference) -> Self {
Term::Reference(x)
Term::Reference(Box::new(x))
}
}
impl From<ExternalFun> for Term {
fn from(x: ExternalFun) -> Self {
Term::ExternalFun(x)
Term::ExternalFun(Box::new(x))
}
}
impl From<InternalFun> for Term {
fn from(x: InternalFun) -> Self {
Term::InternalFun(x)
Term::InternalFun(Box::new(x))
}
}
impl From<Binary> for Term {
Expand All @@ -154,6 +158,16 @@ impl From<BitBinary> for Term {
Term::BitBinary(x)
}
}
impl From<ByteList> for Term {
fn from(x: ByteList) -> Self {
Term::ByteList(x)
}
}
impl From<String> for Term {
fn from(x: String) -> Self {
Term::ByteList(ByteList { bytes: x.into_bytes() })
}
}
impl From<List> for Term {
fn from(x: List) -> Self {
Term::List(x)
Expand Down Expand Up @@ -621,6 +635,55 @@ impl From<(Vec<u8>, u8)> for BitBinary {
}
}


/// Erlang has a transport optimization for lists only containing u8 elements. \
/// Since Strings in erlang are just lists with u8's they call this "STRING_EXT".
///
/// This type does not exist in erlang and is to be seen as a subtype of List.
///
/// See: https://erlang.org/doc/apps/erts/erl_ext_dist.html#STRING_EXT
///
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct ByteList {
pub bytes: Vec<u8>,
}
impl fmt::Display for ByteList {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[")?;
for (i, b) in self.bytes.iter().enumerate() {
if i != 0 {
write!(f, ",")?;
}
write!(f, "{}", b)?;
}
write!(f, "]")?;
Ok(())
}
}
impl From<String> for ByteList {
fn from(string: String) -> Self {
ByteList { bytes : string.into_bytes()}
}
}
impl From<&str> for ByteList {
fn from(string: &str) -> Self {
ByteList { bytes :string.into() }
}
}
impl From<Vec<u8>> for ByteList {
fn from(bytes: Vec<u8>) -> Self {
ByteList { bytes }
}
}
impl<const N: usize> From<&[u8;N]> for ByteList {
fn from(bytes: &[u8;N]) -> Self {
ByteList {
bytes: Vec::from(bytes.as_slice()),
}
}
}


/// List.
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct List {
Expand Down Expand Up @@ -657,6 +720,12 @@ impl From<Vec<Term>> for List {
List { elements }
}
}
impl From<ByteList> for List {
fn from(byte_list: ByteList) -> Self {
let elements = byte_list.bytes.into_iter().map(|value|Term::FixInteger(FixInteger { value: value as i32 })).collect();
List { elements }
}
}

/// Improper list.
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
Expand Down Expand Up @@ -719,14 +788,14 @@ impl From<Vec<Term>> for Tuple {
}

/// Map.
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Map {
pub entries: Vec<(Term, Term)>,
pub map: HashMap<Term, Term>,
}
impl fmt::Display for Map {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "#{{")?;
for (i, &(ref k, ref v)) in self.entries.iter().enumerate() {
for (i, (k, v)) in self.map.iter().enumerate() {
if i != 0 {
write!(f, ",")?;
}
Expand All @@ -736,9 +805,31 @@ impl fmt::Display for Map {
Ok(())
}
}
impl From<Vec<(Term, Term)>> for Map {
fn from(entries: Vec<(Term, Term)>) -> Self {
Map { entries }
impl Hash for Map {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
for (k, v) in self.map.iter() {
k.hash(state);
v.hash(state);
}
}
}
impl<const N: usize> From<[(Term,Term); N]> for Map{
fn from(from: [(Term,Term); N]) -> Self {
Map{ map : HashMap::from(from) }
}
}
impl From<HashMap<Term,Term>> for Map{
fn from(from_map: HashMap<Term,Term>) -> Self {
Map{ map :from_map }
}
}
impl From<HashMap<String,Term>> for Map{
fn from(from_map: HashMap<String,Term>) -> Self {
let mut result_map = HashMap::<Term,Term>::new();
for (k,v) in from_map {
result_map.insert(Term::from(k),v);
}
Map{ map : result_map }
}
}

Expand Down
Loading

0 comments on commit 21c83b4

Please sign in to comment.