From c44d54668bc914d747bd4b8f72c4344db901059a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Niemier?= <~@hauleth.dev> Date: Fri, 21 Aug 2026 17:10:06 +0200 Subject: [PATCH 1/3] Implement `From<&[u8]>` for binary This allows for simpler work with binaries that aren't UTF-8 encoded strings. Currently there is either need to construct such data in place (which limits usage of some Rust libraries) or you need to write additional code to translate one form into another. This implementation is simple and performant enough for this usecase. --- rustler/src/types/binary.rs | 11 +++++++ rustler_tests/lib/rustler_test.ex | 8 +++++ .../native/rustler_test/src/test_binary.rs | 30 +++++++++++++++++++ rustler_tests/test/binary_test.exs | 12 ++++++++ 4 files changed, 61 insertions(+) diff --git a/rustler/src/types/binary.rs b/rustler/src/types/binary.rs index c6a2cb1f..e387f202 100644 --- a/rustler/src/types/binary.rs +++ b/rustler/src/types/binary.rs @@ -262,6 +262,17 @@ impl FromIterator for OwnedBinary { } } +impl> From for OwnedBinary { + fn from(data: T) -> Self { + let buf = data.as_ref(); + let mut bin = Self::new(buf.len()).expect("Allocation failed"); + + bin.as_mut_slice().copy_from_slice(buf); + + bin + } +} + /// An immutable smart-pointer to an Erlang binary. /// /// See [module-level doc](index.html) for more information. diff --git a/rustler_tests/lib/rustler_test.ex b/rustler_tests/lib/rustler_test.ex index 3fefaddd..6a38d2fd 100644 --- a/rustler_tests/lib/rustler_test.ex +++ b/rustler_tests/lib/rustler_test.ex @@ -96,6 +96,14 @@ defmodule RustlerTest do def decode_iolist(_), do: err() def first_four_bytes_of_iolist(_), do: err() + def array_into_binary(), do: err() + def vec_into_binary(), do: err() + def slice_into_binary(), do: err() + def str_into_binary(), do: err() + def string_into_binary(), do: err() + + def binary_from_str(), do: err() + def atom_to_string(_), do: err() def atom_equals_ok(_), do: err() def binary_to_atom(_), do: err() diff --git a/rustler_tests/native/rustler_test/src/test_binary.rs b/rustler_tests/native/rustler_test/src/test_binary.rs index a8e3c291..b2f77e95 100644 --- a/rustler_tests/native/rustler_test/src/test_binary.rs +++ b/rustler_tests/native/rustler_test/src/test_binary.rs @@ -96,3 +96,33 @@ pub fn first_four_bytes_of_iolist<'a>(term: Term<'a>) -> Binary<'a> { let sub = bin.make_subbinary(0, 4).unwrap(); sub } + +#[rustler::nif] +pub fn array_into_binary() -> OwnedBinary { + [1, 2, 3].into() +} + +#[rustler::nif] +pub fn vec_into_binary() -> OwnedBinary { + vec![1, 2, 3].into() +} + +#[rustler::nif] +pub fn slice_into_binary() -> OwnedBinary { + [1, 2, 3][..].into() +} + +#[rustler::nif] +pub fn str_into_binary() -> OwnedBinary { + "foobar".into() +} + +#[rustler::nif] +pub fn string_into_binary() -> OwnedBinary { + String::from("foobar").into() +} + +#[rustler::nif] +pub fn binary_from_str() -> OwnedBinary { + OwnedBinary::from("foobar") +} diff --git a/rustler_tests/test/binary_test.exs b/rustler_tests/test/binary_test.exs index 9aa803fd..2411558a 100644 --- a/rustler_tests/test/binary_test.exs +++ b/rustler_tests/test/binary_test.exs @@ -64,4 +64,16 @@ defmodule RustlerTest.BinaryTest do assert RustlerTest.first_four_bytes_of_iolist(["hi", " ", "there"]) == "hi t" assert RustlerTest.first_four_bytes_of_iolist([[?h, ?i], ~c" ", ["there"]]) == "hi t" end + + test "trait Into" do + assert RustlerTest.array_into_binary() == <<1, 2, 3>> + assert RustlerTest.vec_into_binary() == <<1, 2, 3>> + assert RustlerTest.slice_into_binary() == <<1, 2, 3>> + assert RustlerTest.str_into_binary() == <<1, 2, 3>> + assert RustlerTest.string_into_binary() == <<1, 2, 3>> + end + + test "trait From" do + assert RustlerTest.binary_from_str() == <<1, 2, 3>> + end end From eba8ee365eacd5014bb9356f9e988dc5250e2cf5 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Tue, 25 Aug 2026 21:34:22 +0200 Subject: [PATCH 2/3] Add OwnedBinary::from_slice --- rustler/src/types/binary.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/rustler/src/types/binary.rs b/rustler/src/types/binary.rs index e387f202..ef0241b1 100644 --- a/rustler/src/types/binary.rs +++ b/rustler/src/types/binary.rs @@ -135,6 +135,14 @@ impl OwnedBinary { }) } + /// Copies 'data''s data into a new `OwnedBinary`. + pub fn from_slice(data: impl AsRef<[u8]>) -> Self { + let data = data.as_ref(); + let mut bin = OwnedBinary::new(data.len()).expect("allocation failed"); + bin.as_mut_slice().copy_from_slice(data); + bin + } + /// Attempts to reallocate `self` with the new size. /// /// Memory outside the range of the original binary will not be initialized. If @@ -264,12 +272,7 @@ impl FromIterator for OwnedBinary { impl> From for OwnedBinary { fn from(data: T) -> Self { - let buf = data.as_ref(); - let mut bin = Self::new(buf.len()).expect("Allocation failed"); - - bin.as_mut_slice().copy_from_slice(buf); - - bin + Self::from_slice(data) } } From 0662d5003ef5a112bbd3fca6c320a4b530d52c4a Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Tue, 25 Aug 2026 21:34:28 +0200 Subject: [PATCH 3/3] Fix tests --- rustler_tests/test/binary_test.exs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rustler_tests/test/binary_test.exs b/rustler_tests/test/binary_test.exs index 2411558a..2839fbf2 100644 --- a/rustler_tests/test/binary_test.exs +++ b/rustler_tests/test/binary_test.exs @@ -69,11 +69,11 @@ defmodule RustlerTest.BinaryTest do assert RustlerTest.array_into_binary() == <<1, 2, 3>> assert RustlerTest.vec_into_binary() == <<1, 2, 3>> assert RustlerTest.slice_into_binary() == <<1, 2, 3>> - assert RustlerTest.str_into_binary() == <<1, 2, 3>> - assert RustlerTest.string_into_binary() == <<1, 2, 3>> + assert RustlerTest.str_into_binary() == "foobar" + assert RustlerTest.string_into_binary() == "foobar" end test "trait From" do - assert RustlerTest.binary_from_str() == <<1, 2, 3>> + assert RustlerTest.binary_from_str() == "foobar" end end