add Str.toBytes

This commit is contained in:
Folkert 2021-02-21 19:52:32 +01:00
parent bcbef5d3aa
commit 9116e9e8c9
10 changed files with 73 additions and 2 deletions

View file

@ -68,6 +68,7 @@ comptime {
exportStrFn(str.strFromFloatC, "from_float");
exportStrFn(str.strEqual, "equal");
exportStrFn(str.validateUtf8Bytes, "validate_utf8_bytes");
exportStrFn(str.strToBytesC, "to_bytes");
}
// Export helpers - Must be run inside a comptime

View file

@ -1,4 +1,5 @@
const utils = @import("utils.zig");
const RocList = @import("list.zig").RocList;
const std = @import("std");
const mem = std.mem;
const always_inline = std.builtin.CallOptions.Modifier.always_inline;
@ -961,6 +962,26 @@ test "RocStr.joinWith: result is big" {
expect(roc_result.eq(result));
}
// Str.toBytes
pub fn strToBytesC(arg: RocStr) callconv(.C) RocList {
return @call(.{ .modifier = always_inline }, strToBytes, .{ std.heap.c_allocator, arg });
}
fn strToBytes(allocator: *Allocator, arg: RocStr) RocList {
if (arg.isEmpty()) {
return RocList.empty();
} else if (arg.isSmallStr()) {
const length = arg.len();
const ptr = utils.allocateWithRefcount(allocator, @alignOf(usize), length);
@memcpy(ptr, arg.asU8ptr(), length);
return RocList{ .length = length, .bytes = ptr };
} else {
return RocList{ .length = arg.len(), .bytes = arg.str_bytes };
}
}
pub fn isValidUnicode(ptr: [*]u8, len: usize) callconv(.C) bool {
const bytes: []u8 = ptr[0..len];
return @call(.{ .modifier = always_inline }, unicode.utf8ValidateSlice, .{bytes});

View file

@ -42,6 +42,7 @@ pub const STR_FROM_INT: &str = "roc_builtins.str.from_int";
pub const STR_FROM_FLOAT: &str = "roc_builtins.str.from_float";
pub const STR_EQUAL: &str = "roc_builtins.str.equal";
pub const STR_VALIDATE_UTF_BYTES: &str = "roc_builtins.str.validate_utf8_bytes";
pub const STR_TO_BYTES: &str = "roc_builtins.str.to_bytes";
pub const DICT_HASH: &str = "roc_builtins.dict.hash";
pub const DICT_HASH_STR: &str = "roc_builtins.dict.hash_str";

View file

@ -623,6 +623,12 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
),
);
// toBytes : Str -> List U8
add_type(
Symbol::STR_TO_BYTES,
top_level_function(vec![str_type()], Box::new(list_type(u8_type()))),
);
// fromFloat : Float a -> Str
add_type(
Symbol::STR_FROM_FLOAT,

View file

@ -62,6 +62,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
STR_COUNT_GRAPHEMES => str_count_graphemes,
STR_FROM_INT => str_from_int,
STR_FROM_UTF8 => str_from_utf8,
STR_TO_BYTES => str_to_bytes,
STR_FROM_FLOAT=> str_from_float,
LIST_LEN => list_len,
LIST_GET => list_get,
@ -196,6 +197,7 @@ pub fn builtin_defs(var_store: &mut VarStore) -> MutMap<Symbol, Def> {
Symbol::STR_COUNT_GRAPHEMES => str_count_graphemes,
Symbol::STR_FROM_INT => str_from_int,
Symbol::STR_FROM_UTF8 => str_from_utf8,
Symbol::STR_TO_BYTES => str_to_bytes,
Symbol::STR_FROM_FLOAT=> str_from_float,
Symbol::LIST_LEN => list_len,
Symbol::LIST_GET => list_get,
@ -1655,6 +1657,11 @@ fn str_from_utf8(symbol: Symbol, var_store: &mut VarStore) -> Def {
)
}
/// Str.toBytes : Str -> List U8
fn str_to_bytes(symbol: Symbol, var_store: &mut VarStore) -> Def {
lowlevel_1(symbol, LowLevel::StrToBytes, var_store)
}
/// Str.fromFloat : Float * -> Str
fn str_from_float(symbol: Symbol, var_store: &mut VarStore) -> Def {
let float_var = var_store.fresh();

View file

@ -12,7 +12,7 @@ use crate::llvm::build_list::{
};
use crate::llvm::build_str::{
str_concat, str_count_graphemes, str_ends_with, str_from_float, str_from_int, str_from_utf8,
str_join_with, str_number_of_bytes, str_split, str_starts_with, CHAR_LAYOUT,
str_join_with, str_number_of_bytes, str_split, str_starts_with, str_to_bytes, CHAR_LAYOUT,
};
use crate::llvm::compare::{generic_eq, generic_neq};
use crate::llvm::convert::{
@ -3611,13 +3611,23 @@ fn run_low_level<'a, 'ctx, 'env>(
str_from_float(env, scope, args[0])
}
StrFromUtf8 => {
// Str.fromInt : Int -> Str
// Str.fromUtf8 : List U8 -> Result Str Utf8Problem
debug_assert_eq!(args.len(), 1);
let original_wrapper = load_symbol(scope, &args[0]).into_struct_value();
str_from_utf8(env, parent, original_wrapper)
}
StrToBytes => {
// Str.fromInt : Str -> List U8
debug_assert_eq!(args.len(), 1);
// this is an identity conversion
// we just implement it here to subvert the type system
let string = load_symbol(scope, &args[0]);
str_to_bytes(env, string.into_struct_value())
}
StrSplit => {
// Str.split : Str, Str -> List Str
debug_assert_eq!(args.len(), 2);

View file

@ -275,6 +275,28 @@ pub fn str_from_int<'a, 'ctx, 'env>(
zig_str_to_struct(env, zig_result).into()
}
/// Str.toBytes : Str -> List U8
pub fn str_to_bytes<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
original_wrapper: StructValue<'ctx>,
) -> BasicValueEnum<'ctx> {
let string = complex_bitcast(
env.builder,
original_wrapper.into(),
env.context.i128_type().into(),
"to_bytes",
);
let zig_result = call_bitcode_fn(env, &[string], &bitcode::STR_TO_BYTES);
complex_bitcast(
env.builder,
zig_result,
collection(env.context, env.ptr_bytes).into(),
"to_bytes",
)
}
/// Str.fromUtf8 : List U8 -> { a : Bool, b : Str, c : Nat, d : I8 }
pub fn str_from_utf8<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,

View file

@ -12,6 +12,7 @@ pub enum LowLevel {
StrCountGraphemes,
StrFromInt,
StrFromUtf8,
StrToBytes,
StrFromFloat,
ListLen,
ListGetUnsafe,

View file

@ -882,6 +882,7 @@ define_builtins! {
12 STR_FROM_UTF8: "fromUtf8"
13 STR_UT8_PROBLEM: "Utf8Problem" // the Utf8Problem type alias
14 STR_UT8_BYTE_PROBLEM: "Utf8ByteProblem" // the Utf8ByteProblem type alias
15 STR_TO_BYTES: "toBytes"
}
4 LIST: "List" => {
0 LIST_LIST: "List" imported // the List.List type alias

View file

@ -676,6 +676,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
}
StrStartsWith | StrEndsWith => arena.alloc_slice_copy(&[owned, borrowed]),
StrFromUtf8 => arena.alloc_slice_copy(&[owned]),
StrToBytes => arena.alloc_slice_copy(&[owned]),
StrFromInt | StrFromFloat => arena.alloc_slice_copy(&[irrelevant]),
Hash => arena.alloc_slice_copy(&[borrowed, irrelevant]),
DictSize => arena.alloc_slice_copy(&[borrowed]),