Skip to content

Commit 7be56cf

Browse files
committed
Current state
1 parent 3759197 commit 7be56cf

File tree

3 files changed

+112
-19
lines changed

3 files changed

+112
-19
lines changed

rustler/src/sys/types.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub type ERL_NIF_TERM = ERL_NIF_UINT;
1919
//#[derive(Debug, Copy, Clone)]
2020
//#[repr(C)]
2121
//pub struct ERL_NIF_TERM(ERL_NIF_UINT); // Don't do this, 32 bit calling convention is different for structs and ints.
22+
// Would work with repr(transparent)!
2223

2324
/// See [ErlNifEnv](http://www.erlang.org/doc/man/erl_nif.html#ErlNifEnv) in the Erlang docs.
2425
#[derive(Debug)]

rustler/src/types/atom.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,34 @@ impl Atom {
8484
}
8585
}
8686

87-
impl<'a> Wrapper<'a> for Atom {
87+
// Wrapper
88+
//
89+
// Should be an ErlNifTerm along with its origin environment.
90+
//
91+
// For Atoms and LocalPids, the term is not associated with any environment, so we can
92+
// just store the term itself. For other types, we need to store the environment
93+
// as well, so we can create a new Term from it later.
94+
//
95+
// The objects are not safe to use outside of the function call, so they are not `clone`, or `copy`
96+
// or even movable.
97+
//
98+
// Maybe use references everywhere instead of objects?
99+
//
100+
// A function call would then look like this:
101+
//
102+
// ```rust
103+
// fn foo<'a>(env: Env<'a>, atom: &'a Atom, map: &'a Map) -> NifResult<()> {
104+
// let atom = Atom::from_term(term)?;
105+
// let term = atom.to_term(env);
106+
// }
107+
// ```
108+
//
109+
// Instead of `PhantomData` we could use `std::marker::Unsize` to make the type
110+
// unsized. This would allow us to use the type as a reference, but it would
111+
// also make it impossible to use as a value. This would be a problem for
112+
// `Term` and `Env`, which are both values.
113+
114+
impl Wrapper for Atom {
88115
const WRAPPED_TYPE: crate::TermType = crate::TermType::Atom;
89116

90117
fn unwrap(&self) -> Term<'a> {

rustler/src/wrapped_types/wrapper.rs

Lines changed: 83 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,27 @@ impl From<WrapperError> for crate::Error {
99
}
1010
}
1111

12-
pub trait Wrapper<'a>: Sized {
12+
pub trait Wrapper: Sized {
1313
const WRAPPED_TYPE: TermType;
1414

15-
unsafe fn wrap_ptr_unchecked(env: Env<'a>, ptr: ERL_NIF_TERM) -> Self {
15+
unsafe fn wrap_ptr_unchecked<'a>(env: Env<'a>, ptr: ERL_NIF_TERM) -> Self {
1616
Self::wrap_unchecked(Term::new(env, ptr))
1717
}
1818

19-
fn wrap(term: Term<'a>) -> Result<Self, WrapperError> {
19+
fn wrap<'a>(term: Term<'a>) -> Result<Self, WrapperError> {
2020
if term.get_type() == Self::WRAPPED_TYPE {
2121
unsafe { Ok(Self::wrap_unchecked(term)) }
2222
} else {
2323
Err(WrapperError)
2424
}
2525
}
2626

27-
fn unwrap(&self) -> Term<'a>;
28-
unsafe fn wrap_unchecked(term: Term<'a>) -> Self;
29-
}
27+
fn unwrap<'a>(&self, env: Env<'a>) -> Term<'a>;
3028

31-
impl<'a, T> From<T> for Term<'a>
32-
where
33-
T: Wrapper<'a>,
34-
{
35-
fn from(term: T) -> Self {
36-
term.unwrap()
29+
unsafe fn unwrap_ptr_unchecked<'a>(&self, env: Env<'a>) -> ERL_NIF_TERM {
30+
self.unwrap(env).as_c_arg()
3731
}
32+
unsafe fn wrap_unchecked<'a>(term: Term<'a>) -> Self;
3833
}
3934

