Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Import of serde_rustler #586

Merged
merged 15 commits into from
Mar 20, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ versions.
- `Env::is_process_alive` and `LocalPid::is_alive` (#599)
- Encoding and decoding of 128 bit integers (#600)
- Optional codec for `num_bigint::BigInt` using the `big_integer` feature (#601)
- Add experimental `serde` support derived from `serde_rustler`

### Fixed

Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
"rustler_tests/native/binary_example",
"rustler_tests/native/rustler_test",
"rustler_tests/native/rustler_bigint_test",
"rustler_tests/native/rustler_serde_test",
"rustler_tests/native/deprecated_macros",
"rustler_tests/native/dynamic_load",
"rustler_tests/native/rustler_compile_tests",
Expand Down
3 changes: 3 additions & 0 deletions LICENSE-MIT
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
Copyright (c) 2016 hansihe
Copyright (c) 2016-2024 The Contributors of the Rustler Project
Serde support derived from serde_rustler:
Copyright (c) 2019-2021 Sunny Gonnabathula

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
Expand Down
44 changes: 28 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,34 @@ they unwind into C.
The library provides functionality for both Erlang and Elixir, however Elixir
is favored as of now.

#### Features:
#### Features

- Safety - The code you write in a Rust NIF should never be able to crash the BEAM.
- Interop - Decoding and encoding rust values into Erlang terms is as easy as a function call.
- Type composition - Making a Rust struct encodable and decodable to Erlang or Elixir can be done with a single attribute.
- Resource objects - Enables you to safely pass a reference to a Rust struct into Erlang code. The struct will be automatically dropped when it's no longer referenced.
Safety
: The code you write in a Rust NIF should never be able to crash the BEAM.

#### Getting started
Interop
: Decoding and encoding rust values into Erlang terms is as easy as a function
: call.

Type composition
: Making a Rust struct encodable and decodable to Erlang or Elixir can be done
: with a single attribute.

The easiest way of getting started is the [rustler elixir library](https://hex.pm/packages/rustler).
Resource objects
: Enables you to safely pass a reference to a Rust struct into Erlang code. The
: struct will be automatically dropped when it's no longer referenced.

#### Getting started

- Add the [rustler elixir library](https://hex.pm/packages/rustler) as a dependency of your project.
- Run `mix rustler.new` to generate a new NIF in your project. Follow the instructions.
- If you're already using [`serde`](https://serde.rs), consider using [`serde_rustler`](https://github.com/sunny-g/serde_rustler/tree/master/serde_rustler) to easily encode and decode your data types into and from Elixir terms.
The easiest way of getting started is the [rustler Elixir library](https://hex.pm/packages/rustler).

NOTE: If you have previously used Rustler, you need to run `mix archive.uninstall rustler_installer.ez` to remove it before generating the NIF.
- Add the [rustler Elixir library](https://hex.pm/packages/rustler) as a
dependency of your project.
- Run `mix rustler.new` to generate a new NIF in your project. Follow the
instructions.
- If you are already using [`serde`](https://serde.rs) and/or have been using
`serde_rustler` before, please enable the `serde` feature in your NIF crate's
`Cargo.toml` on the `rustler` dependency.

#### What it looks like

Expand All @@ -58,9 +70,9 @@ Rustler aims to support the newest three major OTP versions as well as newest th
#### Supported NIF version

The minimal supported NIF version for a library should be defined via Cargo
features. The default is currently `2.14` (Erlang/OTP 21). To use features from
NIF version `2.16` (Erlang/OTP 24), the respective feature flag has to be
enabled on the dependency:
features. The default is currently `2.15` (Erlang/OTP 21). To use features from
NIF version `2.16` (Erlang/OTP 24) or `2.17` (Erlang/OTP 26), the respective
feature flag has to be enabled on the dependency:

```toml
[dependencies]
Expand All @@ -84,5 +96,5 @@ at your option.
##### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.
4 changes: 4 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ This document is intended to simplify upgrading to newer versions by extending t
wrapper. For most codebases, it will be enough to activate the feature and
replace all `rustler_bigint::BigInt` usages by `rustler::BigInt` (or
`num_bigint::BigInt`).
2. `serde_rustler` has been integrated into `rustler` behind the feature flag
`serde`. Arbitrary, `serde`-compatible objects (i.e. with `Deserialize` or
`Serialize` `impl`s) can be wrapped in `SerdeTerm` to use them in place of
`Encoder` or `Decoder`. The API is for now considered experimental.

## 0.29 -> 0.30

Expand Down
2 changes: 2 additions & 0 deletions rustler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ nif_version_2_14 = ["rustler_sys/nif_version_2_14"]
nif_version_2_15 = ["nif_version_2_14", "rustler_sys/nif_version_2_15"]
nif_version_2_16 = ["nif_version_2_15", "rustler_sys/nif_version_2_16"]
nif_version_2_17 = ["nif_version_2_16", "rustler_sys/nif_version_2_17"]
serde = ["dep:serde"]

[dependencies]
lazy_static = "1.4"
rustler_codegen = { path = "../rustler_codegen", version = "0.31.0", optional = true}
rustler_sys = { path = "../rustler_sys", version = "~2.4.0" }
num-bigint = { version = "0.4", optional = true }
serde = { version = "1", optional = true }

[package.metadata.release]

Expand Down
Empty file added rustler/src/convert/mod.rs
Empty file.
6 changes: 6 additions & 0 deletions rustler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,9 @@ pub use rustler_codegen::{
init, nif, NifException, NifMap, NifRecord, NifStruct, NifTaggedEnum, NifTuple, NifUnitEnum,
NifUntaggedEnum,
};

#[cfg(feature = "serde")]
pub mod serde;

#[cfg(feature = "serde")]
pub use crate::serde::SerdeTerm;
56 changes: 56 additions & 0 deletions rustler/src/serde/atoms.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//! Constants and utilities for conversion between Rust string-likes and Elixir atoms.

use crate::serde::Error;
use crate::{types::atom::Atom, Encoder, Env, Term};

use lazy_static::lazy_static;

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

atoms! {
nil,
ok,
error,
true_ = "true",
false_ = "false",
undefined,
nan,
inf,
neg_inf,
__struct__,
}

/**
* Attempts to create an atom term from the provided string (if the atom already exists in the atom table). If not, returns a string term.
*/
pub fn str_to_term<'a>(env: &Env<'a>, string: &str) -> Result<Term<'a>, Error> {
if string == "Ok" {
Ok(ok().encode(*env))
} else if string == "Err" {
Ok(error().encode(*env))
} else {
match Atom::try_from_bytes(*env, string.as_bytes()) {
Ok(Some(term)) => Ok(term.encode(*env)),
Ok(None) => Err(Error::InvalidStringable),
_ => Err(Error::InvalidStringable),
}
}
}

/**
* Attempts to create a `String` from the term.
*/
pub fn term_to_string(term: &Term) -> Result<String, Error> {
if ok().eq(term) {
Ok(OK.to_string())
} else if error().eq(term) {
Ok(ERROR.to_string())
} else if term.is_atom() {
term.atom_to_string().or(Err(Error::InvalidAtom))
} else {
Err(Error::InvalidStringable)
}
}
Loading
Loading