Skip to content

Commit bd60f9f

Browse files
committed
Fix allocator usage and implement simple module formatting
1 parent 266e052 commit bd60f9f

File tree

5 files changed

+189
-15
lines changed

5 files changed

+189
-15
lines changed

rustler_tool/src/fake_symbols.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::alloc::{Layout, alloc, dealloc};
1+
use std::alloc::{alloc, dealloc, Layout};
22

33
const HEADER: usize = 8;
44
const ALIGNMENT: usize = 8;
@@ -26,6 +26,8 @@ pub unsafe extern "C" fn enif_free(ptr: *mut u8) {
2626
#[no_mangle]
2727
pub static enif_alloc_binary: usize = 0;
2828
#[no_mangle]
29+
pub static enif_alloc_resource: usize = 0;
30+
#[no_mangle]
2931
pub static enif_alloc_env: usize = 0;
3032
#[no_mangle]
3133
pub static enif_binary_to_term: usize = 0;
@@ -98,6 +100,8 @@ pub static enif_is_ref: usize = 0;
98100
#[no_mangle]
99101
pub static enif_is_tuple: usize = 0;
100102
#[no_mangle]
103+
pub static enif_keep_resource: usize = 0;
104+
#[no_mangle]
101105
pub static enif_make_atom_len: usize = 0;
102106
#[no_mangle]
103107
pub static enif_make_badarg: usize = 0;
@@ -132,6 +136,10 @@ pub static enif_make_new_map: usize = 0;
132136
#[no_mangle]
133137
pub static enif_make_reverse_list: usize = 0;
134138
#[no_mangle]
139+
pub static enif_make_resource: usize = 0;
140+
#[no_mangle]
141+
pub static enif_make_resource_binary: usize = 0;
142+
#[no_mangle]
135143
pub static enif_make_sub_binary: usize = 0;
136144
#[no_mangle]
137145
pub static enif_make_tuple_from_array: usize = 0;
@@ -158,12 +166,20 @@ pub static enif_realloc_binary: usize = 0;
158166
#[no_mangle]
159167
pub static enif_release_binary: usize = 0;
160168
#[no_mangle]
169+
pub static enif_release_resource: usize = 0;
170+
#[no_mangle]
161171
pub static enif_schedule_nif: usize = 0;
162172
#[no_mangle]
163173
pub static enif_self: usize = 0;
164174
#[no_mangle]
175+
pub static enif_send: usize = 0;
176+
#[no_mangle]
165177
pub static enif_snprintf: usize = 0;
166178
#[no_mangle]
167179
pub static enif_term_to_binary: usize = 0;
168180
#[no_mangle]
169181
pub static enif_term_type: usize = 0;
182+
#[no_mangle]
183+
pub static enif_thread_type: usize = 0;
184+
#[no_mangle]
185+
pub static enif_whereis_pid: usize = 0;

rustler_tool/src/main.rs

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#[cfg(unix)]
22
mod fake_symbols;
33
mod nif;
4+
mod nif_elixir;
5+
mod nif_erlang;
46

57
use std::path::PathBuf;
68

@@ -15,24 +17,44 @@ struct Cli {
1517
command: Option<Commands>,
1618
}
1719

20+
#[derive(clap::ValueEnum, Clone, Default, Debug)]
21+
enum OutputFormat {
22+
#[default]
23+
Bare,
24+
Erlang,
25+
Elixir,
26+
}
27+
1828
#[derive(Subcommand)]
1929
enum Commands {
2030
/// does testing things
21-
Nif { path: PathBuf },
31+
Nif {
32+
path: PathBuf,
33+
#[arg(short, long, default_value_t, value_enum)]
34+
format: OutputFormat,
35+
},
2236
}
2337

2438
fn main() {
2539
let cli = Cli::parse();
2640

2741
match &cli.command {
28-
Some(Commands::Nif { path }) => {
29-
println!("Extracting nifs from {:?}", path);
30-
31-
let lib = NifLibrary::load(&path).unwrap();
42+
Some(Commands::Nif { path, format }) => {
43+
let lib = NifLibrary::load(path).unwrap();
3244

33-
println!("Found library {} with nifs", lib.name);
34-
for nif in lib.nifs {
35-
println!(" {}/{}", nif.name, nif.arity);
45+
match format {
46+
OutputFormat::Bare => {
47+
println!("{}", lib.name);
48+
for nif in lib.nifs {
49+
println!(" {}/{}", nif.name, nif.arity);
50+
}
51+
}
52+
OutputFormat::Erlang => {
53+
println!("{}", nif_erlang::LibAsErlang(lib))
54+
}
55+
OutputFormat::Elixir => {
56+
println!("{}", nif_elixir::LibAsElixir(lib))
57+
}
3658
}
3759
}
3860
None => {

rustler_tool/src/nif.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,26 @@ unsafe fn maybe_call_nif_init(
3939
impl NifLibrary {
4040
pub fn load(path: &Path) -> Result<NifLibrary, Box<dyn std::error::Error>> {
4141
unsafe {
42-
let lib = Library::new(&path)?;
42+
let lib = Library::new(path)?;
4343
let entry = maybe_call_nif_init(&lib)?;
4444

4545
let name = CStr::from_ptr((*entry).name).to_str()?.to_string();
4646
let nif_array =
4747
std::slice::from_raw_parts((*entry).funcs, (*entry).num_of_funcs as usize);
4848

49-
let nifs = nif_array
50-
.into_iter()
49+
let mut nifs: Vec<_> = nif_array
50+
.iter()
5151
.filter_map(|f| {
5252
Some(Nif {
53-
name: CStr::from_ptr((*f).name).to_str().ok()?.to_string(),
54-
arity: (*f).arity as usize,
55-
flags: (*f).flags as usize,
53+
name: CStr::from_ptr(f.name).to_str().ok()?.to_string(),
54+
arity: f.arity as usize,
55+
flags: f.flags as usize,
5656
})
5757
})
5858
.collect();
5959

60+
nifs.sort_by_key(|x| x.name.clone());
61+
6062
Ok(NifLibrary {
6163
path: path.to_path_buf(),
6264
name,

rustler_tool/src/nif_elixir.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
use crate::NifLibrary;
2+
use std::fmt;
3+
4+
pub struct LibAsElixir(pub NifLibrary);
5+
6+
impl fmt::Display for LibAsElixir {
7+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
8+
writeln!(
9+
f,
10+
"defmodule {} do",
11+
string_to_elixir_atom(&self.0.name, false)
12+
)?;
13+
14+
for nif in &self.0.nifs {
15+
write!(f, " def {}(", string_to_elixir_atom(&nif.name, true))?;
16+
for i in 0..nif.arity {
17+
if i > 0 {
18+
write!(f, ", ")?;
19+
}
20+
write!(f, "_")?;
21+
}
22+
writeln!(f, "), do: :erlang.nif_error(not_loaded)")?;
23+
}
24+
writeln!(f, "end")
25+
}
26+
}
27+
28+
fn string_to_elixir_atom(s: &str, func: bool) -> String {
29+
match s {
30+
"false" | "true" | "nil" => s.to_string(),
31+
_ if s.starts_with("Elixir.") => s[7..].to_string(),
32+
_ => {
33+
let mut output = String::new();
34+
let mut needs_quotes = false;
35+
for c in s.chars() {
36+
match c {
37+
'a'..='z' | 'A'..='Z' | '0'..='9' | '@' | '_' => output.push(c),
38+
'"' => {
39+
needs_quotes = true;
40+
output.push_str("\\\"");
41+
}
42+
'\\' => {
43+
needs_quotes = true;
44+
output.push_str(r"\\");
45+
}
46+
_ => {
47+
needs_quotes = true;
48+
output.push(c);
49+
}
50+
}
51+
}
52+
53+
if needs_quotes {
54+
format!(":\"{}\"", output).to_string()
55+
} else if !func {
56+
format!(":{}", output).to_string()
57+
} else {
58+
output
59+
}
60+
}
61+
}
62+
}

rustler_tool/src/nif_erlang.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use crate::NifLibrary;
2+
use std::fmt;
3+
4+
pub struct LibAsErlang(pub NifLibrary);
5+
6+
impl fmt::Display for LibAsErlang {
7+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
8+
write!(f, "-module({}).\n\n", string_to_erlang_atom(&self.0.name))?;
9+
writeln!(f, "-export([")?;
10+
let count = self.0.nifs.len();
11+
for (n, nif) in self.0.nifs.iter().enumerate() {
12+
write!(f, " {}/{}", string_to_erlang_atom(&nif.name), nif.arity)?;
13+
if n == count - 1 {
14+
write!(f, ",")?;
15+
}
16+
writeln!(f)?;
17+
}
18+
write!(f, "]).\n\n")?;
19+
20+
// TODO: On Load function
21+
22+
for nif in &self.0.nifs {
23+
write!(f, "{}(", string_to_erlang_atom(&nif.name))?;
24+
for i in 0..nif.arity {
25+
if i > 0 {
26+
write!(f, ", ")?;
27+
}
28+
write!(f, "_")?;
29+
}
30+
write!(f, ") ->\n erlang:nif_error(not_loaded).\n\n")?;
31+
}
32+
33+
Ok(())
34+
}
35+
}
36+
37+
fn string_to_erlang_atom(input: &str) -> String {
38+
let mut output = String::with_capacity(input.len());
39+
let mut needs_quotes = false;
40+
41+
let mut first = true;
42+
43+
for c in input.chars() {
44+
match c {
45+
'A'..='Z' if first => {
46+
needs_quotes = true;
47+
output.push(c);
48+
}
49+
'a'..='z' | 'A'..='Z' | '0'..='9' | '@' | '_' => output.push(c),
50+
'\'' => {
51+
needs_quotes = true;
52+
output.push_str(r"\'");
53+
}
54+
'\\' => {
55+
needs_quotes = true;
56+
output.push_str(r"\\");
57+
}
58+
_ => {
59+
needs_quotes = true;
60+
output.push(c);
61+
}
62+
}
63+
64+
first = false;
65+
}
66+
67+
if needs_quotes {
68+
format!("'{}'", output).to_string()
69+
} else {
70+
output
71+
}
72+
}

0 commit comments

Comments
 (0)