Skip to content

Commit

Permalink
:erlang.register/2
Browse files Browse the repository at this point in the history
  • Loading branch information
KronicDeth committed Apr 24, 2019
1 parent de2062d commit 26de92a
Show file tree
Hide file tree
Showing 10 changed files with 360 additions and 0 deletions.
1 change: 1 addition & 0 deletions lumen_runtime/src/lib.rs
Expand Up @@ -43,6 +43,7 @@ mod logging;
mod map;
pub mod otp;
mod reference;
mod registry;
mod stacktrace;
mod system;
mod term;
Expand Down
49 changes: 49 additions & 0 deletions lumen_runtime/src/otp/erlang.rs
Expand Up @@ -3,6 +3,7 @@
use std::cmp::Ordering;
use std::convert::TryInto;
use std::num::FpCategory;
use std::sync::Arc;

use num_bigint::BigInt;
use num_traits::Zero;
Expand All @@ -15,7 +16,9 @@ use crate::integer::{big, small};
use crate::list::Cons;
use crate::map::Map;
use crate::otp;
use crate::process::local::pid_to_process;
use crate::process::{IntoProcess, Process, TryIntoInProcess};
use crate::registry::{self, Registered};
use crate::stacktrace;
use crate::term::{Tag, Tag::*, Term};
use crate::time;
Expand Down Expand Up @@ -1121,6 +1124,52 @@ pub fn raise_3(class: Term, reason: Term, stacktrace: Term) -> Result {
}
}

pub fn register_2(name: Term, pid_or_port: Term, process_arc: Arc<Process>) -> Result {
match name.tag() {
Atom => match unsafe { name.atom_to_string() }.as_ref().as_ref() {
"undefined" => Err(badarg!()),
_ => {
let mut writable_registry = registry::RW_LOCK_REGISTERED_BY_NAME.write().unwrap();

if !writable_registry.contains_key(&name) {
match pid_or_port.tag() {
LocalPid => {
let pid_process_arc = if pid_or_port.tagged == process_arc.pid.tagged {
process_arc
} else {
match pid_to_process(pid_or_port) {
Some(pid_process_arc) => pid_process_arc,
_ => return Err(badarg!()),
}
};

let mut locked_registered_name =
pid_process_arc.registered_name.lock().unwrap();

match *locked_registered_name {
None => {
writable_registry.insert(
name,
Registered::Process(Arc::clone(&pid_process_arc)),
);
*locked_registered_name = Some(name);

Ok(true.into())
}
Some(_) => Err(badarg!()),
}
}
_ => Err(badarg!()),
}
} else {
Err(badarg!())
}
}
},
_ => Err(badarg!()),
}
}

