lean_sys/types/
mod.rs

1/*!
2Adapted from a file automatically generated by rust-bindgen 0.60.1 from `lean.h`.
3Comments adapted from `lean.h`.
4*/
5
6mod incomplete_array;
7use core::ffi::{c_char, c_int, c_uint, c_void};
8
9pub use incomplete_array::*;
10
11/**
12Lean object header.
13
14The reference counter `m_rc` field also encodes whether the object is single threaded (> 0), multi threaded (< 0), or
15reference counting is not needed (== 0). We don't use reference counting for objects stored in compact regions, or
16marked as persistent.
17
18For "small" objects stored in compact regions, the field `m_cs_sz` contains the object size. For "small" objects not
19stored in compact regions, we use the page information to retrieve its size.
20
21During deallocation and 64-bit machines, the fields `m_rc` and `m_cs_sz` store the next object in the deletion TODO list.
22These two fields together have 48-bits, and this is enough for modern computers.
23In 32-bit machines, the field `m_rc` is sufficient.
24
25The field `m_other` is used to store the number of fields in a constructor object and the element size in a scalar array.
26*/
27#[repr(C)]
28#[derive(Debug, Copy, Clone)]
29pub struct lean_object {
30    pub m_rc: c_int,
31    pub m_cs_sz: u16,
32    pub m_other: u8,
33    pub m_tag: u8,
34}
35
36/// Standard object argument
37pub type lean_obj_arg = *mut lean_object;
38/// Borrowed object argument
39pub type b_lean_obj_arg = *mut lean_object;
40/// Unique (aka non shared) object argument
41pub type u_lean_obj_arg = *mut lean_object;
42/// Standard object result
43pub type lean_obj_res = *mut lean_object;
44/// Borrowed object result
45pub type b_lean_obj_res = *mut lean_object;
46
47#[repr(C)]
48#[derive(Debug)]
49pub struct lean_ctor_object {
50    pub m_header: lean_object,
51    pub m_objs: IncompleteArrayField<*mut lean_object>,
52}
53
54/// Array arrays
55#[repr(C)]
56#[derive(Debug)]
57pub struct lean_array_object {
58    pub m_header: lean_object,
59    pub m_size: usize,
60    pub m_capacity: usize,
61    pub m_data: IncompleteArrayField<*mut lean_object>,
62}
63
64/// Scalar arrays
65#[repr(C)]
66#[derive(Debug)]
67pub struct lean_sarray_object {
68    pub m_header: lean_object,
69    pub m_size: usize,
70    pub m_capacity: usize,
71    pub m_data: IncompleteArrayField<u8>,
72}
73
74#[repr(C)]
75#[derive(Debug)]
76pub struct lean_string_object {
77    pub m_header: lean_object,
78    /// Byte length including `\0` terminator
79    pub m_size: usize,
80    pub m_capacity: usize,
81    /// UTF-8 length
82    pub m_length: usize,
83    pub m_data: IncompleteArrayField<c_char>,
84}
85
86#[repr(C)]
87#[derive(Debug)]
88pub struct lean_closure_object {
89    pub m_header: lean_object,
90    pub m_fun: *mut c_void,
91    /// Number of arguments expected by `m_fun`
92    pub m_arity: u16,
93    //TODO: already been fixed?
94    /// Number of arguments that have been already fixed
95    pub m_num_fixed: u16,
96    pub m_objs: IncompleteArrayField<*mut lean_object>,
97}
98
99#[repr(C)]
100#[derive(Debug, Copy, Clone)]
101pub struct lean_ref_object {
102    pub m_header: lean_object,
103    pub m_value: *mut lean_object,
104}
105
106#[repr(C)]
107#[derive(Debug, Copy, Clone)]
108pub struct lean_thunk_object {
109    pub m_header: lean_object,
110    pub m_value: u64,
111    pub m_closure: u64,
112}
113
114/** Data required for executing a Lean task. It is released as soon as
115the task terminates even if the task object itself is still referenced. */
116#[repr(C)]
117#[derive(Debug, Copy, Clone)]
118pub struct lean_task_imp {
119    pub m_closure: *mut lean_object,
120    pub m_head_dep: *mut lean_task_object,
121    pub m_next_dep: *mut lean_task_object,
122    pub m_prio: c_uint,
123    pub m_canceled: u8,
124    /// If true, task will not be freed until finished
125    pub m_keep_alive: u8,
126    pub m_deleted: u8,
127}
128
129/** Object of type `Task _`. The lifetime of a `lean_task` object can be represented as a state machine with atomic
130state transitions.
131
132In the following, `condition` describes a predicate uniquely identifying a state.
133
134creation:
135* Task.spawn ==> Queued
136* Task.map/bind ==> Waiting
137* Task.pure ==> Finished
138* Promise.new ==> Promised
139
140states:
141* Queued
142  * condition: in `task_manager::m_queues && m_imp != nullptr && !m_imp->m_deleted`
143  * invariant: `m_value == nullptr`
144  * transition: RC becomes 0 ==> Deactivated (`deactivate_task` lock)
145  * transition: dequeued by worker thread            ==> Running     (`spawn_worker` lock)
146* Waiting
147  * condition: reachable from task via `m_head_dep->m_next_dep->... && !m_imp->m_deleted`
148  * invariant: `m_imp != nullptr && m_value == nullptr`
149  * invariant: task dependency is Queued/Waiting/Running
150    * It cannot become Deactivated because this task should be holding an owned reference to it
151  * transition: RC becomes 0 ==> Deactivated (`deactivate_task` lock)
152  * transition: task dependency Finished ==> Queued (`handle_finished` under `spawn_worker` lock)
153* Promised
154  * condition: obtained as result from promise
155  * invariant: `m_imp != nullptr && m_value == nullptr`
156  * transition: promise resolved ==> Finished (`resolve_core` under `spawn_worker` lock)
157  * transition: RC becomes 0 ==> Deactivated (`deactivate_task` lock)
158* Running
159  * condition: `m_imp != nullptr && m_imp->m_closure == nullptr`
160    * The worker takes ownership of the closure when running it
161  * invariant: `m_value == nullptr`
162  * transition: RC becomes 0 ==> Deactivated (`deactivate_task` lock)
163  * transition: finished execution                   ==> Finished    (`spawn_worker` lock)
164* Deactivated
165  * condition: `m_imp != nullptr && m_imp->m_deleted`
166  * invariant: `RC == 0`
167  * invariant: `m_imp->m_closure == nullptr && m_imp->m_head_dep == nullptr` (both freed by `deactivate_task_core`)
168    * Note that all dependent tasks must have already been Deactivated by the converse of the second Waiting invariant
169  * invariant: `m_value == nullptr`
170  * transition: dequeued by worker thread   ==> freed
171  * transition: finished execution          ==> freed
172  * transition: task dependency Finished    ==> freed
173  * We must keep the task object alive until one of these transitions because in either case, we have live
174    (internal, unowned) references to the task up to that point
175  * transition: task dependency Deactivated ==> freed
176* Finished
177  * condition: `m_value != nullptr`
178  * invariant: `m_imp == nullptr`
179  * transition: RC becomes 0 ==> freed (`deactivate_task` lock)
180*/
181#[repr(C)]
182#[derive(Debug, Copy, Clone)]
183pub struct lean_task_object {
184    pub m_header: lean_object,
185    pub m_value: u64,
186    pub m_imp: *mut lean_task_imp,
187}
188
189#[repr(C)]
190#[derive(Debug, Copy, Clone)]
191pub struct lean_promise_object {
192    pub m_header: lean_object,
193    pub m_result: *mut lean_task_object,
194}
195
196pub type lean_external_finalize_proc = Option<unsafe extern "C" fn(arg1: *mut c_void)>;
197pub type lean_external_foreach_proc =
198    Option<unsafe extern "C" fn(arg1: *mut c_void, arg2: b_lean_obj_arg)>;
199
200/* Object for wrapping external data. */
201#[repr(C)]
202#[derive(Debug, Copy, Clone)]
203pub struct lean_external_class {
204    pub m_finalize: lean_external_finalize_proc,
205    pub m_foreach: lean_external_foreach_proc,
206}
207
208#[repr(C)]
209#[derive(Debug, Copy, Clone)]
210pub struct lean_external_object {
211    pub m_header: lean_object,
212    pub m_class: *mut lean_external_class,
213    pub m_data: *mut c_void,
214}