diff --git a/src/core/inttypes.c b/src/core/inttypes.c index d985c5c7..cc7a5787 100644 --- a/src/core/inttypes.c +++ b/src/core/inttypes.c @@ -239,13 +239,15 @@ JANET_CORE_FN(cfun_to_number, } JANET_CORE_FN(cfun_to_bytes, - "(int/to-bytes value &opt endianness)", - "Convert an `int/s64` or `int/u64` into an 8-element tuple of bytes.\n" - "the endianness paramater indicates the byte order:\n" + "(int/to-bytes value &opt endianness buffer)", + "Write the bytes of an `int/s64` or `int/u64` into a buffer.\n" + "The `buffer` parameter specifies an existing buffer to write to, if unset a new buffer will be created.\n" + "Returns the modified buffer.\n" + "The `endianness` paramater indicates the byte order:\n" "- `nil` (unset): system byte order\n" "- `:le`: little-endian, least significant byte first\n" "- `:be`: big-endian, most significant byte first\n") { - janet_arity(argc, 1, 2); + janet_arity(argc, 1, 3); if (janet_is_int(argv[0]) == JANET_INT_NONE) { janet_panicf("int/to-bytes: expected an int/s64 or int/u64, got %q", argv[0]); } @@ -266,13 +268,29 @@ JANET_CORE_FN(cfun_to_bytes, } } - uint8_t *bytes = janet_unwrap_abstract(argv[0]); - Janet *bytes_tuple = janet_tuple_begin(8); - for (int i = 0; i < 8; ++i) { - bytes_tuple[i] = janet_wrap_integer(bytes[reverse ? 7 - i : i]); + JanetBuffer *buffer = NULL; + if (argc > 2 && !janet_checktype(argv[2], JANET_NIL)) { + if (!janet_checktype(argv[2], JANET_BUFFER)) { + janet_panicf("int/to-bytes: expected buffer or nil, got %q", argv[2]); + } + + buffer = janet_unwrap_buffer(argv[2]); + janet_buffer_extra(buffer, 8); + } else { + buffer = janet_buffer(8); } - return janet_wrap_tuple(janet_tuple_end(bytes_tuple)); + uint8_t *bytes = janet_unwrap_abstract(argv[0]); + if (reverse) { + for (int i = 0; i < 8; ++i) { + buffer->data[buffer->count + 7 - i] = bytes[i]; + } + } else { + memcpy(buffer->data + buffer->count, bytes, 8); + } + buffer->count += 8; + + return janet_wrap_buffer(buffer); } /* diff --git a/test/suite0006.janet b/test/suite0006.janet index 52309c01..34633ebd 100644 --- a/test/suite0006.janet +++ b/test/suite0006.janet @@ -92,17 +92,25 @@ (:/ (int/s64 "-0x8000_0000_0000_0000") -1)) # int/s64 and int/u64 serialization -(assert (= (int/to-bytes (u64 0)) [0 0 0 0 0 0 0 0])) +(assert (deep= (int/to-bytes (u64 0)) @"\x00\x00\x00\x00\x00\x00\x00\x00")) -(assert (= (int/to-bytes (i64 1) :le) [1 0 0 0 0 0 0 0])) -(assert (= (int/to-bytes (i64 1) :be) [0 0 0 0 0 0 0 1])) -(assert (= (int/to-bytes (i64 -1)) [0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF])) -(assert (= (int/to-bytes (i64 -5) :be) [0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF (- 0xFF 4)])) +(assert (deep= (int/to-bytes (i64 1) :le) @"\x01\x00\x00\x00\x00\x00\x00\x00")) +(assert (deep= (int/to-bytes (i64 1) :be) @"\x00\x00\x00\x00\x00\x00\x00\x01")) +(assert (deep= (int/to-bytes (i64 -1)) @"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF")) +(assert (deep= (int/to-bytes (i64 -5) :be) @"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFB")) -(assert (= (int/to-bytes (u64 1) :le) [1 0 0 0 0 0 0 0])) -(assert (= (int/to-bytes (u64 1) :be) [0 0 0 0 0 0 0 1])) -(assert (= (int/to-bytes (u64 300) :be) [0 0 0 0 0 0 0x01 0x2C])) +(assert (deep= (int/to-bytes (u64 1) :le) @"\x01\x00\x00\x00\x00\x00\x00\x00")) +(assert (deep= (int/to-bytes (u64 1) :be) @"\x00\x00\x00\x00\x00\x00\x00\x01")) +(assert (deep= (int/to-bytes (u64 300) :be) @"\x00\x00\x00\x00\x00\x00\x01\x2C")) +# int/s64 int/u64 to existing buffer +(let [buf1 @"" + buf2 @"abcd"] + (assert (deep= (int/to-bytes (i64 1) :le buf1) @"\x01\x00\x00\x00\x00\x00\x00\x00")) + (assert (deep= buf1 @"\x01\x00\x00\x00\x00\x00\x00\x00")) + (assert (deep= (int/to-bytes (u64 300) :be buf2) @"abcd\x00\x00\x00\x00\x00\x00\x01\x2C"))) + +# int/s64 and int/u64 paramater type checking (assert-error "bad value passed to int/to-bytes" (int/to-bytes 1)) @@ -111,6 +119,10 @@ "invalid endianness passed to int/to-bytes" (int/to-bytes (u64 0) :little)) +(assert-error + "invalid buffer passed to int/to-bytes" + (int/to-bytes (u64 0) :little :buffer)) + # Dynamic bindings (setdyn :a 10)