Skip to content

Commit 057227e

Browse files
committed
Update documentation
1 parent bcb8811 commit 057227e

File tree

4 files changed

+91
-4
lines changed

4 files changed

+91
-4
lines changed

UPGRADE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ This document is intended to simplify upgrading to newer versions by extending t
1414
2. `serde_rustler` has been integrated into `rustler` behind the feature flag
1515
`serde`. Arbitrary, `serde`-compatible objects (i.e. with `Deserialize` or
1616
`Serialize` `impl`s) can be wrapped in `SerdeTerm` to use them in place of
17-
`Encoder` or `Decoder`.
17+
`Encoder` or `Decoder`. The API is for now considered experimental.
1818

1919
## 0.29 -> 0.30
2020

rustler/src/serde/de.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ use serde::{
1212
};
1313
use std::iter;
1414

15-
/// Converts a native Elixir term to a native Rust type. See the [conversion table](https://github.com/sunny-g/serde_rustler/tree/master/serde_rustler#conversion-table) for details about deserialization behavior.
15+
/// Converts a native BEAM term to a native Rust object. See the conversion table
16+
/// for details about deserialization behavior.
1617
#[inline]
1718
pub fn from_term<'de, 'a: 'de, T>(term: Term<'a>) -> Result<T, Error>
1819
where

rustler/src/serde/mod.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,82 @@
1+
/*!
2+
# (Experimental) Serde Support
3+
4+
The `serde` conversion support is derived from [`serde_rustler`](https://github.com/sunny-g/serde_rustler)
5+
and uses mostly the same conventions and API for now. After the initial release,
6+
the conversions will at least be made more configurable (e.g. to support records
7+
in a better way and allow more Erlang-y configurations).
8+
9+
## Example
10+
11+
```rust
12+
use rustler;
13+
use serde::{Serialize, Deserialize};
14+
use serde_rustler::{from_term, to_term};
15+
16+
rustler::init!("Elixir.SerdeNif", [readme]);
17+
18+
// NOTE: to serialize to the correct Elixir record, you MUST tell serde to
19+
// rename the variants to the full Elixir record module atom.
20+
#[derive(Debug, Serialize, Deserialize)]
21+
enum AnimalType {
22+
#[serde(rename = "Elixir.SerdeNif.AnimalType.Cat")]
23+
Cat(String),
24+
#[serde(rename = "Elixir.SerdeNif.AnimalType.Dog")]
25+
Dog(String),
26+
}
27+
28+
// NOTE: to serialize to an actual Elixir struct (rather than a just map with
29+
// a :__struct__ key), you MUST tell serde to rename the struct to the full
30+
// Elixir struct module atom.
31+
#[derive(Debug, Serialize, Deserialize)]
32+
#[serde(rename = "Elixir.SerdeNif.Animal")]
33+
struct Animal {
34+
#[serde(rename = "type")]
35+
_type: AnimalType,
36+
name: String,
37+
age: u8,
38+
owner: Option<String>,
39+
}
40+
41+
#[rustler::nif]
42+
fn readme(SerdeTerm(animal): SerdeTerm<Animal>) -> impl Encoder {
43+
println!("serialized animal: {:?}", animal);
44+
SerdeTerm(animal)
45+
}
46+
```
47+
48+
## Conversion Table
49+
50+
The conversions table is for now identical to the one that `serde_rustler` used,
51+
with added support for 128-bit integers.
52+
53+
| Type Name | Serde (Rust) Values | Elixir Terms (default behaviour) | `deserialize_any` into Elixir Term |
54+
|-----|-----|-----|-----|
55+
| bool | `true` or `false` | `true` or `false` | `true` or `false` |
56+
| <sup>[1](#todo)</sup> number | `i8..i128`, `u8..u128`, `f32`, `f64` | `number` | `number` as `f64`, `i64`, `u64` or larger |
57+
| char | `'A'` | `[u32]` | `[u32]` |
58+
| string | `""` | `bitstring` | `bitstring` |
59+
| byte array | `&[u8]` or `Vec<u8>` | `<<_::_*8>>` | `bitstring` |
60+
| option | `Some(T)` or `None` | `T` or `:nil` | `T` or `:nil` |
61+
| unit | `None` | `:nil` | `:nil` |
62+
| unit struct | `struct Unit` | `:nil` | `:nil` |
63+
| <sup>[3](#atom)</sup> unit variant | `E::A` in `enum UnitVariant { A }` | `:A` | `"A"` |
64+
| <sup>[3](#atom)</sup> newtype struct | `struct Millimeters(u8)` | `{:Millimeters, u8}` | `["Millimeters", u8]` |
65+
| <sup>[3](#atom)</sup> newtype variant | `E::N` in `enum E { N(u8) }` | `{:N, u8}` | `["N", u8]` |
66+
| <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]` |
67+
| seq | `Vec<T>` | `[T,]` | `[T,]` |
68+
| tuple | `(u8,)` | `{u8,}` | `[u8,]` |
69+
| <sup>[3](#atom)</sup> tuple struct | `struct Rgb(u8, u8, u8)` | `{:Rgb, u8, u8, u8}` | `["Rgb", u8, u8, u8]` |
70+
| <sup>[3](#atom)</sup> tuple variant | `E::T` in `enum E { T(u8, u8) }` | `{:T, u8, u8}` | `["T", u8, u8]` |
71+
| <sup>[1](#todo)</sup> map | `HashMap<K, V>` | `%{}` | `%{}` |
72+
| <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}` |
73+
| <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}` |
74+
75+
<a name="todo">1</a>: API still being decided / implemented.
76+
77+
<a name="atom">2</a>: When serializing unknown input to terms, atoms will not be created and will instead be replaced with Elixir bitstrings. Therefore "records" will be tuples (`{bitstring, ...}`) and "structs" will be maps containing `%{:__struct__ => bitstring}`. The unfortunate consequence of this is that `deserialize_any` will lack the necessary information needed deserialize many terms without type hints, such as `structs`, `enums` and `enum variants`, and `tuples`.
78+
*/
79+
180
pub mod atoms;
281
mod de;
382
mod error;
@@ -10,6 +89,13 @@ pub use ser::{to_term, Serializer};
1089

1190
use crate::{Decoder, Encoder, Env, NifResult, Term};
1291

92+
/// Wrapper type to en- and decode serde terms
93+
///
94+
/// If the wrapped type implements `serde::Serialize`, `SerdeTerm<T>` implements
95+
/// `Encoder` and will thus be transparently converted *to* a BEAM object.
96+
///
97+
/// If the wrapped type implements `serde::Deserialize`, it implements `Decoder`
98+
/// and can thus be transparently converted *from* a BEAM object.
1399
pub struct SerdeTerm<T>(pub T);
14100

15101
impl<T: serde::Serialize> Encoder for SerdeTerm<T> {

rustler/src/serde/ser.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use crate::{types::tuple, Encoder, Env, OwnedBinary, Term};
66
use serde::ser::{self, Serialize};
77

88
#[inline]
9-
/// Converts a native Rust type into a native Elixir term. See [conversion table](https://github.com/sunny-g/serde_rustler/tree/master/serde_rustler#conversion-table) for details about serialization behavior.
10-
///
9+
/// Converts a native Rust type into a native BEAM term. See conversion table
10+
/// for details about serialization behavior.
1111
pub fn to_term<T>(env: Env, value: T) -> Result<Term, Error>
1212
where
1313
T: Serialize,

0 commit comments

Comments
 (0)