/// `rem/2` infix operator. Integer remainder.
pub fn rem_2(dividend: Term, divisor: Term, process: &Process) -> Result {
integer_infix_operator!(dividend, divisor, process, %)
Expand Down
8 changes: 8 additions & 0 deletions lumen_runtime/src/otp/erlang/tests.rs
Expand Up @@ -88,6 +88,7 @@ mod number_or_badarith_1;
mod or_2;
mod orelse_2;
mod raise_3;
mod register_2;
mod rem_2;
mod self_0;
mod setelement_3;
Expand Down Expand Up @@ -131,3 +132,10 @@ where
{
f(&process::local::new())
}

fn with_process_arc<F>(f: F)
where
F: FnOnce(Arc<Process>) -> (),
{
f(process::local::new())
}
76 changes: 76 additions & 0 deletions lumen_runtime/src/otp/erlang/tests/register_2.rs
@@ -0,0 +1,76 @@
use super::*;

mod with_atom_name;

#[test]
fn with_local_reference_name_errors_badarg() {
with_name_errors_badarg(|process| Term::local_reference(&process));
}

#[test]
fn with_empty_list_right_errors_badarg() {
with_name_errors_badarg(|_| Term::EMPTY_LIST);
}

#[test]
fn with_list_right_errors_badarg() {
with_name_errors_badarg(|process| {
Term::cons(0.into_process(&process), 1.into_process(&process), &process)
});
}

#[test]
fn with_small_integer_right_errors_badarg() {
with_name_errors_badarg(|process| 0.into_process(&process));
}

#[test]
fn with_big_integer_right_errors_badarg() {
with_name_errors_badarg(|process| (crate::integer::small::MAX + 1).into_process(&process));
}

#[test]
fn with_float_right_errors_badarg() {
with_name_errors_badarg(|process| 0.0.into_process(&process));
}

#[test]
fn with_local_pid_right_errors_badarg() {
with_name_errors_badarg(|_| Term::local_pid(0, 1).unwrap());
}

#[test]
fn with_external_pid_right_errors_badarg() {
with_name_errors_badarg(|process| Term::external_pid(1, 2, 3, &process).unwrap());
}

#[test]
fn with_tuple_right_errors_badarg() {
with_name_errors_badarg(|process| Term::slice_to_tuple(&[], &process));
}

#[test]
fn with_map_right_errors_badarg() {
with_name_errors_badarg(|process| Term::slice_to_map(&[], &process));
}

#[test]
fn with_heap_binary_right_errors_badarg() {
with_name_errors_badarg(|process| Term::slice_to_binary(&[], &process));
}

#[test]
fn with_subbinary_right_errors_badarg() {
with_name_errors_badarg(|process| bitstring!(1 :: 1, &process));
}

fn with_name_errors_badarg<N>(name: N)
where
N: FnOnce(&Process) -> Term,
{
with_process_arc(|process_arc| {
let pid = Term::local_pid(0, 0).unwrap();

assert_badarg!(erlang::register_2(name(&process_arc), pid, process_arc));
});
}
31 changes: 31 additions & 0 deletions lumen_runtime/src/otp/erlang/tests/register_2/with_atom_name.rs
@@ -0,0 +1,31 @@
use super::*;

mod without_registered_name;

#[test]
fn with_undefined_atom_errors_badarg() {
with_name_errors_badarg(|_| Term::str_to_atom("undefined", DoNotCare).unwrap())
}

#[test]
fn with_registered_name_errors_badarg() {
let registered_name = Term::str_to_atom("registered_name", DoNotCare).unwrap();
let registered_process_arc = process::local::new();

assert_eq!(
erlang::register_2(
registered_name,
registered_process_arc.pid,
registered_process_arc
),
Ok(true.into())
);

let unregistered_process_arc = process::local::new();

assert_badarg!(erlang::register_2(
registered_name,
unregistered_process_arc.pid,
unregistered_process_arc
));
}
@@ -0,0 +1,91 @@
use super::*;

use std::sync::atomic::AtomicUsize;

mod with_local_pid;

#[test]
fn with_atom_pid_or_process_errors_badarg() {
with_pid_or_port_errors_badarg(|_| Term::str_to_atom("pid_or_port", DoNotCare).unwrap())
}

#[test]
fn with_empty_list_pid_or_process_errors_badarg() {
with_pid_or_port_errors_badarg(|_| Term::EMPTY_LIST);
}

#[test]
fn with_list_pid_or_process_errors_badarg() {
with_pid_or_port_errors_badarg(|process| {
Term::cons(0.into_process(&process), 1.into_process(&process), &process)
});
}

#[test]
fn with_small_integer_pid_or_process_errors_badarg() {
with_pid_or_port_errors_badarg(|process| 0.into_process(&process));
}

#[test]
fn with_big_integer_pid_or_process_errors_badarg() {
with_pid_or_port_errors_badarg(|process| {
(crate::integer::small::MAX + 1).into_process(&process)
});
}

#[test]
fn with_float_pid_or_process_errors_badarg() {
with_pid_or_port_errors_badarg(|process| 0.0.into_process(&process));
}

#[test]
fn with_external_pid_pid_or_process_errors_badarg() {
with_pid_or_port_errors_badarg(|process| Term::external_pid(1, 2, 3, &process).unwrap());
}

#[test]
fn with_tuple_pid_or_process_errors_badarg() {
with_pid_or_port_errors_badarg(|process| Term::slice_to_tuple(&[], &process));
}

#[test]
fn with_map_pid_or_process_errors_badarg() {
with_pid_or_port_errors_badarg(|process| Term::slice_to_map(&[], &process));
}

#[test]
fn with_heap_binary_pid_or_process_errors_badarg() {
with_pid_or_port_errors_badarg(|process| Term::slice_to_binary(&[], &process));
}

#[test]
fn with_subbinary_pid_or_process_errors_badarg() {
with_pid_or_port_errors_badarg(|process| bitstring!(1 :: 1, &process));
}

static REGISTERED_NAME_COUNTER: AtomicUsize = AtomicUsize::new(0);

fn registered_name() -> Term {
Term::str_to_atom(
format!(
"registered{}",
REGISTERED_NAME_COUNTER.fetch_add(1, std::sync::atomic::Ordering::SeqCst)
)
.as_ref(),
DoNotCare,
)
.unwrap()
}

fn with_pid_or_port_errors_badarg<P>(pid_or_port: P)
where
P: FnOnce(&Process) -> Term,
{
with_process_arc(|process_arc| {
assert_badarg!(erlang::register_2(
registered_name(),
pid_or_port(&process_arc),
process_arc
));
})
}
@@ -0,0 +1,63 @@
use super::*;

use crate::registry::Registered;

#[test]
fn without_process() {
with_process_arc(|process_arc| {
let pid_or_port = process::identifier::local::next();

assert_badarg!(erlang::register_2(
registered_name(),
pid_or_port,
process_arc
));
});
}

#[test]
fn with_same_process() {
with_process_arc(|process_arc| {
let name = registered_name();
let pid_or_port = process_arc.pid;

assert_eq!(
erlang::register_2(name, pid_or_port, process_arc.clone()),
Ok(true.into())
);
assert_eq!(*process_arc.registered_name.lock().unwrap(), Some(name));
assert_eq!(
registry::RW_LOCK_REGISTERED_BY_NAME
.read()
.unwrap()
.get(&name),
Some(&Registered::Process(process_arc))
);
});
}

#[test]
fn with_different_process() {
with_process_arc(|process_arc| {
let name = registered_name();

let another_process_arc = process::local::new();
let pid_or_port = another_process_arc.pid;

assert_eq!(
erlang::register_2(name, pid_or_port, process_arc),
Ok(true.into())
);
assert_eq!(
*another_process_arc.registered_name.lock().unwrap(),
Some(name)
);
assert_eq!(
registry::RW_LOCK_REGISTERED_BY_NAME
.read()
.unwrap()
.get(&name),
Some(&Registered::Process(another_process_arc))
);
});
}

0 comments on commit 26de92a

Please sign in to comment.