use super::*;
use crate::{
abi_stability::stable_abi_trait::get_type_layout, sabi_types::Constructor, std_types::RVec,
traits::IntoReprC,
};
use std::{
cmp::{Eq, PartialEq},
ops::Range,
};
#[cfg(test)]
mod tests;
#[repr(C)]
#[derive(Debug, Copy, Clone, StableAbi)]
#[sabi(unsafe_sabi_opaque_fields)]
pub struct TLFunctions {
functions: *const CompTLFunction,
field_fn_ranges: *const StartLen,
functions_len: u16,
field_fn_ranges_len: u16,
}
unsafe impl Sync for TLFunctions {}
unsafe impl Send for TLFunctions {}
impl TLFunctions {
pub const fn new(
functions: RSlice<'static, CompTLFunction>,
field_fn_ranges: RSlice<'static, StartLenRepr>,
) -> Self {
Self {
functions: functions.as_ptr(),
functions_len: functions.len() as u16,
field_fn_ranges: field_fn_ranges.as_ptr() as *const StartLenRepr as *const StartLen,
field_fn_ranges_len: field_fn_ranges.len() as u16,
}
}
fn functions(&self) -> &'static [CompTLFunction] {
unsafe { std::slice::from_raw_parts(self.functions, self.functions_len as usize) }
}
fn field_fn_ranges(&self) -> &'static [StartLen] {
unsafe {
std::slice::from_raw_parts(self.field_fn_ranges, self.field_fn_ranges_len as usize)
}
}
pub fn get(&'static self, nth: usize, shared_vars: &'static SharedVars) -> Option<TLFunction> {
let func = self.functions().get(nth)?;
Some(func.expand(shared_vars))
}
pub fn index(&'static self, nth: usize, shared_vars: &'static SharedVars) -> TLFunction {
self.functions()[nth].expand(shared_vars)
}
#[inline]
pub const fn len(&'static self) -> usize {
self.functions_len as usize
}
pub const fn is_empty(&'static self) -> bool {
self.functions_len == 0
}
}
#[repr(C)]
#[derive(Copy, Clone, StableAbi)]
#[sabi(unsafe_sabi_opaque_fields)]
pub struct TLFunctionSlice {
functions: Option<&'static TLFunctions>,
shared_vars: &'static SharedVars,
fn_range: StartLen,
}
impl TLFunctionSlice {
pub const fn empty(shared_vars: &'static SharedVars) -> Self {
Self {
functions: None,
shared_vars,
fn_range: StartLen::EMPTY,
}
}
pub fn for_field(
i: usize,
functions: Option<&'static TLFunctions>,
shared_vars: &'static SharedVars,
) -> Self {
let fn_range = functions
.and_then(|fns| fns.field_fn_ranges().get(i).cloned())
.unwrap_or(StartLen::EMPTY);
Self {
functions,
fn_range,
shared_vars,
}
}
pub const fn shared_vars(&self) -> &'static SharedVars {
self.shared_vars
}
#[inline]
pub fn iter(self) -> TLFunctionIter {
TLFunctionIter::new(self.fn_range, self.functions, self.shared_vars)
}
pub fn get(self, index: usize) -> Option<TLFunction> {
self.functions?
.get(self.fn_range.start_usize() + index, self.shared_vars)
}
pub fn index(self, index: usize) -> TLFunction {
self.functions
.expect("self.functions must be Some(..) to index a TLFunctionSlice")
.index(self.fn_range.start_usize() + index, self.shared_vars)
}
#[inline]
pub const fn len(self) -> usize {
self.fn_range.len_usize()
}
#[inline]
pub const fn is_empty(self) -> bool {
self.fn_range.len() == 0
}
}
impl IntoIterator for TLFunctionSlice {
type IntoIter = TLFunctionIter;
type Item = TLFunction;
#[inline]
fn into_iter(self) -> TLFunctionIter {
self.iter()
}
}
impl Debug for TLFunctionSlice {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl Eq for TLFunctionSlice {}
impl PartialEq for TLFunctionSlice {
fn eq(&self, other: &Self) -> bool {
self.fn_range.len() == other.fn_range.len() && self.iter().eq(other.iter())
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, StableAbi)]
pub struct TLFunctionQualifiers(u16);
impl TLFunctionQualifiers {
pub const NEW: Self = Self(0);
const UNSAFE_BIT: u16 = 1;
pub const fn is_unsafe(&self) -> bool {
(self.0 & Self::UNSAFE_BIT) != 0
}
pub const fn set_unsafe(mut self) -> Self {
self.0 |= Self::UNSAFE_BIT;
self
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, StableAbi)]
#[sabi(unsafe_sabi_opaque_fields)]
pub struct CompTLFunction {
name: StartLen,
contiguous_strings_offset: u16,
bound_lifetimes_len: u16,
param_names_len: u16,
return_type_layout: u16,
paramret_lifetime_range: LifetimeRange,
param_type_layouts: TypeLayoutRange,
fn_qualifs: TLFunctionQualifiers,
}
impl CompTLFunction {
#[allow(clippy::too_many_arguments)]
pub const fn new(
name: StartLenRepr,
contiguous_strings_offset: u16,
bound_lifetimes_len: u16,
param_names_len: u16,
return_type_layout: u16,
paramret_lifetime_range: u32,
param_type_layouts: u64,
fn_qualifs: TLFunctionQualifiers,
) -> Self {
Self {
name: StartLen::from_u32(name),
contiguous_strings_offset,
bound_lifetimes_len,
param_names_len,
return_type_layout,
paramret_lifetime_range: LifetimeRange::from_u21(paramret_lifetime_range),
param_type_layouts: TypeLayoutRange::from_u64(param_type_layouts),
fn_qualifs,
}
}
pub fn expand(&self, shared_vars: &'static SharedVars) -> TLFunction {
let strings = shared_vars.strings().into_c();
let lifetime_indices = shared_vars.lifetime_indices();
let type_layouts = shared_vars.type_layouts();
let cs_offset = self.contiguous_strings_offset as usize;
let bound_lifetimes = cs_offset..cs_offset + (self.bound_lifetimes_len as usize);
let param_names =
bound_lifetimes.end..bound_lifetimes.end + (self.param_names_len as usize);
TLFunction {
shared_vars: CmpIgnored::new(shared_vars),
name: strings.slice(self.name.to_range()),
bound_lifetimes: strings.slice(bound_lifetimes),
param_names: strings.slice(param_names),
param_type_layouts: self.param_type_layouts.expand(type_layouts),
paramret_lifetime_indices: self.paramret_lifetime_range.slicing(lifetime_indices),
return_type_layout: type_layouts
.get(self.return_type_layout as usize)
.map(|fnp| Constructor(*fnp)),
fn_qualifs: self.fn_qualifs,
}
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Eq, StableAbi)]
#[sabi(unsafe_sabi_opaque_fields)]
pub struct TLFunction {
pub(super) shared_vars: CmpIgnored<&'static SharedVars>,
pub name: RStr<'static>,
pub bound_lifetimes: RStr<'static>,
pub param_names: RStr<'static>,
pub param_type_layouts: MultipleTypeLayouts<'static>,
pub paramret_lifetime_indices: LifetimeArrayOrSlice<'static>,
return_type_layout: Option<Constructor<&'static TypeLayout>>,
pub fn_qualifs: TLFunctionQualifiers,
}
impl PartialEq for TLFunction {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
&& self.bound_lifetimes == other.bound_lifetimes
&& self.param_names == other.param_names
&& self.get_params_ret_iter().eq(other.get_params_ret_iter())
&& self.paramret_lifetime_indices == other.paramret_lifetime_indices
&& self.return_type_layout.map(|x| x.get()) == other.return_type_layout.map(|x| x.get())
&& self.fn_qualifs == other.fn_qualifs
}
}
impl TLFunction {
pub(crate) fn get_param_names(&self) -> GetParamNames {
GetParamNames {
split: self.param_names.as_str().split(';'),
length: self.param_type_layouts.len(),
current: 0,
}
}
pub(crate) fn get_params(&self) -> impl ExactSizeIterator<Item = TLField> + Clone + Debug {
let shared_vars = *self.shared_vars;
self.get_param_names()
.zip(self.param_type_layouts.iter())
.map(move |(param_name, layout)| TLField::new(param_name.into(), layout, shared_vars))
}
pub(crate) fn get_return(&self) -> TLField {
const UNIT_GET_ABI_INFO: extern "C" fn() -> &'static TypeLayout = get_type_layout::<()>;
TLField::new(
rstr!("__returns"),
match self.return_type_layout {
Some(Constructor(x)) => x,
None => UNIT_GET_ABI_INFO,
},
&self.shared_vars,
)
}
pub const fn return_type_layout(&self) -> Option<extern "C" fn() -> &'static TypeLayout> {
match self.return_type_layout {
Some(x) => Some(x.0),
None => None,
}
}
pub(crate) fn get_params_ret_iter(
&self,
) -> impl ExactSizeIterator<Item = TLField> + Clone + Debug {
ChainOnce::new(self.get_params(), self.get_return())
}
#[allow(dead_code)]
pub(crate) fn get_params_ret_vec(&self) -> RVec<TLField> {
self.get_params_ret_iter().collect()
}
pub(crate) const fn qualifiers(&self) -> TLFunctionQualifiers {
self.fn_qualifs
}
}
impl Display for TLFunction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.fn_qualifs.is_unsafe() {
f.write_str("unsafe ")?;
}
f.write_str("fn(")?;
let params = self.get_params();
let param_count = params.len();
for (param_i, param) in params.enumerate() {
Display::fmt(¶m.name(), f)?;
Display::fmt(&": ", f)?;
Display::fmt(¶m.full_type(), f)?;
if param_i + 1 != param_count {
Display::fmt(&", ", f)?;
}
}
write!(f, ")")?;
let returns = self.get_return();
Display::fmt(&"->", f)?;
Display::fmt(&returns.full_type(), f)?;
if !self.paramret_lifetime_indices.is_empty() {
writeln!(f, "\nlifetime indices:{:?}", self.paramret_lifetime_indices)?;
}
Ok(())
}
}
pub struct TLFunctionIter {
start: usize,
end: usize,
functions: Option<&'static TLFunctions>,
shared_vars: &'static SharedVars,
}
#[allow(clippy::missing_const_for_fn)]
impl TLFunctionIter {
fn new(
start_len: StartLen,
functions: Option<&'static TLFunctions>,
shared_vars: &'static SharedVars,
) -> Self {
let Range { start, end } = start_len.to_range();
if let Some(functions) = functions {
assert!(start <= functions.len(), "{} < {}", start, functions.len());
assert!(end <= functions.len(), "{} < {}", end, functions.len());
}
Self {
start,
end,
functions,
shared_vars,
}
}
fn length(&self) -> usize {
self.end - self.start
}
}
impl Iterator for TLFunctionIter {
type Item = TLFunction;
fn next(&mut self) -> Option<TLFunction> {
let functions = self.functions?;
if self.start >= self.end {
return None;
}
let ret = functions.index(self.start, self.shared_vars);
self.start += 1;
Some(ret)
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.length();
(len, Some(len))
}
fn count(self) -> usize {
self.length()
}
}
impl ExactSizeIterator for TLFunctionIter {}
#[derive(Debug, Clone)]
pub struct GetParamNames {
split: std::str::Split<'static, char>,
length: usize,
current: usize,
}
impl Iterator for GetParamNames {
type Item = &'static str;
fn next(&mut self) -> Option<Self::Item> {
if self.length == self.current {
return None;
}
let current = self.current;
self.current += 1;
match self.split.next().filter(|&x| !x.is_empty() || x == "_") {
Some(x) => Some(x),
None => Some(PARAM_INDEX[current]),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.length - self.current;
(len, Some(len))
}
fn count(self) -> usize {
self.length - self.current
}
}
impl std::iter::ExactSizeIterator for GetParamNames {}
static PARAM_INDEX: [&str; 64] = [
"param_0", "param_1", "param_2", "param_3", "param_4", "param_5", "param_6", "param_7",
"param_8", "param_9", "param_10", "param_11", "param_12", "param_13", "param_14", "param_15",
"param_16", "param_17", "param_18", "param_19", "param_20", "param_21", "param_22", "param_23",
"param_24", "param_25", "param_26", "param_27", "param_28", "param_29", "param_30", "param_31",
"param_32", "param_33", "param_34", "param_35", "param_36", "param_37", "param_38", "param_39",
"param_40", "param_41", "param_42", "param_43", "param_44", "param_45", "param_46", "param_47",
"param_48", "param_49", "param_50", "param_51", "param_52", "param_53", "param_54", "param_55",
"param_56", "param_57", "param_58", "param_59", "param_60", "param_61", "param_62", "param_63",
];