use crate::register_intrinsic;
use crate::types::{AggregateField, TypeId, TypeManager};
use crate::value::insn::Intrinsic;
struct Enumerate;
impl Intrinsic for Enumerate {
fn name(&self) -> &'static str {
"enumerate"
}
fn arity(&self) -> usize {
1
}
fn result_type(&self, types: &TypeManager, args: &[TypeId]) -> TypeId {
let (elem, len, is_list) = types
.seq_of(args[0])
.expect("enumerate operand must be a sequence (array or list)");
let i64_ty = types.get_int(8);
let fields = vec![
AggregateField::new("index", i64_ty),
AggregateField::new("elem", elem),
];
let tuple = types
.get_named_aggregate(&fields)
.expect("enumerate tuple type must be published");
types
.get_seq(tuple, len, is_list)
.expect("enumerate result sequence type must be published")
}
fn eval(&self, _args: &[(u128, usize)], _out_size: usize) -> Option<u128> {
None
}
}
register_intrinsic!(Enumerate);
#[cfg(test)]
mod tests {
use crate::types::{AggregateField, TypeRequest};
use crate::value::insn::IntrinsicId;
fn publish_result(
types: &mut crate::types::TypeManager,
elem: crate::types::TypeId,
len: usize,
is_list: bool,
) {
types.get_or_make_int(8);
let fields = vec![
AggregateField::new("index", types.get_int(8)),
AggregateField::new("elem", elem),
];
let tuple = types.create_requested_types(&[TypeRequest::aggregate(fields)])[0];
let request = if is_list {
TypeRequest::list(tuple, Some(len))
} else {
TypeRequest::array(tuple, len)
};
types.create_requested_types(&[request]);
}
#[test]
fn enumerate_registered_and_resolves() {
let id = IntrinsicId::from_name("enumerate").expect("enumerate registered");
assert_eq!(id.name(), "enumerate");
assert_eq!(id.desc().arity(), 1);
}
#[test]
fn enumerate_of_a_list_is_a_list_of_tuples() {
let mut types = crate::types::TypeManager::default();
let i8 = types.get_or_make_int(1);
let list = types.get_or_make_list(i8, 4);
publish_result(&mut types, i8, 4, true);
let id = IntrinsicId::from_name("enumerate").unwrap();
let result = id.desc().result_type(&types, &[list]);
assert_eq!(types.array_of(result), None);
let (tuple, bound) = types.list_of(result).expect("result is a list");
assert_eq!(bound, Some(4));
let fields = types.aggregate_fields(tuple).expect("element is a tuple");
assert_eq!(fields[1].type_id, i8);
}
#[test]
fn result_type_is_array_of_index_elem_tuples() {
let mut types = crate::types::TypeManager::default();
let i8 = types.get_or_make_int(1);
let arr = types.get_or_make_array(i8, 4);
publish_result(&mut types, i8, 4, false);
let id = IntrinsicId::from_name("enumerate").unwrap();
let result = id.desc().result_type(&types, &[arr]);
let (tuple, count) = types.array_of(result).expect("result is an array");
assert_eq!(count, 4);
let fields = types
.aggregate_fields(tuple)
.expect("element is an aggregate");
assert_eq!(fields.len(), 2);
assert_eq!(fields[0].name, "index");
assert_eq!(types.size_of(fields[0].type_id), 8);
assert_eq!(fields[1].name, "elem");
assert_eq!(fields[1].type_id, i8);
}
}