1use super::*;
2
3use crate::{
4 abi_stability::stable_abi_trait::get_type_layout, sabi_types::Constructor, std_types::RVec,
5 traits::IntoReprC,
6};
7
8use std::{
9 cmp::{Eq, PartialEq},
10 ops::Range,
11};
12
13#[cfg(test)]
16mod tests;
17
18#[repr(C)]
22#[derive(Debug, Copy, Clone, StableAbi)]
23#[sabi(unsafe_sabi_opaque_fields)]
24pub struct TLFunctions {
25 functions: *const CompTLFunction,
26 field_fn_ranges: *const StartLen,
28
29 functions_len: u16,
30 field_fn_ranges_len: u16,
31}
32
33unsafe impl Sync for TLFunctions {}
34unsafe impl Send for TLFunctions {}
35
36impl TLFunctions {
37 pub const fn new(
39 functions: RSlice<'static, CompTLFunction>,
40 field_fn_ranges: RSlice<'static, StartLenRepr>,
41 ) -> Self {
42 Self {
43 functions: functions.as_ptr(),
44 functions_len: functions.len() as u16,
45 field_fn_ranges: field_fn_ranges.as_ptr() as *const StartLenRepr as *const StartLen,
46 field_fn_ranges_len: field_fn_ranges.len() as u16,
47 }
48 }
49
50 fn functions(&self) -> &'static [CompTLFunction] {
51 unsafe { std::slice::from_raw_parts(self.functions, self.functions_len as usize) }
52 }
53
54 fn field_fn_ranges(&self) -> &'static [StartLen] {
55 unsafe {
56 std::slice::from_raw_parts(self.field_fn_ranges, self.field_fn_ranges_len as usize)
57 }
58 }
59
60 pub fn get(&'static self, nth: usize, shared_vars: &'static SharedVars) -> Option<TLFunction> {
63 let func = self.functions().get(nth)?;
64 Some(func.expand(shared_vars))
65 }
66
67 pub fn index(&'static self, nth: usize, shared_vars: &'static SharedVars) -> TLFunction {
74 self.functions()[nth].expand(shared_vars)
75 }
76
77 #[inline]
79 pub const fn len(&'static self) -> usize {
80 self.functions_len as usize
81 }
82
83 pub const fn is_empty(&'static self) -> bool {
85 self.functions_len == 0
86 }
87}
88
89#[repr(C)]
93#[derive(Copy, Clone, StableAbi)]
94#[sabi(unsafe_sabi_opaque_fields)]
95pub struct TLFunctionSlice {
96 functions: Option<&'static TLFunctions>,
97 shared_vars: &'static SharedVars,
98 fn_range: StartLen,
99}
100
101impl TLFunctionSlice {
102 pub const fn empty(shared_vars: &'static SharedVars) -> Self {
104 Self {
105 functions: None,
106 shared_vars,
107 fn_range: StartLen::EMPTY,
108 }
109 }
110
111 pub fn for_field(
113 i: usize,
114 functions: Option<&'static TLFunctions>,
115 shared_vars: &'static SharedVars,
116 ) -> Self {
117 let fn_range = functions
118 .and_then(|fns| fns.field_fn_ranges().get(i).cloned())
119 .unwrap_or(StartLen::EMPTY);
120
121 Self {
122 functions,
123 fn_range,
124 shared_vars,
125 }
126 }
127
128 pub const fn shared_vars(&self) -> &'static SharedVars {
130 self.shared_vars
131 }
132 #[inline]
134 pub fn iter(self) -> TLFunctionIter {
135 TLFunctionIter::new(self.fn_range, self.functions, self.shared_vars)
136 }
137
138 pub fn get(self, index: usize) -> Option<TLFunction> {
141 self.functions?
142 .get(self.fn_range.start_usize() + index, self.shared_vars)
143 }
144
145 pub fn index(self, index: usize) -> TLFunction {
151 self.functions
152 .expect("self.functions must be Some(..) to index a TLFunctionSlice")
153 .index(self.fn_range.start_usize() + index, self.shared_vars)
154 }
155
156 #[inline]
158 pub const fn len(self) -> usize {
159 self.fn_range.len_usize()
160 }
161 #[inline]
163 pub const fn is_empty(self) -> bool {
164 self.fn_range.len() == 0
165 }
166}
167
168impl IntoIterator for TLFunctionSlice {
169 type IntoIter = TLFunctionIter;
170 type Item = TLFunction;
171
172 #[inline]
173 fn into_iter(self) -> TLFunctionIter {
174 self.iter()
175 }
176}
177
178impl Debug for TLFunctionSlice {
179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 f.debug_list().entries(self.iter()).finish()
181 }
182}
183
184impl Eq for TLFunctionSlice {}
185
186impl PartialEq for TLFunctionSlice {
187 fn eq(&self, other: &Self) -> bool {
188 self.fn_range.len() == other.fn_range.len() && self.iter().eq(other.iter())
189 }
190}
191
192#[repr(transparent)]
201#[derive(Copy, Clone, Debug, PartialEq, Eq, StableAbi)]
202pub struct TLFunctionQualifiers(u16);
203
204impl TLFunctionQualifiers {
205 pub const NEW: Self = Self(0);
207
208 const UNSAFE_BIT: u16 = 1;
209
210 pub const fn is_unsafe(&self) -> bool {
212 (self.0 & Self::UNSAFE_BIT) != 0
213 }
214 pub const fn set_unsafe(mut self) -> Self {
216 self.0 |= Self::UNSAFE_BIT;
217 self
218 }
219}
220
221#[repr(C)]
226#[derive(Copy, Clone, Debug, PartialEq, Eq, StableAbi)]
227#[sabi(unsafe_sabi_opaque_fields)]
228pub struct CompTLFunction {
229 name: StartLen,
230 contiguous_strings_offset: u16,
231 bound_lifetimes_len: u16,
232 param_names_len: u16,
233 return_type_layout: u16,
235 paramret_lifetime_range: LifetimeRange,
236 param_type_layouts: TypeLayoutRange,
237 fn_qualifs: TLFunctionQualifiers,
238}
239
240impl CompTLFunction {
241 #[allow(clippy::too_many_arguments)]
243 pub const fn new(
244 name: StartLenRepr,
245 contiguous_strings_offset: u16,
246 bound_lifetimes_len: u16,
247 param_names_len: u16,
248 return_type_layout: u16,
249 paramret_lifetime_range: u32,
250 param_type_layouts: u64,
251 fn_qualifs: TLFunctionQualifiers,
252 ) -> Self {
253 Self {
254 name: StartLen::from_u32(name),
255 contiguous_strings_offset,
256 bound_lifetimes_len,
257 param_names_len,
258 return_type_layout,
259 paramret_lifetime_range: LifetimeRange::from_u21(paramret_lifetime_range),
260 param_type_layouts: TypeLayoutRange::from_u64(param_type_layouts),
261 fn_qualifs,
262 }
263 }
264
265 pub fn expand(&self, shared_vars: &'static SharedVars) -> TLFunction {
267 let strings = shared_vars.strings().into_c();
268 let lifetime_indices = shared_vars.lifetime_indices();
269 let type_layouts = shared_vars.type_layouts();
270
271 let cs_offset = self.contiguous_strings_offset as usize;
272
273 let bound_lifetimes = cs_offset..cs_offset + (self.bound_lifetimes_len as usize);
274 let param_names =
275 bound_lifetimes.end..bound_lifetimes.end + (self.param_names_len as usize);
276
277 TLFunction {
278 shared_vars: CmpIgnored::new(shared_vars),
279 name: strings.slice(self.name.to_range()),
280 bound_lifetimes: strings.slice(bound_lifetimes),
281 param_names: strings.slice(param_names),
282 param_type_layouts: self.param_type_layouts.expand(type_layouts),
283 paramret_lifetime_indices: self.paramret_lifetime_range.slicing(lifetime_indices),
284 return_type_layout: type_layouts
285 .get(self.return_type_layout as usize)
286 .map(|fnp| Constructor(*fnp)),
287 fn_qualifs: self.fn_qualifs,
288 }
289 }
290}
291
292#[repr(C)]
296#[derive(Copy, Clone, Debug, Eq, StableAbi)]
297#[sabi(unsafe_sabi_opaque_fields)]
298pub struct TLFunction {
299 pub(super) shared_vars: CmpIgnored<&'static SharedVars>,
300
301 pub name: RStr<'static>,
303
304 pub bound_lifetimes: RStr<'static>,
307
308 pub param_names: RStr<'static>,
310
311 pub param_type_layouts: MultipleTypeLayouts<'static>,
313 pub paramret_lifetime_indices: LifetimeArrayOrSlice<'static>,
315
316 return_type_layout: Option<Constructor<&'static TypeLayout>>,
318
319 pub fn_qualifs: TLFunctionQualifiers,
321}
322
323impl PartialEq for TLFunction {
324 fn eq(&self, other: &Self) -> bool {
325 self.name == other.name
326 && self.bound_lifetimes == other.bound_lifetimes
327 && self.param_names == other.param_names
328 && self.get_params_ret_iter().eq(other.get_params_ret_iter())
329 && self.paramret_lifetime_indices == other.paramret_lifetime_indices
330 && self.return_type_layout.map(|x| x.get()) == other.return_type_layout.map(|x| x.get())
331 && self.fn_qualifs == other.fn_qualifs
332 }
333}
334
335impl TLFunction {
336 pub(crate) fn get_param_names(&self) -> GetParamNames {
337 GetParamNames {
338 split: self.param_names.as_str().split(';'),
339 length: self.param_type_layouts.len(),
340 current: 0,
341 }
342 }
343
344 pub(crate) fn get_params(&self) -> impl ExactSizeIterator<Item = TLField> + Clone + Debug {
346 let shared_vars = *self.shared_vars;
347 self.get_param_names()
348 .zip(self.param_type_layouts.iter())
349 .map(move |(param_name, layout)| TLField::new(param_name.into(), layout, shared_vars))
350 }
351
352 pub(crate) fn get_return(&self) -> TLField {
353 const UNIT_GET_ABI_INFO: extern "C" fn() -> &'static TypeLayout = get_type_layout::<()>;
354
355 TLField::new(
356 rstr!("__returns"),
357 match self.return_type_layout {
358 Some(Constructor(x)) => x,
359 None => UNIT_GET_ABI_INFO,
360 },
361 &self.shared_vars,
362 )
363 }
364
365 pub const fn return_type_layout(&self) -> Option<extern "C" fn() -> &'static TypeLayout> {
367 match self.return_type_layout {
368 Some(x) => Some(x.0),
369 None => None,
370 }
371 }
372
373 pub(crate) fn get_params_ret_iter(
375 &self,
376 ) -> impl ExactSizeIterator<Item = TLField> + Clone + Debug {
377 ChainOnce::new(self.get_params(), self.get_return())
378 }
379
380 #[allow(dead_code)]
382 pub(crate) fn get_params_ret_vec(&self) -> RVec<TLField> {
383 self.get_params_ret_iter().collect()
384 }
385
386 pub(crate) const fn qualifiers(&self) -> TLFunctionQualifiers {
387 self.fn_qualifs
388 }
389}
390
391impl Display for TLFunction {
392 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
393 if self.fn_qualifs.is_unsafe() {
394 f.write_str("unsafe ")?;
395 }
396 f.write_str("fn(")?;
397 let params = self.get_params();
398 let param_count = params.len();
399 for (param_i, param) in params.enumerate() {
400 Display::fmt(¶m.name(), f)?;
401 Display::fmt(&": ", f)?;
402 Display::fmt(¶m.full_type(), f)?;
403 if param_i + 1 != param_count {
404 Display::fmt(&", ", f)?;
405 }
406 }
407 write!(f, ")")?;
408
409 let returns = self.get_return();
410 Display::fmt(&"->", f)?;
411 Display::fmt(&returns.full_type(), f)?;
412
413 if !self.paramret_lifetime_indices.is_empty() {
414 writeln!(f, "\nlifetime indices:{:?}", self.paramret_lifetime_indices)?;
415 }
416
417 Ok(())
418 }
419}
420
421pub struct TLFunctionIter {
425 start: usize,
426 end: usize,
427 functions: Option<&'static TLFunctions>,
428 shared_vars: &'static SharedVars,
429}
430
431#[allow(clippy::missing_const_for_fn)]
432impl TLFunctionIter {
433 fn new(
434 start_len: StartLen,
435 functions: Option<&'static TLFunctions>,
436 shared_vars: &'static SharedVars,
437 ) -> Self {
438 let Range { start, end } = start_len.to_range();
439 if let Some(functions) = functions {
440 assert!(start <= functions.len(), "{} < {}", start, functions.len());
441 assert!(end <= functions.len(), "{} < {}", end, functions.len());
442 }
443 Self {
444 start,
445 end,
446 functions,
447 shared_vars,
448 }
449 }
450 fn length(&self) -> usize {
451 self.end - self.start
452 }
453}
454
455impl Iterator for TLFunctionIter {
456 type Item = TLFunction;
457
458 fn next(&mut self) -> Option<TLFunction> {
459 let functions = self.functions?;
460 if self.start >= self.end {
461 return None;
462 }
463 let ret = functions.index(self.start, self.shared_vars);
464 self.start += 1;
465 Some(ret)
466 }
467
468 fn size_hint(&self) -> (usize, Option<usize>) {
469 let len = self.length();
470 (len, Some(len))
471 }
472
473 fn count(self) -> usize {
474 self.length()
475 }
476}
477
478impl ExactSizeIterator for TLFunctionIter {}
479
480#[derive(Debug, Clone)]
483pub struct GetParamNames {
484 split: std::str::Split<'static, char>,
485 length: usize,
486 current: usize,
487}
488
489impl Iterator for GetParamNames {
490 type Item = &'static str;
491 fn next(&mut self) -> Option<Self::Item> {
492 if self.length == self.current {
493 return None;
494 }
495 let current = self.current;
496 self.current += 1;
497 match self.split.next().filter(|&x| !x.is_empty() || x == "_") {
498 Some(x) => Some(x),
499 None => Some(PARAM_INDEX[current]),
500 }
501 }
502
503 fn size_hint(&self) -> (usize, Option<usize>) {
504 let len = self.length - self.current;
505 (len, Some(len))
506 }
507 fn count(self) -> usize {
508 self.length - self.current
509 }
510}
511
512impl std::iter::ExactSizeIterator for GetParamNames {}
513
514static PARAM_INDEX: [&str; 64] = [
515 "param_0", "param_1", "param_2", "param_3", "param_4", "param_5", "param_6", "param_7",
516 "param_8", "param_9", "param_10", "param_11", "param_12", "param_13", "param_14", "param_15",
517 "param_16", "param_17", "param_18", "param_19", "param_20", "param_21", "param_22", "param_23",
518 "param_24", "param_25", "param_26", "param_27", "param_28", "param_29", "param_30", "param_31",
519 "param_32", "param_33", "param_34", "param_35", "param_36", "param_37", "param_38", "param_39",
520 "param_40", "param_41", "param_42", "param_43", "param_44", "param_45", "param_46", "param_47",
521 "param_48", "param_49", "param_50", "param_51", "param_52", "param_53", "param_54", "param_55",
522 "param_56", "param_57", "param_58", "param_59", "param_60", "param_61", "param_62", "param_63",
523];