Skip to content

Commit ef9fc8f

Browse files
Add fine::make_new_binary to streamline returning large buffers (#6)
1 parent d7309f8 commit ef9fc8f

File tree

5 files changed

+33
-6
lines changed

5 files changed

+33
-6
lines changed

README.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -181,19 +181,15 @@ Fine provides implementations for the following types:
181181
> circumvented.
182182
>
183183
> Similarly, when returning large binaries, prefer creating the term
184-
> with `enif_make_new_binary` and returning `fine::Term`, instead of
184+
> with `fine::make_new_binary` and returning `fine::Term`, instead of
185185
> allocating an intermediary `std::string`, as shown below.
186186
>
187187
> ```c++
188188
> fine::Term read_data(ErlNifEnv *env) {
189189
> const char *buffer = ...;
190190
> uint64_t size = ...;
191191
>
192-
> ERL_NIF_TERM binary_term;
193-
> auto binary_data = enif_make_new_binary(env, size, &binary_term);
194-
> memcpy(binary_data, buffer, size);
195-
>
196-
> return binary_term;
192+
> return fine::make_new_binary(env, buffer, size);
197193
> }
198194
> ```
199195
>

include/fine.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,22 @@ Term make_resource_binary(ErlNifEnv *env, ResourcePtr<T> resource,
300300
env, reinterpret_cast<void *>(resource.get()), data, size);
301301
}
302302

303+
// Creates a binary term copying data from the given buffer.
304+
//
305+
// This is useful when returning large binary from a NIF and the source
306+
// buffer does not outlive the return.
307+
inline fine::Term make_new_binary(ErlNifEnv *env, const char *data,
308+
size_t size) {
309+
ERL_NIF_TERM term;
310+
auto term_data = enif_make_new_binary(env, size, &term);
311+
if (term_data == nullptr) {
312+
throw std::runtime_error(
313+
"make_new_binary failed, failed to allocate new binary");
314+
}
315+
memcpy(term_data, data, size);
316+
return term;
317+
}
318+
303319
// Decodes the given Erlang term as a value of the specified type.
304320
//
305321
// The given type must have a specialized Decoder<T> implementation.

test/c_src/finest.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,13 @@ ErlNifPid resource_get(ErlNifEnv *, fine::ResourcePtr<TestResource> resource) {
186186
}
187187
FINE_NIF(resource_get, 0);
188188

189+
fine::Term make_new_binary(ErlNifEnv *env) {
190+
const char *buffer = "hello world";
191+
size_t size = 11;
192+
return fine::make_new_binary(env, buffer, size);
193+
}
194+
FINE_NIF(make_new_binary, 0);
195+
189196
int64_t throw_runtime_error(ErlNifEnv *) {
190197
throw std::runtime_error("runtime error reason");
191198
}

test/lib/finest/nif.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ defmodule Finest.NIF do
4141
def resource_create(_pid), do: err!()
4242
def resource_get(_resource), do: err!()
4343

44+
def make_new_binary(), do: err!()
45+
4446
def throw_runtime_error(), do: err!()
4547
def throw_invalid_argument(), do: err!()
4648
def throw_other_exception(), do: err!()

test/test/finest_test.exs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,12 @@ defmodule FinestTest do
234234
end
235235
end
236236

237+
describe "make_new_binary" do
238+
test "creates a binary term copying the original buffer" do
239+
assert NIF.make_new_binary() == "hello world"
240+
end
241+
end
242+
237243
describe "exceptions" do
238244
test "standard exceptions" do
239245
assert_raise RuntimeError, "runtime error reason", fn ->

0 commit comments

Comments
 (0)