seq_runtime/closures/env.rs
1//! Closure environment construction and generic access.
2//!
3//! - `create_env` allocates a fixed-size `Vec<Value>` returned as a boxed slice
4//! pointer for LLVM codegen to populate.
5//! - `env_set` fills a slot; each slot is written exactly once before
6//! `make_closure` takes ownership.
7//! - `env_get` is the generic read path; type-specific readers live in
8//! `super::accessors`.
9
10use crate::value::Value;
11
12use super::MAX_CAPTURES;
13
14/// Create a closure environment (array of captured values)
15///
16/// Called from generated LLVM code to allocate space for captured values.
17/// Returns a raw pointer to a boxed slice that will be filled with values.
18///
19/// # Safety
20/// - Caller must populate the environment with `env_set` before using
21/// - Caller must eventually pass ownership to a Closure value (via `make_closure`)
22// Allow improper_ctypes_definitions: Called from LLVM IR (not C), both sides understand layout
23#[allow(improper_ctypes_definitions)]
24#[unsafe(no_mangle)]
25pub extern "C" fn patch_seq_create_env(size: i32) -> *mut [Value] {
26 if size < 0 {
27 panic!("create_env: size cannot be negative: {}", size);
28 }
29
30 let size_usize = size as usize;
31 if size_usize > MAX_CAPTURES {
32 panic!(
33 "create_env: size {} exceeds MAX_CAPTURES ({})",
34 size_usize, MAX_CAPTURES
35 );
36 }
37
38 let mut vec: Vec<Value> = Vec::with_capacity(size_usize);
39
40 // Fill with placeholder values (will be replaced by env_set)
41 for _ in 0..size {
42 vec.push(Value::Int(0));
43 }
44
45 Box::into_raw(vec.into_boxed_slice())
46}
47
48/// Set a value in the closure environment
49///
50/// Called from generated LLVM code to populate captured values.
51///
52/// # Safety
53/// - env must be a valid pointer from `create_env`
54/// - index must be in bounds [0, size)
55/// - env must not have been passed to `make_closure` yet
56// Allow improper_ctypes_definitions: Called from LLVM IR (not C), both sides understand layout
57#[allow(improper_ctypes_definitions)]
58#[unsafe(no_mangle)]
59pub unsafe extern "C" fn patch_seq_env_set(env: *mut [Value], index: i32, value: Value) {
60 if env.is_null() {
61 panic!("env_set: null environment pointer");
62 }
63
64 if index < 0 {
65 panic!("env_set: index cannot be negative: {}", index);
66 }
67
68 let env_slice = unsafe { &mut *env };
69 let idx = index as usize;
70
71 if idx >= env_slice.len() {
72 panic!(
73 "env_set: index {} out of bounds for environment of size {}",
74 index,
75 env_slice.len()
76 );
77 }
78
79 env_slice[idx] = value;
80}
81
82/// Get a value from the closure environment
83///
84/// Called from generated closure function code to access captured values.
85/// Takes environment as separate data pointer and length (since LLVM can't handle fat pointers).
86///
87/// # Safety
88/// - env_data must be a valid pointer to an array of Values
89/// - env_len must match the actual array length
90/// - index must be in bounds [0, env_len)
91// Allow improper_ctypes_definitions: Called from LLVM IR (not C), both sides understand layout
92#[allow(improper_ctypes_definitions)]
93#[unsafe(no_mangle)]
94pub unsafe extern "C" fn patch_seq_env_get(
95 env_data: *const Value,
96 env_len: usize,
97 index: i32,
98) -> Value {
99 if env_data.is_null() {
100 panic!("env_get: null environment pointer");
101 }
102
103 if index < 0 {
104 panic!("env_get: index cannot be negative: {}", index);
105 }
106
107 let idx = index as usize;
108
109 if idx >= env_len {
110 panic!(
111 "env_get: index {} out of bounds for environment of size {}",
112 index, env_len
113 );
114 }
115
116 // Clone the value from the environment
117 unsafe { (*env_data.add(idx)).clone() }
118}