4035
macro_rules! wrapper {
@@ -54,20 +49,20 @@ macro_rules! wrapper {
5449
/// If the term is already is in the provided env, it will be directly returned.
5550
/// Otherwise the term will be copied over.
5651
pub fn in_env<'b>(&self, env: Env<'b>) -> $name<'b> {
57-
let term = self.unwrap().in_env(env);
52+
let term = self.unwrap(env);
5853
unsafe { $name::wrap_unchecked(term) }
5954
}
6055
}
6156

62-
impl<'a> Wrapper<'a> for $name<'a> {
57+
impl<'a> Wrapper for $name<'a> {
6358
const WRAPPED_TYPE: $crate::TermType = $term_type;
6459

65-
unsafe fn wrap_unchecked(term: Term<'a>) -> Self {
60+
unsafe fn wrap_unchecked<'b>(term: Term<'b>) -> Self {
6661
$name(term)
6762
}
6863

69-
fn unwrap(&self) -> Term<'a> {
70-
self.0
64+
fn unwrap<'b>(&self, env: Env<'b>) -> Term<'b> {
65+
self.0.in_env(env)
7166
}
7267
}
7368

@@ -97,7 +92,77 @@ macro_rules! wrapper {
9792

9893
impl<'a> $crate::Encoder for $name<'a> {
9994
fn encode<'b>(&self, env: $crate::Env<'b>) -> Term<'b> {
100-
self.0.encode(env)
95+
self.unwrap().encode(env)
96+
}
97+
}
98+
99+
// impl<'a> std::hash::Hash for $name<'a> {
100+
// fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
101+
// self.0.hash(state);
102+
// }
103+
// }
104+
//
105+
impl<'a> std::fmt::Debug for $name<'a> {
106+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
107+
self.0.fmt(f)
108+
}
109+
}
110+
};
111+
}
112+
113+
macro_rules! wrapper_impls {
114+
($name: ident, $term_type:path) => {
115+
impl<'a> $name<'a> {
116+
/// Returns a representation of self in the given Env.
117+
///
118+
/// If the term is already is in the provided env, it will be directly returned.
119+
/// Otherwise the term will be copied over.
120+
pub fn in_env<'b>(&self, env: Env<'b>) -> $name<'b> {
121+
use $crate::wrapped_types::Wrapper;
122+
let term = self.unwrap().in_env(env);
123+
unsafe { $name::wrap_unchecked(term) }
124+
}
125+
}
126+
127+
impl<'a> std::ops::Deref for $name<'a> {
128+
type Target = Term<'a>;
129+
130+
fn deref(&self) -> &Self::Target {
131+
&self.unwrap()
132+
}
133+
}
134+
135+
impl<'a> TryFrom<Term<'a>> for $name<'a> {
136+
type Error = $crate::Error;
137+
138+
fn try_from(term: Term<'a>) -> Result<Self, Self::Error> {
139+
use $crate::wrapped_types::Wrapper;
140+
Self::wrap(term).or(Err($crate::Error::BadArg))
141+
}
142+
}
143+
144+
impl<'a> $crate::Decoder<'a> for $name<'a> {
145+
fn decode(term: Term<'a>) -> $crate::NifResult<Self> {
146+
use $crate::wrapped_types::Wrapper;
147+
Self::wrap(term).or(Err($crate::Error::BadArg))
148+
}
149+
}
150+
151+
impl<'a> $crate::Encoder for $name<'a> {
152+
fn encode<'b>(&self, env: $crate::Env<'b>) -> Term<'b> {
153+
self.unwrap().encode(env)
154+
}
155+
}
156+
157+
impl<'a> std::hash::Hash for $name<'a> {
158+
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
159+
self.unwrap().hash(state);
160+
}
161+
}
162+
163+
impl<'a> std::fmt::Debug for $name<'a> {
164+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
165+
self.unwrap().fmt(f)
101166
}
102167
}
103168
};

0 commit comments

Comments
 (0)