Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions serde_rustler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ crate-type = ["rlib"]

[dependencies]
lazy_static = "1.4.0"
quick-error = "1.2"
rustler = "0.21.0"
rustler_codegen = "0.21.0"
thiserror = "1.0"
rustler = "0.23"
rustler_codegen = "0.23"
serde = "1.0"
61 changes: 29 additions & 32 deletions serde_rustler/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

<!-- [![GitHub tag](https://img.shields.io/github/tag/Naereen/StrapDown.js.svg)](https://GitHub.com/Naereen/StrapDown.js/tags/) -->
<!-- [![Build Status](https://semaphoreci.com/api/v1/sunny-g/xdr/branches/master/badge.svg)](https://semaphoreci.com/sunny-g/xdr) -->

[![Crates.io](https://img.shields.io/crates/v/serde_rustler.svg)](https://crates.io/crates/serde_rustler)
[![Documentation](https://docs.rs/serde_rustler/badge.svg)](https://docs.rs/serde_rustler)
[![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://lbesson.mit-license.org/)
Expand All @@ -20,12 +21,10 @@ serde_rustler = "0.0.3"
## Quick Start

```rust
#[macro_use] extern crate rustler;

use serde::{Serialize, Deserialize}
use serde_rustler::{from_term, to_term};

rustler_export_nifs! {
rustler::rustler_export_nifs! {
"Elixir.SerdeRustlerTests",
[("nif", 1, nif)],
None
Expand All @@ -48,14 +47,11 @@ fn nif<'a>(env: Env<'a>, args: &[Term<'a>]) -> NifResult<Term<'a>> {
Below is a more comprehensive example of how you might use `serde_rustler` within a rust NIF...

```rust
#[macro_use]
extern crate rustler;

use rustler::{Env, error::Error as NifError, NifResult, Term};
use serde::{Serialize, Deserialize};
use serde_rustler::{from_term, to_term};

rustler_export_nifs! {
rustler::rustler_export_nifs! {
"Elixir.SerdeNif",
[("readme", 1, readme)],
None
Expand Down Expand Up @@ -137,27 +133,27 @@ end

### Conversion Table

| Type Name | Serde (Rust) Values | Elixir Terms (default behaviour) | `deserialize_any` into Elixir Term |
|-----|-----|-----|-----|
| bool | `true` or `false` | `true` or `false` | `true` or `false` |
| <sup>[1](#todo)</sup> number | `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`, `f32`, `f64` (TODO: `i128` and `u128`) | `number` | `number` as `f64`, `i64`, or `u64` |
| char | `'A'` | `[u32]` | `[u32]` |
| string | `""` | `bitstring` | `bitstring` |
| byte array | `&[u8]` or `Vec<u8>` | `<<_::_*8>>` | `bitstring` |
| option | `Some(T)` or `None` | `T` or `:nil` | `T` or `:nil` |
| unit | `None` | `:nil` | `:nil` |
| unit struct | `struct Unit` | `:nil` | `:nil` |
| <sup>[3](#atom)</sup> unit variant | `E::A` in `enum UnitVariant { A }` | `:A` | `"A"` |
| <sup>[3](#atom)</sup> newtype struct | `struct Millimeters(u8)` | `{:Millimeters, u8}` | `["Millimeters", u8]` |
| <sup>[3](#atom)</sup> newtype variant | `E::N` in `enum E { N(u8) }` | `{:N, u8}` | `["N", u8]` |
| <sup>[3](#atom)</sup> newtype variant (any `Ok` and `Err` tagged enum) | `enum R<T, E> { Ok(T), Err(E) }` | `{:ok, T}` or `{:error, E}` | `["Ok", T]` or `["Err", E]` |
| seq | `Vec<T>` | `[T,]` | `[T,]` |
| tuple | `(u8,)` | `{u8,}` | `[u8,]` |
| <sup>[3](#atom)</sup> tuple struct | `struct Rgb(u8, u8, u8)` | `{:Rgb, u8, u8, u8}` | `["Rgb", u8, u8, u8]` |
| <sup>[3](#atom)</sup> tuple variant | `E::T` in `enum E { T(u8, u8) }` | `{:T, u8, u8}` | `["T", u8, u8]` |
| <sup>[1](#todo)</sup> map | `HashMap<K, V>` | `%{}` | `%{}` |
| <sup>[3](#atom)</sup> struct | `struct Rgb { r: u8, g: u8, b: u8 }` | `%Rgb{ r: u8, g: u8, b: u8 }` | `%{"r" => u8, "g" => u8, "b" => u8}` |
| <sup>[3](#atom)</sup> struct variant | `E::S` in `enum E { Rgb { r: u8, g: u8, b: u8 } }` | `%Rgb{ r: u8, g: u8, b: u8 }` | `%{"r" => u8, "g" => u8, "b" => u8}` |
| Type Name | Serde (Rust) Values | Elixir Terms (default behaviour) | `deserialize_any` into Elixir Term |
| ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------- | ------------------------------------ |
| bool | `true` or `false` | `true` or `false` | `true` or `false` |
| <sup>[1](#todo)</sup> number | `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64`, `f32`, `f64` (TODO: `i128` and `u128`) | `number` | `number` as `f64`, `i64`, or `u64` |
| char | `'A'` | `[u32]` | `[u32]` |
| string | `""` | `bitstring` | `bitstring` |
| byte array | `&[u8]` or `Vec<u8>` | `<<_::_*8>>` | `bitstring` |
| option | `Some(T)` or `None` | `T` or `:nil` | `T` or `:nil` |
| unit | `None` | `:nil` | `:nil` |
| unit struct | `struct Unit` | `:nil` | `:nil` |
| <sup>[3](#atom)</sup> unit variant | `E::A` in `enum UnitVariant { A }` | `:A` | `"A"` |
| <sup>[3](#atom)</sup> newtype struct | `struct Millimeters(u8)` | `{:Millimeters, u8}` | `["Millimeters", u8]` |
| <sup>[3](#atom)</sup> newtype variant | `E::N` in `enum E { N(u8) }` | `{:N, u8}` | `["N", u8]` |
| <sup>[3](#atom)</sup> newtype variant (any `Ok` and `Err` tagged enum) | `enum R<T, E> { Ok(T), Err(E) }` | `{:ok, T}` or `{:error, E}` | `["Ok", T]` or `["Err", E]` |
| seq | `Vec<T>` | `[T,]` | `[T,]` |
| tuple | `(u8,)` | `{u8,}` | `[u8,]` |
| <sup>[3](#atom)</sup> tuple struct | `struct Rgb(u8, u8, u8)` | `{:Rgb, u8, u8, u8}` | `["Rgb", u8, u8, u8]` |
| <sup>[3](#atom)</sup> tuple variant | `E::T` in `enum E { T(u8, u8) }` | `{:T, u8, u8}` | `["T", u8, u8]` |
| <sup>[1](#todo)</sup> map | `HashMap<K, V>` | `%{}` | `%{}` |
| <sup>[3](#atom)</sup> struct | `struct Rgb { r: u8, g: u8, b: u8 }` | `%Rgb{ r: u8, g: u8, b: u8 }` | `%{"r" => u8, "g" => u8, "b" => u8}` |
| <sup>[3](#atom)</sup> struct variant | `E::S` in `enum E { Rgb { r: u8, g: u8, b: u8 } }` | `%Rgb{ r: u8, g: u8, b: u8 }` | `%{"r" => u8, "g" => u8, "b" => u8}` |

<a name="todo">1</a>: API still being decided / implemented.

Expand All @@ -166,6 +162,7 @@ end
## Benchmarks

To run:

```sh
cd serde_rustler_tests
MIX_ENV=bench mix run test/benchmarks.exs
Expand All @@ -189,11 +186,11 @@ Also take note of the results for any test taking longer than 1ms or tests invol

## Changelog

| Version | Change Summary |
| ------- | ---------------|
| Version | Change Summary |
| ------------------------------------------------------ | -------------------------------------------------- |
| [v0.0.3](https://crates.io/crates/serde_rustler/0.0.3) | better `char` and `tuple` support, adds benchmarks |
| [v0.0.2](https://crates.io/crates/serde_rustler/0.0.2) | cleanup, better `deserialize_any` support |
| [v0.0.1](https://crates.io/crates/serde_rustler/0.0.1) | initial release |
| [v0.0.2](https://crates.io/crates/serde_rustler/0.0.2) | cleanup, better `deserialize_any` support |
| [v0.0.1](https://crates.io/crates/serde_rustler/0.0.1) | initial release |

## Contributing

Expand Down
16 changes: 8 additions & 8 deletions serde_rustler/src/atoms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,29 @@
use crate::Error;
use rustler::{types::atom::Atom, Encoder, Env, Term};

lazy_static! {
lazy_static::lazy_static! {
pub static ref OK: String = String::from("Ok");
pub static ref ERROR: String = String::from("Err");
}

rustler_atoms! {
rustler::atoms! {
/// The atom `nil`.
atom nil;
nil,

/// The atom `:ok`.
atom ok;
ok,

/// The atom `:error`.
atom error;
error,

/// The atom/Boolean `true`.
atom true_ = "true";
true_ = "true",

/// The atom/Boolean `false`.
atom false_ = "false";
false_ = "false",

/// The atom `:__struct__`.
atom __struct__;
__struct__,
}

/**
Expand Down
222 changes: 109 additions & 113 deletions serde_rustler/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,119 +1,115 @@
use quick_error::quick_error;
use std::fmt::Display;

use rustler::Error as NifError;
use serde::{de, ser};
use std::fmt::Display;
use thiserror::Error;

quick_error! {
#[derive(Debug)]
pub enum Error {
DeserializationError(err: String) {
display("{}", err)
}
TypeHintsRequired {
display("Cannot deserialize any, type hints are required")
}
InvalidAtom {
display("Failed to deserialize atom")
}
InvalidBoolean {
display("Failed to deserialize boolean")
}
InvalidNumber {
display("Failed to deserialize number")
}
InvalidStringable {
display("Failed to deserialize term as an &str")
}
InvalidList {
display("Failed to deserialize list")
}
InvalidTuple {
display("Failed to deserialize tuple")
}
InvalidSequenceElement {
display("Failed to deserialize sequence element")
}

ExpectedAtom {
display("Expected to deserialize atom")
}
ExpectedBoolean {
display("Expected to deserialize boolean")
}
ExpectedBinary {
display("Expected to deserialize binary")
}
ExpectedNumber {
display("Expected to deserialize number")
}
ExpectedChar {
display("Expected to deserialize char")
}
ExpectedStringable {
display("Expected to deserialize a UTF-8 stringable term")
}
ExpectedNil {
display("Expected to deserialize nil")
}
ExpectedList {
display("Expected to deserialize list")
}
ExpectedTuple {
display("Expected to deserialize tuple")
}
ExpectedEnum {
display("Expected to deserialize enum")
}
ExpectedMap {
display("Expected to deserialize map")
}
ExpectedStruct {
display("Expected to deserialize struct")
}
ExpectedStructName {
display("Expected to deserialize struct name")
}
ExpectedStructValue {
display("Expected to deserialize struct value")
}
ExpectedUnitVariant {
display("Expected to deserialize unit variant")
}
ExpectedNewtypeStruct {
display("Expected to deserialize newtype struct tuple")
}
ExpectedNewtypeVariant {
display("Expected to deserialize newtype variant")
}
ExpectedTupleVariant {
display("Expected to deserialize tuple variant")
}
ExpectedStructVariant {
display("Expected to deserialize struct variant")
}

SerializationError(err: String) {
display("{}", err)
}
InvalidVariantName {
display("Failed to serialize variant to atom or string")
}
InvalidStructName {
display("Failed to serialize struct name to atom or string")
}
InvalidBinary {
display("Failed to serialize binary")
}
InvalidMap {
display("Failed to serialize map to NIF map")
}
InvalidStruct {
display("Failed to serialize struct to NIF struct")
}
InvalidStructKey {
display("Failed to serialize struct key")
}
}
#[derive(Debug, Error)]
pub enum Error {
#[error("{0}")]
DeserializationError(String),

#[error("Cannot deserialize any, type hints are required")]
TypeHintsRequired,

#[error("Failed to deserialize atom")]
InvalidAtom,

#[error("Failed to deserialize boolean")]
InvalidBoolean,

#[error("Failed to deserialize number")]
InvalidNumber,

#[error("Failed to deserialize term as an &str")]
InvalidStringable,

#[error("Failed to deserialize list")]
InvalidList,

#[error("Failed to deserialize tuple")]
InvalidTuple,

#[error("Failed to deserialize sequence element")]
InvalidSequenceElement,

#[error("Expected to deserialize atom")]
ExpectedAtom,

#[error("Expected to deserialize boolean")]
ExpectedBoolean,

#[error("Expected to deserialize binary")]
ExpectedBinary,

#[error("Expected to deserialize number")]
ExpectedNumber,

#[error("Expected to deserialize char")]
ExpectedChar,

#[error("Expected to deserialize a UTF-8 stringable term")]
ExpectedStringable,

#[error("Expected to deserialize nil")]
ExpectedNil,

#[error("Expected to deserialize list")]
ExpectedList,

#[error("Expected to deserialize tuple")]
ExpectedTuple,

#[error("Expected to deserialize enum")]
ExpectedEnum,

#[error("Expected to deserialize map")]
ExpectedMap,

#[error("Expected to deserialize struct")]
ExpectedStruct,

#[error("Expected to deserialize struct name")]
ExpectedStructName,

#[error("Expected to deserialize struct value")]
ExpectedStructValue,

#[error("Expected to deserialize unit variant")]
ExpectedUnitVariant,

#[error("Expected to deserialize newtype struct tuple")]
ExpectedNewtypeStruct,

#[error("Expected to deserialize new type variant")]
ExpectedNewtypeVariant,

#[error("Expected to deserialize tuple variant")]
ExpectedTupleVariant,

#[error("Expected to deserialize struct variant")]
ExpectedStructVariant,

#[error("{0}")]
SerializationError(String),

#[error("Failed to serialize variant to atom or string")]
InvalidVariantName,

#[error("Failed to serialize struct name to atom or string")]
InvalidStructName,

#[error("Failed to serialize variant to binary")]
InvalidBinary,

#[error("Failed to serialize NIF map")]
InvalidMap,

#[error("Failed to serialize struct to NIF struct")]
InvalidStruct,

#[error("Failed to serialize struct key")]
InvalidStructKey,
}

impl From<Error> for NifError {
Expand Down
2 changes: 0 additions & 2 deletions serde_rustler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

#![recursion_limit = "196"]

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate rustler;
extern crate rustler_codegen;

Expand Down
Loading