Skip to content

Draft: Start implementing generic wrapper types #666

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

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
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: 4 additions & 2 deletions rustler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@ mod alloc;
pub mod types;

mod term;
mod wrapped_types;

pub use crate::term::Term;
pub use crate::types::{
Atom, Binary, Decoder, Encoder, ErlOption, ListIterator, LocalPid, MapIterator, NewBinary,
OwnedBinary, Reference,
Atom, Binary, Decoder, Encoder, ErlOption, LocalPid, NewBinary, OwnedBinary,
};

pub use crate::wrapped_types::{ListIterator, Map, MapIterator, Reference, Tuple, Wrapper};

#[cfg(feature = "big_integer")]
pub use crate::types::BigInt;

Expand Down
5 changes: 1 addition & 4 deletions rustler/src/serde/de.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use crate::serde::{atoms, error::Error, util};
use crate::{
types::{ListIterator, MapIterator},
Term, TermType,
};
use crate::{ListIterator, MapIterator, Term, TermType};
use serde::{
de::{
self, Deserialize, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, VariantAccess,
Expand Down
10 changes: 7 additions & 3 deletions rustler/src/serde/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::io::Write;

use crate::serde::{atoms, error::Error, util};
use crate::wrapper::list::make_list;
use crate::{types::tuple, Encoder, Env, OwnedBinary, Term};
use crate::{Encoder, Env, OwnedBinary, Term};
use serde::ser::{self, Serialize};

#[inline]
Expand Down Expand Up @@ -336,7 +336,7 @@ impl<'a> SequenceSerializer<'a> {

#[inline]
fn to_tuple(&self) -> Result<Term<'a>, Error> {
Ok(tuple::make_tuple(self.ser.env, &self.items))
Ok(self.ser.env.make_tuple(&self.items).into())
}
}

Expand Down Expand Up @@ -460,7 +460,11 @@ impl<'a> MapSerializer<'a> {

#[inline]
fn to_map(&self) -> Result<Term<'a>, Error> {
Term::map_from_arrays(self.ser.env, &self.keys, &self.values).or(Err(Error::InvalidMap))
self.ser
.env
.map_from_arrays(&self.keys, &self.values)
.map(|map| map.into())
.or(Err(Error::InvalidMap))
}

#[inline]
Expand Down
7 changes: 5 additions & 2 deletions rustler/src/serde/util.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::serde::{atoms, Error};
use crate::{types::tuple, Binary, Decoder, Encoder, Env, Term};
use crate::{Binary, Decoder, Encoder, Env, Term, Tuple};

/// Converts an `&str` to either an existing atom or an Elixir bitstring.
pub fn str_to_term<'a>(env: &Env<'a>, string: &str) -> Result<Term<'a>, Error> {
Expand Down Expand Up @@ -62,7 +62,10 @@ pub fn validate_tuple(term: Term, len: Option<usize>) -> Result<Vec<Term>, Error
return Err(Error::ExpectedTuple);
}

let tuple = tuple::get_tuple(term).or(Err(Error::ExpectedTuple))?;
let tuple = Tuple::try_from(term)
.or(Err(Error::ExpectedTuple))?
.to_vec();

match len {
None => Ok(tuple),
Some(len) => {
Expand Down
1 change: 1 addition & 0 deletions rustler/src/sys/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub type ERL_NIF_TERM = ERL_NIF_UINT;
//#[derive(Debug, Copy, Clone)]
//#[repr(C)]
//pub struct ERL_NIF_TERM(ERL_NIF_UINT); // Don't do this, 32 bit calling convention is different for structs and ints.
// Would work with repr(transparent)!

/// See [ErlNifEnv](http://www.erlang.org/doc/man/erl_nif.html#ErlNifEnv) in the Erlang docs.
#[derive(Debug)]
Expand Down
41 changes: 41 additions & 0 deletions rustler/src/types/atom.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::wrapper::atom;
use crate::wrapper::NIF_TERM;
use crate::Wrapper;
use crate::{Decoder, Encoder, Env, Error, NifResult, Term};
use std::fmt;
use std::hash::{Hash, Hasher};
Expand Down Expand Up @@ -83,6 +84,46 @@ impl Atom {
}
}

// Wrapper
//
// Should be an ErlNifTerm along with its origin environment.
//
// For Atoms and LocalPids, the term is not associated with any environment, so we can
// just store the term itself. For other types, we need to store the environment
// as well, so we can create a new Term from it later.
//
// The objects are not safe to use outside of the function call, so they are not `clone`, or `copy`
// or even movable.
//
// Maybe use references everywhere instead of objects?
//
// A function call would then look like this:
//
// ```rust
// fn foo<'a>(env: Env<'a>, atom: &'a Atom, map: &'a Map) -> NifResult<()> {
// let atom = Atom::from_term(term)?;
// let term = atom.to_term(env);
// }
// ```
//
// Instead of `PhantomData` we could use `std::marker::Unsize` to make the type
// unsized. This would allow us to use the type as a reference, but it would
// also make it impossible to use as a value. This would be a problem for
// `Term` and `Env`, which are both values.

impl Wrapper for Atom {
const WRAPPED_TYPE: crate::TermType = crate::TermType::Atom;

fn unwrap(&self) -> Term<'a> {
unimplemented!()
}

unsafe fn wrap_unchecked(term: Term<'a>) -> Self {
Atom::from_nif_term(term.as_c_arg())
}
}

use std::fmt;
impl fmt::Debug for Atom {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
crate::wrapper::term::fmt(self.as_c_arg(), f)
Expand Down
14 changes: 8 additions & 6 deletions rustler/src/types/elixir_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,21 @@
//! `#[module = "Elixir.TheStructModule"]`.

use super::atom::{self, Atom};
use super::map::map_new;
use crate::{Env, NifResult, Term};
use crate::{Env, Error, Map, NifResult, Term};

pub fn get_ex_struct_name(map: Term) -> NifResult<Atom> {
// In an Elixir struct the value in the __struct__ field is always an atom.
map.map_get(atom::__struct__()).and_then(Atom::from_term)
let map: Map<'_> = map.try_into()?;
map.get(atom::__struct__())
.ok_or(Error::BadArg)
.and_then(Atom::from_term)
}

pub fn make_ex_struct<'a>(env: Env<'a>, struct_module: &str) -> NifResult<Term<'a>> {
let map = map_new(env);
pub fn make_ex_struct<'a>(env: Env<'a>, struct_module: &str) -> NifResult<Map<'a>> {
let map = env.new_map();

let struct_atom = atom::__struct__();
let module_atom = Atom::from_str(env, struct_module)?;

map.map_put(struct_atom, module_atom)
map.put(struct_atom, module_atom)
}
204 changes: 0 additions & 204 deletions rustler/src/types/list.rs

This file was deleted.

Loading
Loading