1use std::slice;
4
5use nifty_runtime::Failure;
6
7use super::{borrow_context, count};
8use crate::context::Context;
9use crate::value::{self, Slot, TypeDesc};
10
11#[unsafe(no_mangle)]
16pub(crate) unsafe extern "C" fn nf_list_new(
17 ty: &'static TypeDesc,
18 items: *const Slot,
19 len: usize,
20) -> Slot {
21 let items = if len == 0 {
22 Vec::new()
23 } else {
24 unsafe { slice::from_raw_parts(items, len) }.to_vec()
26 };
27 value::list_slot(ty, items)
28}
29
30#[unsafe(no_mangle)]
32pub(crate) extern "C" fn nf_list_len(list: Slot) -> i64 {
33 count(value::as_list(list).items.len())
34}
35
36#[unsafe(no_mangle)]
41pub(crate) unsafe extern "C" fn nf_list_get(
42 context: *const Context,
43 list: Slot,
44 index: i64,
45 span: u32,
46 out: *mut Slot,
47) -> bool {
48 let context = unsafe { borrow_context(context) };
50 let items = &value::as_list(list).items;
51 match position(context, index, items.len(), span) {
52 Some(position) => {
53 unsafe { out.write(items[position]) };
55 true
56 }
57 None => false,
58 }
59}
60
61#[unsafe(no_mangle)]
66pub(crate) unsafe extern "C" fn nf_list_push(place: *mut Slot, item: Slot) {
67 value::list_mut(unsafe { &mut *place }).items.push(item);
69}
70
71#[unsafe(no_mangle)]
76pub(crate) unsafe extern "C" fn nf_list_remove(
77 context: *const Context,
78 place: *mut Slot,
79 index: i64,
80 span: u32,
81) -> bool {
82 let (context, place) = unsafe { (borrow_context(context), &mut *place) };
84 let len = value::as_list(*place).items.len();
85 let Some(position) = position(context, index, len, span) else {
86 return false;
87 };
88 let list = value::list_mut(place);
89 value::release(list.items.remove(position), list.element);
90 true
91}
92
93#[unsafe(no_mangle)]
100pub(crate) unsafe extern "C" fn nf_list_item_mut(
101 context: *const Context,
102 place: *mut Slot,
103 index: i64,
104 span: u32,
105 out: *mut *mut Slot,
106) -> bool {
107 let (context, place) = unsafe { (borrow_context(context), &mut *place) };
109 let len = value::as_list(*place).items.len();
110 let Some(position) = position(context, index, len, span) else {
111 return false;
112 };
113 let item = &raw mut value::list_mut(place).items[position];
114 unsafe { out.write(item) };
116 true
117}
118
119fn position(context: &Context, index: i64, len: usize, span: u32) -> Option<usize> {
122 let Ok(position) = usize::try_from(index) else {
123 context.fail(Failure::NegativePosition(index), span);
124 return None;
125 };
126 if position >= len {
127 context.fail(Failure::NoItem { position, len }, span);
128 return None;
129 }
130 Some(position)
131}