mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 07:41:12 +00:00
Add small string support to the dev backend
This commit is contained in:
parent
1fba3702a8
commit
2f24067267
3 changed files with 1017 additions and 7 deletions
|
@ -9,7 +9,7 @@ use std::marker::PhantomData;
|
||||||
pub mod aarch64;
|
pub mod aarch64;
|
||||||
pub mod x86_64;
|
pub mod x86_64;
|
||||||
|
|
||||||
const PTR_SIZE: u32 = 64;
|
const PTR_SIZE: u32 = 8;
|
||||||
|
|
||||||
pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait> {
|
pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait> {
|
||||||
const GENERAL_PARAM_REGS: &'static [GeneralReg];
|
const GENERAL_PARAM_REGS: &'static [GeneralReg];
|
||||||
|
@ -489,6 +489,25 @@ impl<
|
||||||
ASM::mov_freg64_freg64(&mut self.buf, dst_reg, CC::FLOAT_RETURN_REGS[0]);
|
ASM::mov_freg64_freg64(&mut self.buf, dst_reg, CC::FLOAT_RETURN_REGS[0]);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Layout::Builtin(Builtin::Str) => {
|
||||||
|
if CC::returns_via_arg_pointer(ret_layout)? {
|
||||||
|
// This will happen on windows, return via pointer here.
|
||||||
|
Err("FnCall: Returning strings via pointer not yet implemented".to_string())
|
||||||
|
} else {
|
||||||
|
let offset = self.claim_stack_size(16)?;
|
||||||
|
self.symbol_storage_map.insert(
|
||||||
|
*dst,
|
||||||
|
SymbolStorage::Base {
|
||||||
|
offset,
|
||||||
|
size: 16,
|
||||||
|
owned: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
ASM::mov_base32_reg64(&mut self.buf, offset, CC::GENERAL_RETURN_REGS[0]);
|
||||||
|
ASM::mov_base32_reg64(&mut self.buf, offset + 8, CC::GENERAL_RETURN_REGS[1]);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
x => Err(format!(
|
x => Err(format!(
|
||||||
"FnCall: receiving return type, {:?}, is not yet implemented",
|
"FnCall: receiving return type, {:?}, is not yet implemented",
|
||||||
x
|
x
|
||||||
|
@ -893,6 +912,35 @@ impl<
|
||||||
ASM::mov_freg64_imm64(&mut self.buf, &mut self.relocs, reg, val);
|
ASM::mov_freg64_imm64(&mut self.buf, &mut self.relocs, reg, val);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Literal::Str(x) if x.len() < 16 => {
|
||||||
|
// Load small string.
|
||||||
|
let reg = self.get_tmp_general_reg()?;
|
||||||
|
|
||||||
|
let offset = self.claim_stack_size(16)?;
|
||||||
|
self.symbol_storage_map.insert(
|
||||||
|
*sym,
|
||||||
|
SymbolStorage::Base {
|
||||||
|
offset,
|
||||||
|
size: 16,
|
||||||
|
owned: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let mut bytes = [0; 16];
|
||||||
|
bytes[..x.len()].copy_from_slice(x.as_bytes());
|
||||||
|
bytes[15] = (x.len() as u8) | 0b1000_0000;
|
||||||
|
|
||||||
|
let mut num_bytes = [0; 8];
|
||||||
|
num_bytes.copy_from_slice(&bytes[..8]);
|
||||||
|
let num = i64::from_ne_bytes(num_bytes);
|
||||||
|
ASM::mov_reg64_imm64(&mut self.buf, reg, num);
|
||||||
|
ASM::mov_base32_reg64(&mut self.buf, offset, reg);
|
||||||
|
|
||||||
|
num_bytes.copy_from_slice(&bytes[8..]);
|
||||||
|
let num = i64::from_ne_bytes(num_bytes);
|
||||||
|
ASM::mov_reg64_imm64(&mut self.buf, reg, num);
|
||||||
|
ASM::mov_base32_reg64(&mut self.buf, offset + 8, reg);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
x => Err(format!("loading literal, {:?}, is not yet implemented", x)),
|
x => Err(format!("loading literal, {:?}, is not yet implemented", x)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1012,6 +1060,20 @@ impl<
|
||||||
Layout::Builtin(Builtin::Float64) => {
|
Layout::Builtin(Builtin::Float64) => {
|
||||||
ASM::mov_freg64_base32(&mut self.buf, CC::FLOAT_RETURN_REGS[0], *offset);
|
ASM::mov_freg64_base32(&mut self.buf, CC::FLOAT_RETURN_REGS[0], *offset);
|
||||||
}
|
}
|
||||||
|
Layout::Builtin(Builtin::Str) => {
|
||||||
|
if self.symbol_storage_map.contains_key(&Symbol::RET_POINTER) {
|
||||||
|
// This will happen on windows, return via pointer here.
|
||||||
|
Err("Returning strings via pointer not yet implemented".to_string())
|
||||||
|
} else {
|
||||||
|
ASM::mov_reg64_base32(&mut self.buf, CC::GENERAL_RETURN_REGS[0], *offset);
|
||||||
|
ASM::mov_reg64_base32(
|
||||||
|
&mut self.buf,
|
||||||
|
CC::GENERAL_RETURN_REGS[1],
|
||||||
|
*offset + 8,
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
Layout::Struct(field_layouts) => {
|
Layout::Struct(field_layouts) => {
|
||||||
let (offset, size) = (*offset, *size);
|
let (offset, size) = (*offset, *size);
|
||||||
// Nothing to do for empty struct
|
// Nothing to do for empty struct
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
#[macro_use]
|
|
||||||
extern crate pretty_assertions;
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate indoc;
|
extern crate indoc;
|
||||||
|
|
||||||
extern crate bumpalo;
|
|
||||||
extern crate libc;
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod helpers;
|
mod helpers;
|
||||||
|
|
||||||
|
|
954
compiler/gen_dev/tests/dev_str.rs
Normal file
954
compiler/gen_dev/tests/dev_str.rs
Normal file
|
@ -0,0 +1,954 @@
|
||||||
|
// use roc_std::{RocList, RocStr};
|
||||||
|
#[macro_use]
|
||||||
|
extern crate indoc;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod helpers;
|
||||||
|
|
||||||
|
#[cfg(all(test, any(target_os = "linux", target_os = "macos"), any(target_arch = "x86_64"/*, target_arch = "aarch64"*/)))]
|
||||||
|
mod dev_str {
|
||||||
|
// #[test]
|
||||||
|
// fn str_split_bigger_delimiter_small_str() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// List.len (Str.split "hello" "JJJJ there")
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// 1,
|
||||||
|
// i64
|
||||||
|
// );
|
||||||
|
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// when List.first (Str.split "JJJ" "JJJJ there") is
|
||||||
|
// Ok str ->
|
||||||
|
// Str.countGraphemes str
|
||||||
|
|
||||||
|
// _ ->
|
||||||
|
// -1
|
||||||
|
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// 3,
|
||||||
|
// i64
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_split_str_concat_repeated() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// when List.first (Str.split "JJJJJ" "JJJJ there") is
|
||||||
|
// Ok str ->
|
||||||
|
// str
|
||||||
|
// |> Str.concat str
|
||||||
|
// |> Str.concat str
|
||||||
|
// |> Str.concat str
|
||||||
|
// |> Str.concat str
|
||||||
|
|
||||||
|
// _ ->
|
||||||
|
// "Not Str!"
|
||||||
|
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocStr::from_slice(b"JJJJJJJJJJJJJJJJJJJJJJJJJ"),
|
||||||
|
// RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_split_small_str_bigger_delimiter() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// when
|
||||||
|
// List.first
|
||||||
|
// (Str.split "JJJ" "0123456789abcdefghi")
|
||||||
|
// is
|
||||||
|
// Ok str -> str
|
||||||
|
// _ -> ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocStr::from_slice(b"JJJ"),
|
||||||
|
// RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_split_big_str_small_delimiter() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// Str.split "01234567789abcdefghi?01234567789abcdefghi" "?"
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocList::from_slice(&[
|
||||||
|
// RocStr::from_slice(b"01234567789abcdefghi"),
|
||||||
|
// RocStr::from_slice(b"01234567789abcdefghi")
|
||||||
|
// ]),
|
||||||
|
// RocList<RocStr>
|
||||||
|
// );
|
||||||
|
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// Str.split "01234567789abcdefghi 3ch 01234567789abcdefghi" "3ch"
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocList::from_slice(&[
|
||||||
|
// RocStr::from_slice(b"01234567789abcdefghi "),
|
||||||
|
// RocStr::from_slice(b" 01234567789abcdefghi")
|
||||||
|
// ]),
|
||||||
|
// RocList<RocStr>
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_split_small_str_small_delimiter() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// Str.split "J!J!J" "!"
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocList::from_slice(&[
|
||||||
|
// RocStr::from_slice(b"J"),
|
||||||
|
// RocStr::from_slice(b"J"),
|
||||||
|
// RocStr::from_slice(b"J")
|
||||||
|
// ]),
|
||||||
|
// RocList<RocStr>
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_split_bigger_delimiter_big_strs() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// Str.split
|
||||||
|
// "string to split is shorter"
|
||||||
|
// "than the delimiter which happens to be very very long"
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocList::from_slice(&[RocStr::from_slice(b"string to split is shorter")]),
|
||||||
|
// RocList<RocStr>
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_split_empty_strs() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// Str.split "" ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocList::from_slice(&[RocStr::from_slice(b"")]),
|
||||||
|
// RocList<RocStr>
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_split_minimal_example() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// Str.split "a," ","
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocList::from_slice(&[RocStr::from_slice(b"a"), RocStr::from_slice(b"")]),
|
||||||
|
// RocList<RocStr>
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_split_small_str_big_delimiter() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// Str.split
|
||||||
|
// "1---- ---- ---- ---- ----2---- ---- ---- ---- ----"
|
||||||
|
// "---- ---- ---- ---- ----"
|
||||||
|
// |> List.len
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// 3,
|
||||||
|
// i64
|
||||||
|
// );
|
||||||
|
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// Str.split
|
||||||
|
// "1---- ---- ---- ---- ----2---- ---- ---- ---- ----"
|
||||||
|
// "---- ---- ---- ---- ----"
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocList::from_slice(&[
|
||||||
|
// RocStr::from_slice(b"1"),
|
||||||
|
// RocStr::from_slice(b"2"),
|
||||||
|
// RocStr::from_slice(b"")
|
||||||
|
// ]),
|
||||||
|
// RocList<RocStr>
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_split_small_str_20_char_delimiter() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// Str.split
|
||||||
|
// "3|-- -- -- -- -- -- |4|-- -- -- -- -- -- |"
|
||||||
|
// "|-- -- -- -- -- -- |"
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocList::from_slice(&[
|
||||||
|
// RocStr::from_slice(b"3"),
|
||||||
|
// RocStr::from_slice(b"4"),
|
||||||
|
// RocStr::from_slice(b"")
|
||||||
|
// ]),
|
||||||
|
// RocList<RocStr>
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_concat_big_to_big() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// Str.concat
|
||||||
|
// "First string that is fairly long. Longer strings make for different errors. "
|
||||||
|
// "Second string that is also fairly long. Two long strings test things that might not appear with short strings."
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocStr::from_slice(b"First string that is fairly long. Longer strings make for different errors. Second string that is also fairly long. Two long strings test things that might not appear with short strings."),
|
||||||
|
// RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn small_str_literal() {
|
||||||
|
assert_evals_to!(
|
||||||
|
"\"JJJJJJJJJJJJJJJ\"",
|
||||||
|
[
|
||||||
|
0x4a,
|
||||||
|
0x4a,
|
||||||
|
0x4a,
|
||||||
|
0x4a,
|
||||||
|
0x4a,
|
||||||
|
0x4a,
|
||||||
|
0x4a,
|
||||||
|
0x4a,
|
||||||
|
0x4a,
|
||||||
|
0x4a,
|
||||||
|
0x4a,
|
||||||
|
0x4a,
|
||||||
|
0x4a,
|
||||||
|
0x4a,
|
||||||
|
0x4a,
|
||||||
|
0b1000_1111
|
||||||
|
],
|
||||||
|
[u8; 16]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn small_str_zeroed_literal() {
|
||||||
|
// // Verifies that we zero out unused bytes in the string.
|
||||||
|
// // This is important so that string equality tests don't randomly
|
||||||
|
// // fail due to unused memory being there!
|
||||||
|
// assert_llvm_evals_to!(
|
||||||
|
// "\"J\"",
|
||||||
|
// [
|
||||||
|
// 0x4a,
|
||||||
|
// 0x00,
|
||||||
|
// 0x00,
|
||||||
|
// 0x00,
|
||||||
|
// 0x00,
|
||||||
|
// 0x00,
|
||||||
|
// 0x00,
|
||||||
|
// 0x00,
|
||||||
|
// 0x00,
|
||||||
|
// 0x00,
|
||||||
|
// 0x00,
|
||||||
|
// 0x00,
|
||||||
|
// 0x00,
|
||||||
|
// 0x00,
|
||||||
|
// 0x00,
|
||||||
|
// 0b1000_0001
|
||||||
|
// ],
|
||||||
|
// [u8; 16]
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn small_str_concat_empty_first_arg() {
|
||||||
|
// assert_llvm_evals_to!(
|
||||||
|
// r#"Str.concat "" "JJJJJJJJJJJJJJJ""#,
|
||||||
|
// [
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0b1000_1111
|
||||||
|
// ],
|
||||||
|
// [u8; 16]
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn small_str_concat_empty_second_arg() {
|
||||||
|
// assert_llvm_evals_to!(
|
||||||
|
// r#"Str.concat "JJJJJJJJJJJJJJJ" """#,
|
||||||
|
// [
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0b1000_1111
|
||||||
|
// ],
|
||||||
|
// [u8; 16]
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn small_str_concat_small_to_big() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// r#"Str.concat "abc" " this is longer than 15 chars""#,
|
||||||
|
// RocStr::from_slice(b"abc this is longer than 15 chars"),
|
||||||
|
// RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn small_str_concat_small_to_small_staying_small() {
|
||||||
|
// assert_llvm_evals_to!(
|
||||||
|
// r#"Str.concat "J" "JJJJJJJJJJJJJJ""#,
|
||||||
|
// [
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0x4a,
|
||||||
|
// 0b1000_1111
|
||||||
|
// ],
|
||||||
|
// [u8; 16]
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn small_str_concat_small_to_small_overflow_to_big() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// r#"Str.concat "abcdefghijklm" "nopqrstuvwxyz""#,
|
||||||
|
// RocStr::from_slice(b"abcdefghijklmnopqrstuvwxyz"),
|
||||||
|
// RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_concat_empty() {
|
||||||
|
// assert_evals_to!(r#"Str.concat "" """#, RocStr::default(), RocStr);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn small_str_is_empty() {
|
||||||
|
// assert_evals_to!(r#"Str.isEmpty "abc""#, false, bool);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn big_str_is_empty() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// r#"Str.isEmpty "this is more than 15 chars long""#,
|
||||||
|
// false,
|
||||||
|
// bool
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn empty_str_is_empty() {
|
||||||
|
// assert_evals_to!(r#"Str.isEmpty """#, true, bool);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_starts_with() {
|
||||||
|
// assert_evals_to!(r#"Str.startsWith "hello world" "hell""#, true, bool);
|
||||||
|
// assert_evals_to!(r#"Str.startsWith "hello world" """#, true, bool);
|
||||||
|
// assert_evals_to!(r#"Str.startsWith "nope" "hello world""#, false, bool);
|
||||||
|
// assert_evals_to!(r#"Str.startsWith "hell" "hello world""#, false, bool);
|
||||||
|
// assert_evals_to!(r#"Str.startsWith "" "hello world""#, false, bool);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_starts_with_code_point() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// &format!(r#"Str.startsWithCodePt "foobar" {}"#, 'f' as u32),
|
||||||
|
// true,
|
||||||
|
// bool
|
||||||
|
// );
|
||||||
|
// assert_evals_to!(
|
||||||
|
// &format!(r#"Str.startsWithCodePt "zoobar" {}"#, 'f' as u32),
|
||||||
|
// false,
|
||||||
|
// bool
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_ends_with() {
|
||||||
|
// assert_evals_to!(r#"Str.endsWith "hello world" "world""#, true, bool);
|
||||||
|
// assert_evals_to!(r#"Str.endsWith "nope" "hello world""#, false, bool);
|
||||||
|
// assert_evals_to!(r#"Str.endsWith "" "hello world""#, false, bool);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_count_graphemes_small_str() {
|
||||||
|
// assert_evals_to!(r#"Str.countGraphemes "å🤔""#, 2, usize);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_count_graphemes_three_js() {
|
||||||
|
// assert_evals_to!(r#"Str.countGraphemes "JJJ""#, 3, usize);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_count_graphemes_big_str() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// r#"Str.countGraphemes "6🤔å🤔e¥🤔çppkd🙃1jdal🦯asdfa∆ltråø˚waia8918.,🏅jjc""#,
|
||||||
|
// 45,
|
||||||
|
// usize
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_starts_with_same_big_str() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// r#"Str.startsWith "123456789123456789" "123456789123456789""#,
|
||||||
|
// true,
|
||||||
|
// bool
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_starts_with_different_big_str() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// r#"Str.startsWith "12345678912345678910" "123456789123456789""#,
|
||||||
|
// true,
|
||||||
|
// bool
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_starts_with_same_small_str() {
|
||||||
|
// assert_evals_to!(r#"Str.startsWith "1234" "1234""#, true, bool);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_starts_with_different_small_str() {
|
||||||
|
// assert_evals_to!(r#"Str.startsWith "1234" "12""#, true, bool);
|
||||||
|
// }
|
||||||
|
// #[test]
|
||||||
|
// fn str_starts_with_false_small_str() {
|
||||||
|
// assert_evals_to!(r#"Str.startsWith "1234" "23""#, false, bool);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_int() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// r#"Str.fromInt 1234"#,
|
||||||
|
// roc_std::RocStr::from_slice("1234".as_bytes()),
|
||||||
|
// roc_std::RocStr
|
||||||
|
// );
|
||||||
|
// assert_evals_to!(
|
||||||
|
// r#"Str.fromInt 0"#,
|
||||||
|
// roc_std::RocStr::from_slice("0".as_bytes()),
|
||||||
|
// roc_std::RocStr
|
||||||
|
// );
|
||||||
|
// assert_evals_to!(
|
||||||
|
// r#"Str.fromInt -1"#,
|
||||||
|
// roc_std::RocStr::from_slice("-1".as_bytes()),
|
||||||
|
// roc_std::RocStr
|
||||||
|
// );
|
||||||
|
|
||||||
|
// let max = format!("{}", i64::MAX);
|
||||||
|
// assert_evals_to!(
|
||||||
|
// r#"Str.fromInt Num.maxInt"#,
|
||||||
|
// RocStr::from_slice(max.as_bytes()),
|
||||||
|
// RocStr
|
||||||
|
// );
|
||||||
|
|
||||||
|
// let min = format!("{}", i64::MIN);
|
||||||
|
// assert_evals_to!(
|
||||||
|
// r#"Str.fromInt Num.minInt"#,
|
||||||
|
// RocStr::from_slice(min.as_bytes()),
|
||||||
|
// RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_pass_single_ascii() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// when Str.fromUtf8 [ 97 ] is
|
||||||
|
// Ok val -> val
|
||||||
|
// Err _ -> ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// roc_std::RocStr::from_slice("a".as_bytes()),
|
||||||
|
// roc_std::RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_pass_many_ascii() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// when Str.fromUtf8 [ 97, 98, 99, 0x7E ] is
|
||||||
|
// Ok val -> val
|
||||||
|
// Err _ -> ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// roc_std::RocStr::from_slice("abc~".as_bytes()),
|
||||||
|
// roc_std::RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_pass_single_unicode() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// when Str.fromUtf8 [ 0xE2, 0x88, 0x86 ] is
|
||||||
|
// Ok val -> val
|
||||||
|
// Err _ -> ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// roc_std::RocStr::from_slice("∆".as_bytes()),
|
||||||
|
// roc_std::RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_pass_many_unicode() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// when Str.fromUtf8 [ 0xE2, 0x88, 0x86, 0xC5, 0x93, 0xC2, 0xAC ] is
|
||||||
|
// Ok val -> val
|
||||||
|
// Err _ -> ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// roc_std::RocStr::from_slice("∆œ¬".as_bytes()),
|
||||||
|
// roc_std::RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_pass_single_grapheme() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// when Str.fromUtf8 [ 0xF0, 0x9F, 0x92, 0x96 ] is
|
||||||
|
// Ok val -> val
|
||||||
|
// Err _ -> ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// roc_std::RocStr::from_slice("💖".as_bytes()),
|
||||||
|
// roc_std::RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_pass_many_grapheme() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// when Str.fromUtf8 [ 0xF0, 0x9F, 0x92, 0x96, 0xF0, 0x9F, 0xA4, 0xA0, 0xF0, 0x9F, 0x9A, 0x80 ] is
|
||||||
|
// Ok val -> val
|
||||||
|
// Err _ -> ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// roc_std::RocStr::from_slice("💖🤠🚀".as_bytes()),
|
||||||
|
// roc_std::RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_pass_all() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// when Str.fromUtf8 [ 0xF0, 0x9F, 0x92, 0x96, 98, 0xE2, 0x88, 0x86 ] is
|
||||||
|
// Ok val -> val
|
||||||
|
// Err _ -> ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// roc_std::RocStr::from_slice("💖b∆".as_bytes()),
|
||||||
|
// roc_std::RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_fail_invalid_start_byte() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// when Str.fromUtf8 [ 97, 98, 0x80, 99 ] is
|
||||||
|
// Err (BadUtf8 InvalidStartByte byteIndex) ->
|
||||||
|
// if byteIndex == 2 then
|
||||||
|
// "a"
|
||||||
|
// else
|
||||||
|
// "b"
|
||||||
|
// _ -> ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// roc_std::RocStr::from_slice("a".as_bytes()),
|
||||||
|
// roc_std::RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_fail_unexpected_end_of_sequence() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// when Str.fromUtf8 [ 97, 98, 99, 0xC2 ] is
|
||||||
|
// Err (BadUtf8 UnexpectedEndOfSequence byteIndex) ->
|
||||||
|
// if byteIndex == 3 then
|
||||||
|
// "a"
|
||||||
|
// else
|
||||||
|
// "b"
|
||||||
|
// _ -> ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// roc_std::RocStr::from_slice("a".as_bytes()),
|
||||||
|
// roc_std::RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_fail_expected_continuation() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// when Str.fromUtf8 [ 97, 98, 99, 0xC2, 0x00 ] is
|
||||||
|
// Err (BadUtf8 ExpectedContinuation byteIndex) ->
|
||||||
|
// if byteIndex == 3 then
|
||||||
|
// "a"
|
||||||
|
// else
|
||||||
|
// "b"
|
||||||
|
// _ -> ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// roc_std::RocStr::from_slice("a".as_bytes()),
|
||||||
|
// roc_std::RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_fail_overlong_encoding() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// when Str.fromUtf8 [ 97, 0xF0, 0x80, 0x80, 0x80 ] is
|
||||||
|
// Err (BadUtf8 OverlongEncoding byteIndex) ->
|
||||||
|
// if byteIndex == 1 then
|
||||||
|
// "a"
|
||||||
|
// else
|
||||||
|
// "b"
|
||||||
|
// _ -> ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// roc_std::RocStr::from_slice("a".as_bytes()),
|
||||||
|
// roc_std::RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_fail_codepoint_too_large() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// when Str.fromUtf8 [ 97, 0xF4, 0x90, 0x80, 0x80 ] is
|
||||||
|
// Err (BadUtf8 CodepointTooLarge byteIndex) ->
|
||||||
|
// if byteIndex == 1 then
|
||||||
|
// "a"
|
||||||
|
// else
|
||||||
|
// "b"
|
||||||
|
// _ -> ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// roc_std::RocStr::from_slice("a".as_bytes()),
|
||||||
|
// roc_std::RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_fail_surrogate_half() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// when Str.fromUtf8 [ 97, 98, 0xED, 0xA0, 0x80 ] is
|
||||||
|
// Err (BadUtf8 EncodesSurrogateHalf byteIndex) ->
|
||||||
|
// if byteIndex == 2 then
|
||||||
|
// "a"
|
||||||
|
// else
|
||||||
|
// "b"
|
||||||
|
// _ -> ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// roc_std::RocStr::from_slice("a".as_bytes()),
|
||||||
|
// roc_std::RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_equality() {
|
||||||
|
// assert_evals_to!(r#""a" == "a""#, true, bool);
|
||||||
|
// assert_evals_to!(
|
||||||
|
// r#""loremipsumdolarsitamet" == "loremipsumdolarsitamet""#,
|
||||||
|
// true,
|
||||||
|
// bool
|
||||||
|
// );
|
||||||
|
// assert_evals_to!(r#""a" != "b""#, true, bool);
|
||||||
|
// assert_evals_to!(r#""a" == "b""#, false, bool);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_clone() {
|
||||||
|
// use roc_std::RocStr;
|
||||||
|
// let long = RocStr::from_slice("loremipsumdolarsitamet".as_bytes());
|
||||||
|
// let short = RocStr::from_slice("x".as_bytes());
|
||||||
|
// let empty = RocStr::from_slice("".as_bytes());
|
||||||
|
|
||||||
|
// debug_assert_eq!(long.clone(), long);
|
||||||
|
// debug_assert_eq!(short.clone(), short);
|
||||||
|
// debug_assert_eq!(empty.clone(), empty);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn nested_recursive_literal() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// Expr : [ Add Expr Expr, Val I64, Var I64 ]
|
||||||
|
|
||||||
|
// expr : Expr
|
||||||
|
// expr = Add (Add (Val 3) (Val 1)) (Add (Val 1) (Var 1))
|
||||||
|
|
||||||
|
// printExpr : Expr -> Str
|
||||||
|
// printExpr = \e ->
|
||||||
|
// when e is
|
||||||
|
// Add a b ->
|
||||||
|
// "Add ("
|
||||||
|
// |> Str.concat (printExpr a)
|
||||||
|
// |> Str.concat ") ("
|
||||||
|
// |> Str.concat (printExpr b)
|
||||||
|
// |> Str.concat ")"
|
||||||
|
// Val v -> "Val " |> Str.concat (Str.fromInt v)
|
||||||
|
// Var v -> "Var " |> Str.concat (Str.fromInt v)
|
||||||
|
|
||||||
|
// printExpr expr
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocStr::from_slice(b"Add (Add (Val 3) (Val 1)) (Add (Val 1) (Var 1))"),
|
||||||
|
// RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_join_comma_small() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// r#"Str.joinWith ["1", "2"] ", " "#,
|
||||||
|
// RocStr::from("1, 2"),
|
||||||
|
// RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_join_comma_big() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// r#"Str.joinWith ["10000000", "2000000", "30000000"] ", " "#,
|
||||||
|
// RocStr::from("10000000, 2000000, 30000000"),
|
||||||
|
// RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_join_comma_single() {
|
||||||
|
// assert_evals_to!(r#"Str.joinWith ["1"] ", " "#, RocStr::from("1"), RocStr);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_float() {
|
||||||
|
// assert_evals_to!(r#"Str.fromFloat 3.14"#, RocStr::from("3.14"), RocStr);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_to_utf8() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// r#"Str.toUtf8 "hello""#,
|
||||||
|
// RocList::from_slice(&[104, 101, 108, 108, 111]),
|
||||||
|
// RocList<u8>
|
||||||
|
// );
|
||||||
|
// assert_evals_to!(
|
||||||
|
// r#"Str.toUtf8 "this is a long string""#,
|
||||||
|
// RocList::from_slice(&[
|
||||||
|
// 116, 104, 105, 115, 32, 105, 115, 32, 97, 32, 108, 111, 110, 103, 32, 115, 116,
|
||||||
|
// 114, 105, 110, 103
|
||||||
|
// ]),
|
||||||
|
// RocList<u8>
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_range() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// bytes = Str.toUtf8 "hello"
|
||||||
|
// when Str.fromUtf8Range bytes { count: 5, start: 0 } is
|
||||||
|
// Ok utf8String -> utf8String
|
||||||
|
// _ -> ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocStr::from("hello"),
|
||||||
|
// RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_range_slice() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// bytes = Str.toUtf8 "hello"
|
||||||
|
// when Str.fromUtf8Range bytes { count: 4, start: 1 } is
|
||||||
|
// Ok utf8String -> utf8String
|
||||||
|
// _ -> ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocStr::from("ello"),
|
||||||
|
// RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_range_slice_not_end() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// bytes = Str.toUtf8 "hello"
|
||||||
|
// when Str.fromUtf8Range bytes { count: 3, start: 1 } is
|
||||||
|
// Ok utf8String -> utf8String
|
||||||
|
// _ -> ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocStr::from("ell"),
|
||||||
|
// RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_range_order_does_not_matter() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// bytes = Str.toUtf8 "hello"
|
||||||
|
// when Str.fromUtf8Range bytes { start: 1, count: 3 } is
|
||||||
|
// Ok utf8String -> utf8String
|
||||||
|
// _ -> ""
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocStr::from("ell"),
|
||||||
|
// RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_range_out_of_bounds_start_value() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// bytes = Str.toUtf8 "hello"
|
||||||
|
// when Str.fromUtf8Range bytes { start: 7, count: 3 } is
|
||||||
|
// Ok _ -> ""
|
||||||
|
// Err (BadUtf8 _ _) -> ""
|
||||||
|
// Err OutOfBounds -> "out of bounds"
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocStr::from("out of bounds"),
|
||||||
|
// RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_range_count_too_high() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// bytes = Str.toUtf8 "hello"
|
||||||
|
// when Str.fromUtf8Range bytes { start: 0, count: 6 } is
|
||||||
|
// Ok _ -> ""
|
||||||
|
// Err (BadUtf8 _ _) -> ""
|
||||||
|
// Err OutOfBounds -> "out of bounds"
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocStr::from("out of bounds"),
|
||||||
|
// RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn str_from_utf8_range_count_too_high_for_start() {
|
||||||
|
// assert_evals_to!(
|
||||||
|
// indoc!(
|
||||||
|
// r#"
|
||||||
|
// bytes = Str.toUtf8 "hello"
|
||||||
|
// when Str.fromUtf8Range bytes { start: 4, count: 3 } is
|
||||||
|
// Ok _ -> ""
|
||||||
|
// Err (BadUtf8 _ _) -> ""
|
||||||
|
// Err OutOfBounds -> "out of bounds"
|
||||||
|
// "#
|
||||||
|
// ),
|
||||||
|
// RocStr::from("out of bounds"),
|
||||||
|
// RocStr
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue