Merge branch 'trunk' into str-refcount

This commit is contained in:
Richard Feldman 2020-09-30 20:26:21 -04:00 committed by GitHub
commit cc0fd32f27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 526 additions and 132 deletions

8
Cargo.lock generated
View File

@ -2325,6 +2325,7 @@ dependencies = [
"roc_problem",
"roc_region",
"roc_solve",
"roc_std",
"roc_types",
"roc_unify",
"roc_uniq",
@ -2484,6 +2485,13 @@ dependencies = [
"roc_unify",
]
[[package]]
name = "roc_std"
version = "0.1.0"
dependencies = [
"libc",
]
[[package]]
name = "roc_types"
version = "0.1.0"

View File

@ -26,6 +26,7 @@ members = [
"vendor/pretty",
"editor",
"cli",
"roc_std",
"docs"
]

View File

@ -52,3 +52,4 @@ quickcheck_macros = "0.8"
tokio = { version = "0.2", features = ["blocking", "fs", "sync", "rt-threaded"] }
bumpalo = { version = "3.2", features = ["collections"] }
libc = "0.2"
roc_std = { path = "../../roc_std" }

View File

@ -1,25 +1,19 @@
use std::ffi::CString;
use std::os::raw::c_char;
use RocCallResult::*;
#[repr(C)]
union Payload<T: Copy> {
success: T,
failure: *mut c_char,
#[repr(u64)]
pub enum RocCallResult<T> {
Success(T),
Failure(*mut c_char),
}
#[repr(C)]
pub struct RocCallResult<T: Copy> {
pub flag: u64,
payload: Payload<T>,
}
impl<T: Copy> Into<Result<T, String>> for RocCallResult<T> {
impl<T: Sized> Into<Result<T, String>> for RocCallResult<T> {
fn into(self) -> Result<T, String> {
if self.flag == 0 {
Ok(unsafe { self.payload.success })
} else {
Err(unsafe {
let raw = CString::from_raw(self.payload.failure);
match self {
Success(value) => Ok(value),
Failure(failure) => Err({
let raw = unsafe { CString::from_raw(failure) };
let result = format!("{:?}", raw);
@ -27,7 +21,7 @@ impl<T: Copy> Into<Result<T, String>> for RocCallResult<T> {
std::mem::forget(raw);
result
})
}),
}
}
}

View File

@ -14,31 +14,148 @@ mod helpers;
#[cfg(test)]
mod gen_list {
use crate::helpers::with_larger_debug_stack;
//use roc_std::roclist;
use roc_std::RocList;
#[test]
fn roc_list_construction() {
let list = RocList::from_slice(&vec![1i64; 23]);
assert_eq!(&list, &list);
}
#[test]
fn empty_list_literal() {
assert_evals_to!("[]", &[], &'static [i64]);
assert_evals_to!("[]", RocList::from_slice(&[]), RocList<i64>);
}
#[test]
fn int_singleton_list_literal() {
assert_evals_to!("[1]", &[1], &'static [i64]);
assert_evals_to!("[1, 2]", RocList::from_slice(&[1, 2]), RocList<i64>);
}
#[test]
fn int_list_literal() {
assert_evals_to!("[ 12, 9, 6, 3 ]", &[12, 9, 6, 3], &'static [i64]);
assert_evals_to!("[ 12, 9 ]", RocList::from_slice(&[12, 9]), RocList<i64>);
assert_evals_to!(
"[ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ]",
RocList::from_slice(&(vec![1i64; 23])),
RocList<i64>
);
}
#[test]
fn bool_list_literal() {
// NOTE: make sure to explicitly declare the elements to be of type bool, or
// use both True and False; only using one of them causes the list to in practice be
// of type `List [ True ]` or `List [ False ]`, those are tag unions with one constructor
// and not fields, and don't have a runtime representation.
assert_evals_to!(
indoc!(
r#"
false : Bool
false = False
[ false ]
"#
),
RocList::from_slice(&(vec![false; 1])),
RocList<bool>
);
assert_evals_to!(
"[ True, False, True ]",
RocList::from_slice(&[true, false, true]),
RocList<bool>
);
assert_evals_to!(
indoc!(
r#"
false : Bool
false = False
[false ]
"#
),
RocList::from_slice(&(vec![false; 1])),
RocList<bool>
);
assert_evals_to!(
indoc!(
r#"
true : Bool
true = True
List.repeat 23 true
"#
),
RocList::from_slice(&(vec![true; 23])),
RocList<bool>
);
assert_evals_to!(
indoc!(
r#"
true : Bool
true = True
List.repeat 23 { x: true, y: true }
"#
),
RocList::from_slice(&(vec![[true, true]; 23])),
RocList<[bool; 2]>
);
assert_evals_to!(
indoc!(
r#"
true : Bool
true = True
List.repeat 23 { x: true, y: true, a: true, b: true, c: true, d : true, e: true, f: true }
"#
),
RocList::from_slice(&(vec![[true, true, true, true, true, true, true, true]; 23])),
RocList<[bool; 8]>
);
}
#[test]
fn variously_sized_list_literals() {
assert_evals_to!("[]", RocList::from_slice(&[]), RocList<i64>);
assert_evals_to!("[1]", RocList::from_slice(&[1]), RocList<i64>);
assert_evals_to!("[1, 2]", RocList::from_slice(&[1, 2]), RocList<i64>);
assert_evals_to!("[1, 2, 3]", RocList::from_slice(&[1, 2, 3]), RocList<i64>);
assert_evals_to!(
"[1, 2, 3, 4]",
RocList::from_slice(&[1, 2, 3, 4]),
RocList<i64>
);
assert_evals_to!(
"[1, 2, 3, 4, 5]",
RocList::from_slice(&[1, 2, 3, 4, 5]),
RocList<i64>
);
}
#[test]
fn list_append() {
assert_evals_to!("List.append [1] 2", &[1, 2], &'static [i64]);
assert_evals_to!("List.append [1, 1] 2", &[1, 1, 2], &'static [i64]);
assert_evals_to!(
"List.append [1] 2",
RocList::from_slice(&[1, 2]),
RocList<i64>
);
assert_evals_to!(
"List.append [1, 1] 2",
RocList::from_slice(&[1, 1, 2]),
RocList<i64>
);
}
#[test]
fn list_append_to_empty_list() {
assert_evals_to!("List.append [] 3", &[3], &'static [i64]);
assert_evals_to!("List.append [] 3", RocList::from_slice(&[3]), RocList<i64>);
}
#[test]
@ -53,8 +170,8 @@ mod gen_list {
List.append (List.append initThrees 3) 3
"#
),
&[3, 3],
&'static [i64]
RocList::from_slice(&[3, 3]),
RocList<i64>
);
}
@ -62,8 +179,8 @@ mod gen_list {
fn list_append_bools() {
assert_evals_to!(
"List.append [ True, False ] True",
&[true, false, true],
&'static [bool]
RocList::from_slice(&[true, false, true]),
RocList<bool>
);
}
@ -71,15 +188,19 @@ mod gen_list {
fn list_append_longer_list() {
assert_evals_to!(
"List.append [ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 ] 23",
&[11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23],
&'static [i64]
RocList::from_slice(&[11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]),
RocList<i64>
);
}
#[test]
fn list_prepend() {
assert_evals_to!("List.prepend [] 1", &[1], &'static [i64]);
assert_evals_to!("List.prepend [2] 1", &[1, 2], &'static [i64]);
assert_evals_to!("List.prepend [] 1", RocList::from_slice(&[1]), RocList<i64>);
assert_evals_to!(
"List.prepend [2] 1",
RocList::from_slice(&[1, 2]),
RocList<i64>
);
assert_evals_to!(
indoc!(
@ -91,8 +212,8 @@ mod gen_list {
List.prepend (List.prepend init 4) 6
"#
),
&[6, 4],
&'static [i64]
RocList::from_slice(&[6, 4]),
RocList<i64>
);
}
@ -100,8 +221,8 @@ mod gen_list {
fn list_prepend_bools() {
assert_evals_to!(
"List.prepend [ True, False ] True",
&[true, true, false],
&'static [bool]
RocList::from_slice(&[true, true, false]),
RocList<bool>
);
}
@ -109,8 +230,10 @@ mod gen_list {
fn list_prepend_big_list() {
assert_evals_to!(
"List.prepend [ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 100, 100, 100, 100 ] 9",
&[9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 100, 100, 100, 100],
&'static [i64]
RocList::from_slice(&[
9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 100, 100, 100, 100
]),
RocList<i64>
);
}
@ -153,8 +276,8 @@ mod gen_list {
List.keepIf empty (\x -> True)
"#
),
&[],
&'static [i64]
RocList::from_slice(&[]),
RocList<i64>
);
}
@ -171,8 +294,8 @@ mod gen_list {
List.keepIf [] alwaysTrue
"#
),
&[],
&'static [i64]
RocList::from_slice(&[]),
RocList<i64>
);
}
@ -192,8 +315,8 @@ mod gen_list {
List.keepIf oneThroughEight alwaysTrue
"#
),
&[1, 2, 3, 4, 5, 6, 7, 8],
&'static [i64]
RocList::from_slice(&[1, 2, 3, 4, 5, 6, 7, 8]),
RocList<i64>
);
}
@ -209,8 +332,8 @@ mod gen_list {
List.keepIf [1,2,3,4,5,6,7,8] alwaysFalse
"#
),
&[],
&'static [i64]
RocList::from_slice(&[]),
RocList<i64>
);
}
@ -226,8 +349,8 @@ mod gen_list {
List.keepIf [1,2,3,4,5,6,7,8] intIsLessThanThree
"#
),
&[1, 2],
&'static [i64]
RocList::from_slice(&[1, 2]),
RocList<i64>
);
}
@ -246,8 +369,8 @@ mod gen_list {
// List.keepIf ["Hello", "Hello", "Goodbye"] strIsHello
// "#
// ),
// &["Hello", "Hello"],
// &'static [&'static str]
// RocList::from_slice(&["Hello", "Hello"]),
// RocList<&'static str>
// );
// }
@ -263,8 +386,8 @@ mod gen_list {
List.map empty (\x -> x)
"#
),
&[],
&'static [i64]
RocList::from_slice(&[]),
RocList<i64>
);
}
@ -280,8 +403,8 @@ mod gen_list {
List.map nonEmpty (\x -> x)
"#
),
&[1],
&'static [i64]
RocList::from_slice(&[1]),
RocList<i64>
);
}
@ -297,8 +420,8 @@ mod gen_list {
List.map nonEmpty (\x -> x + 1)
"#
),
&[2],
&'static [i64]
RocList::from_slice(&[2]),
RocList<i64>
);
}
@ -314,8 +437,10 @@ mod gen_list {
List.map nonEmpty (\x -> x * 2)
"#
),
&[2, 4, 6, 8, 10, 2, 4, 6, 8, 10, 2, 4, 6, 8, 10, 2, 4, 6, 8, 10, 2, 4, 6, 8, 10],
&'static [i64]
RocList::from_slice(&[
2, 4, 6, 8, 10, 2, 4, 6, 8, 10, 2, 4, 6, 8, 10, 2, 4, 6, 8, 10, 2, 4, 6, 8, 10
]),
RocList<i64>
);
}
@ -332,8 +457,8 @@ mod gen_list {
List.map nonEmpty (\x -> x > 0)
"#
),
&[true, true, false, true, true],
&'static [bool]
RocList::from_slice(&[true, true, false, true, true]),
RocList<bool>
);
}
@ -353,8 +478,8 @@ mod gen_list {
List.map nonEmpty greaterThanOne
"#
),
&[true, true, false, true, true],
&'static [bool]
RocList::from_slice(&[true, true, false, true, true]),
RocList<bool>
);
}
@ -366,27 +491,31 @@ mod gen_list {
List.map [] (\x -> x > 0)
"#
),
&[],
&'static [bool]
RocList::from_slice(&[]),
RocList<bool>
);
}
#[test]
fn list_join_empty_list() {
assert_evals_to!("List.join []", &[], &'static [i64]);
assert_evals_to!("List.join []", RocList::from_slice(&[]), RocList<i64>);
}
#[test]
fn list_join_one_list() {
assert_evals_to!("List.join [ [1, 2, 3 ] ]", &[1, 2, 3], &'static [i64]);
assert_evals_to!(
"List.join [ [1, 2, 3 ] ]",
RocList::from_slice(&[1, 2, 3]),
RocList<i64>
);
}
#[test]
fn list_join_two_non_empty_lists() {
assert_evals_to!(
"List.join [ [1, 2, 3 ] , [4 ,5, 6] ]",
&[1, 2, 3, 4, 5, 6],
&'static [i64]
RocList::from_slice(&[1, 2, 3, 4, 5, 6]),
RocList<i64>
);
}
@ -394,8 +523,8 @@ mod gen_list {
fn list_join_two_non_empty_lists_of_float() {
assert_evals_to!(
"List.join [ [ 1.2, 1.1 ], [ 2.1, 2.2 ] ]",
&[1.2, 1.1, 2.1, 2.2],
&'static [f64]
RocList::from_slice(&[1.2, 1.1, 2.1, 2.2]),
RocList<f64>
);
}
@ -416,11 +545,11 @@ mod gen_list {
]
"#
),
&[
RocList::from_slice(&[
1.2, 1.1, 2.1, 2.2, 3.0, 4.0, 5.0, 6.1, 9.0, 3.0, 4.0, 5.0, 6.1, 9.0, 3.0, 4.0,
5.0, 6.1, 9.0, 3.0, 4.0, 5.0, 6.1, 9.0, 3.0, 4.0, 5.0, 6.1, 9.0
],
&'static [f64]
]),
RocList<f64>
);
}
@ -436,35 +565,47 @@ mod gen_list {
List.join [ [ 0.2, 11.11 ], empty ]
"#
),
&[0.2, 11.11],
&'static [f64]
RocList::from_slice(&[0.2, 11.11]),
RocList<f64>
);
}
#[test]
fn list_join_all_empty_lists() {
assert_evals_to!("List.join [ [], [], [] ]", &[], &'static [f64]);
assert_evals_to!(
"List.join [ [], [], [] ]",
RocList::from_slice(&[]),
RocList<f64>
);
}
#[test]
fn list_join_one_empty_list() {
assert_evals_to!(
"List.join [ [ 1.2, 1.1 ], [] ]",
&[1.2, 1.1],
&'static [f64]
RocList::from_slice(&[1.2, 1.1]),
RocList<f64>
);
}
#[test]
fn list_single() {
assert_evals_to!("List.single 1", &[1], &'static [i64]);
assert_evals_to!("List.single 5.6", &[5.6], &'static [f64]);
assert_evals_to!("List.single 1", RocList::from_slice(&[1]), RocList<i64>);
assert_evals_to!("List.single 5.6", RocList::from_slice(&[5.6]), RocList<f64>);
}
#[test]
fn list_repeat() {
assert_evals_to!("List.repeat 5 1", &[1, 1, 1, 1, 1], &'static [i64]);
assert_evals_to!("List.repeat 4 2", &[2, 2, 2, 2], &'static [i64]);
assert_evals_to!(
"List.repeat 5 1",
RocList::from_slice(&[1, 1, 1, 1, 1]),
RocList<i64>
);
assert_evals_to!(
"List.repeat 4 2",
RocList::from_slice(&[2, 2, 2, 2]),
RocList<i64>
);
assert_evals_to!("List.repeat 2 []", &[&[], &[]], &'static [&'static [i64]]);
assert_evals_to!(
@ -483,8 +624,8 @@ mod gen_list {
assert_evals_to!(
"List.repeat 15 4",
&[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
&'static [i64]
RocList::from_slice(&[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]),
RocList<i64>
);
}
@ -492,11 +633,15 @@ mod gen_list {
fn list_reverse() {
assert_evals_to!(
"List.reverse [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ]",
&[12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1],
&'static [i64]
RocList::from_slice(&[12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]),
RocList<i64>
);
assert_evals_to!("List.reverse [1, 2, 3]", &[3, 2, 1], &'static [i64]);
assert_evals_to!("List.reverse [4]", &[4], &'static [i64]);
assert_evals_to!(
"List.reverse [1, 2, 3]",
RocList::from_slice(&[3, 2, 1]),
RocList<i64>
);
assert_evals_to!("List.reverse [4]", RocList::from_slice(&[4]), RocList<i64>);
}
#[test]
@ -511,14 +656,14 @@ mod gen_list {
List.reverse emptyList
"#
),
&[],
&'static [i64]
RocList::from_slice(&[]),
RocList<i64>
);
}
#[test]
fn list_reverse_empty_list() {
assert_evals_to!("List.reverse []", &[], &'static [i64]);
assert_evals_to!("List.reverse []", RocList::from_slice(&[]), RocList<i64>);
}
#[test]
@ -537,14 +682,14 @@ mod gen_list {
List.concat firstList secondList
"#
),
&[],
&'static [i64]
RocList::from_slice(&[]),
RocList<i64>
);
}
#[test]
fn list_concat_two_empty_lists() {
assert_evals_to!("List.concat [] []", &[], &'static [i64]);
assert_evals_to!("List.concat [] []", RocList::from_slice(&[]), RocList<i64>);
}
#[test]
@ -563,32 +708,40 @@ mod gen_list {
List.concat firstList secondList
"#
),
&[],
&'static [i64]
RocList::from_slice(&[]),
RocList<i64>
);
}
#[test]
fn list_concat_second_list_is_empty() {
assert_evals_to!("List.concat [ 12, 13 ] []", &[12, 13], &'static [i64]);
assert_evals_to!(
"List.concat [ 12, 13 ] []",
RocList::from_slice(&[12, 13]),
RocList<i64>
);
assert_evals_to!(
"List.concat [ 34, 43 ] [ 64, 55, 66 ]",
&[34, 43, 64, 55, 66],
&'static [i64]
RocList::from_slice(&[34, 43, 64, 55, 66]),
RocList<i64>
);
}
#[test]
fn list_concat_first_list_is_empty() {
assert_evals_to!("List.concat [] [ 23, 24 ]", &[23, 24], &'static [i64]);
assert_evals_to!(
"List.concat [] [ 23, 24 ]",
RocList::from_slice(&[23, 24]),
RocList<i64>
);
}
#[test]
fn list_concat_two_non_empty_lists() {
assert_evals_to!(
"List.concat [1, 2 ] [ 3, 4 ]",
&[1, 2, 3, 4],
&'static [i64]
RocList::from_slice(&[1, 2, 3, 4]),
RocList<i64>
);
}
@ -596,8 +749,8 @@ mod gen_list {
fn list_concat_two_bigger_non_empty_lists() {
assert_evals_to!(
"List.concat [ 1.1, 2.2 ] [ 3.3, 4.4, 5.5 ]",
&[1.1, 2.2, 3.3, 4.4, 5.5],
&'static [f64]
RocList::from_slice(&[1.1, 2.2, 3.3, 4.4, 5.5]),
RocList<f64>
);
}
@ -614,12 +767,10 @@ mod gen_list {
expected.extend(vec2);
let expected_slice: &[i64] = expected.as_ref();
assert_evals_to!(
&format!("List.concat {} {}", slice_str1, slice_str2),
expected_slice,
&'static [i64]
RocList::from_slice(&expected),
RocList<i64>
);
}
@ -849,8 +1000,8 @@ mod gen_list {
fn set_unique_int_list() {
assert_evals_to!(
"List.set [ 12, 9, 7, 1, 5 ] 2 33",
&[12, 9, 33, 1, 5],
&'static [i64]
RocList::from_slice(&[12, 9, 33, 1, 5]),
RocList<i64>
);
}
@ -858,8 +1009,8 @@ mod gen_list {
fn set_unique_list_oob() {
assert_evals_to!(
"List.set [ 3, 17, 4.1 ] 1337 9.25",
&[3.0, 17.0, 4.1],
&'static [f64]
RocList::from_slice(&[3.0, 17.0, 4.1]),
RocList<f64>
);
}
@ -948,8 +1099,8 @@ mod gen_list {
wrapLen [ 1, 7, 9 ]
"#
),
&[3],
&'static [i64]
RocList::from_slice(&[3]),
RocList<i64>
);
}
@ -964,6 +1115,8 @@ mod gen_list {
wrapFirst [ 1, 2 ]
"#
),
// RocList::from_slice(&[1]),
// RocList<i64>
&[1],
&'static [i64]
);
@ -986,8 +1139,8 @@ mod gen_list {
dupe [ 1, 2 ]
"#
),
&[1, 1],
&'static [i64]
RocList::from_slice(&[1, 1]),
RocList<i64>
);
}
@ -1009,8 +1162,8 @@ mod gen_list {
swap 0 1 [ 1, 2 ]
"#
),
&[2, 1],
&'static [i64]
RocList::from_slice(&[2, 1]),
RocList<i64>
);
}
@ -1061,8 +1214,8 @@ mod gen_list {
// [ 1,3 ]
// "#
// ),
// &[2, 1],
// &'static [i64]
// RocList::from_slice(&[2, 1]),
// RocList<i64>
// );
// }
@ -1100,8 +1253,8 @@ mod gen_list {
// [ 1,3 ]
// "#
// ),
// &[2, 1],
// &'static [i64]
// RocList::from_slice(&[2, 1]),
// RocList<i64>
// );
// }
@ -1170,8 +1323,8 @@ mod gen_list {
quicksort [ 7, 4, 21, 19 ]
"#
),
&[4, 7, 19, 21],
&'static [i64]
RocList::from_slice(&[4, 7, 19, 21]),
RocList<i64>
);
})
}
@ -1243,8 +1396,8 @@ mod gen_list {
quicksort [ 7, 4, 21, 19 ]
"#
),
&[19, 7, 4, 21],
&'static [i64]
RocList::from_slice(&[19, 7, 4, 21]),
RocList<i64>
);
})
}
@ -1368,8 +1521,8 @@ mod gen_list {
id x
"#
),
&[1, 2, 3],
&'static [i64]
RocList::from_slice(&[1, 2, 3]),
RocList<i64>
);
}
@ -1387,8 +1540,8 @@ mod gen_list {
id x
"#
),
&[0, 2, 3],
&'static [i64]
RocList::from_slice(&[0, 2, 3]),
RocList<i64>
);
}
@ -1404,8 +1557,8 @@ mod gen_list {
Pair v _ -> v
"#
),
&[1, 2, 3],
&'static [i64]
RocList::from_slice(&[1, 2, 3]),
RocList<i64>
);
}
}

View File

@ -396,7 +396,11 @@ macro_rules! assert_llvm_evals_to {
let (main_fn_name, errors, execution_engine) =
$crate::helpers::eval::helper_without_uniqueness(&arena, $src, $leak, &context);
let transform = |success| assert_eq!($transform(success), $expected);
let transform = |success| {
let expected = $expected;
let given = $transform(success);
assert_eq!(&given, &expected);
};
run_jit_function!(execution_engine, main_fn_name, $ty, transform, errors)
};

12
roc_std/Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "roc_std"
version = "0.1.0"
authors = ["Richard Feldman <oss@rtfeldman.com>"]
repository = "https://github.com/rtfeldman/roc"
readme = "README.md"
edition = "2018"
description = "Rust representations of Roc data structures"
license = "Apache-2.0"
[dependencies]
libc = "0.2"

221
roc_std/src/lib.rs Normal file
View File

@ -0,0 +1,221 @@
#![crate_type = "lib"]
#![no_std]
use core::fmt;
// A list of C functions that are being imported
extern "C" {
pub fn printf(format: *const u8, ...) -> i32;
}
const REFCOUNT_1: usize = isize::MIN as usize;
//#[macro_export]
//macro_rules! roclist {
// () => (
// $crate::RocList::empty()
// );
// ($($x:expr),+ $(,)?) => (
// $crate::RocList::from_slice(&[$($x),+])
// );
//}
#[repr(C)]
pub struct RocList<T> {
elements: *mut T,
length: usize,
}
#[derive(Clone, Copy, Debug)]
pub enum Storage {
ReadOnly,
Refcounted(usize),
Capacity(usize),
}
impl<T> RocList<T> {
pub fn len(&self) -> usize {
self.length
}
pub fn is_empty(&self) -> bool {
self.length == 0
}
pub fn empty() -> Self {
RocList {
length: 0,
elements: core::ptr::null_mut(),
}
}
pub fn get(&self, index: usize) -> Option<&T> {
if index < self.len() {
Some(unsafe {
let raw = self.elements.add(index);
&*raw
})
} else {
None
}
}
pub fn storage(&self) -> Option<Storage> {
use core::cmp::Ordering::*;
if self.length == 0 {
return None;
}
unsafe {
let value = *self.get_storage_ptr();
// NOTE doesn't work with elements of 16 or more bytes
match usize::cmp(&0, &value) {
Equal => Some(Storage::ReadOnly),
Less => Some(Storage::Refcounted(value)),
Greater => Some(Storage::Capacity(value)),
}
}
}
fn get_storage_ptr(&self) -> *const usize {
let elem_alignment = core::mem::align_of::<T>();
unsafe {
if elem_alignment <= core::mem::align_of::<usize>() {
let ptr = self.elements as *const usize;
ptr.offset(-1)
} else {
let ptr = self.elements as *const (usize, usize);
(ptr.offset(-1)) as *const usize
}
}
}
fn get_storage_ptr_mut(&mut self) -> *mut usize {
self.get_storage_ptr() as *mut usize
}
fn get_element_ptr<Q>(elements: *const Q) -> *const usize {
let elem_alignment = core::mem::align_of::<T>();
unsafe {
if elem_alignment <= core::mem::align_of::<usize>() {
let ptr = elements as *const usize;
ptr.offset(1)
} else {
let ptr = elements as *const (usize, usize);
(ptr.offset(1)) as *const usize
}
}
}
pub fn from_slice_with_capacity(slice: &[T], capacity: usize) -> RocList<T>
where
T: Copy,
{
assert!(slice.len() <= capacity);
let ptr = slice.as_ptr();
let element_bytes = capacity * core::mem::size_of::<T>();
let padding = {
if core::mem::align_of::<T>() <= core::mem::align_of::<usize>() {
// aligned on usize (8 bytes on 64-bit systems)
0
} else {
// aligned on 2*usize (16 bytes on 64-bit systems)
core::mem::size_of::<usize>()
}
};
let num_bytes = core::mem::size_of::<usize>() + padding + element_bytes;
let elements = unsafe {
let raw_ptr = libc::malloc(num_bytes);
// write the capacity
let capacity_ptr = raw_ptr as *mut usize;
*capacity_ptr = capacity;
let raw_ptr = Self::get_element_ptr(raw_ptr as *mut T);
{
// NOTE: using a memcpy here causes weird issues
let target_ptr = raw_ptr as *mut T;
let source_ptr = ptr as *const T;
let length = slice.len() as isize;
for index in 0..length {
*target_ptr.offset(index) = *source_ptr.offset(index);
}
}
raw_ptr as *mut T
};
RocList {
length: slice.len(),
elements,
}
}
pub fn from_slice(slice: &[T]) -> RocList<T>
where
T: Copy,
{
Self::from_slice_with_capacity(slice, slice.len())
}
pub fn as_slice(&self) -> &[T] {
unsafe { core::slice::from_raw_parts(self.elements, self.length) }
}
}
impl<T: fmt::Debug> fmt::Debug for RocList<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// RocList { storage: Refcounted(3), elements: [ 1,2,3,4] }
f.debug_struct("RocList")
.field("storage", &self.storage())
.field("elements", &self.as_slice())
.finish()
}
}
impl<T: PartialEq> PartialEq for RocList<T> {
fn eq(&self, other: &Self) -> bool {
if self.length != other.length {
return false;
}
for i in 0..(self.length as isize) {
unsafe {
if *self.elements.offset(i) != *other.elements.offset(i) {
return false;
}
}
}
true
}
}
impl<T: Eq> Eq for RocList<T> {}
impl<T> Drop for RocList<T> {
fn drop(&mut self) {
use Storage::*;
match self.storage() {
None | Some(ReadOnly) => {}
Some(Capacity(_)) | Some(Refcounted(REFCOUNT_1)) => unsafe {
libc::free(self.get_storage_ptr() as *mut libc::c_void);
},
Some(Refcounted(rc)) => {
let sptr = self.get_storage_ptr_mut();
unsafe {
*sptr = rc - 1;
}
}
}
}
}