use std::vec::Vec as StdVec;
use abi::{Option, RString, Str, Vec, assert_ffi_safe};
pub mod abi;
mod data_type;
mod stub;
pub use data_type::DataType;
pub use stub::ToStub;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub type DocComments = &'static [&'static str];
#[repr(C)]
pub struct Description {
pub version: Str,
pub module: Module,
}
assert_ffi_safe!(Description, size = 96, align = 8);
impl Description {
#[must_use]
pub fn new(module: Module) -> Self {
Self {
version: VERSION.into(),
module,
}
}
}
#[repr(C)]
#[derive(Debug, PartialEq)]
pub struct DocBlock(pub Vec<Str>);
impl From<&'static [&'static str]> for DocBlock {
fn from(val: &'static [&'static str]) -> Self {
Self(
val.iter()
.map(|s| (*s).into())
.collect::<StdVec<_>>()
.into(),
)
}
}
#[repr(C)]
pub struct Module {
pub name: RString,
pub functions: Vec<Function>,
pub classes: Vec<Class>,
pub enums: Vec<Enum>,
pub constants: Vec<Constant>,
}
assert_ffi_safe!(Module, size = 80, align = 8);
#[repr(C)]
pub struct Function {
pub name: RString,
pub docs: DocBlock,
pub ret: Option<Retval>,
pub params: Vec<Parameter>,
}
assert_ffi_safe!(Function, size = 88, align = 8);
#[repr(C)]
#[derive(Debug, PartialEq)]
pub struct Parameter {
pub name: RString,
pub ty: Option<DataType>,
pub nullable: bool,
pub variadic: bool,
pub default: Option<RString>,
}
assert_ffi_safe!(Parameter, size = 80, align = 8);
#[repr(C)]
pub struct Class {
pub name: RString,
pub docs: DocBlock,
pub extends: Option<RString>,
pub implements: Vec<RString>,
pub properties: Vec<Property>,
pub methods: Vec<Method>,
pub constants: Vec<Constant>,
pub is_interface: bool,
}
assert_ffi_safe!(Class, size = 128, align = 8);
impl Class {
#[must_use]
pub fn closure() -> Self {
Self {
name: "RustClosure".into(),
docs: DocBlock(StdVec::new().into()),
extends: Option::None,
implements: StdVec::new().into(),
properties: StdVec::new().into(),
methods: vec![Method {
name: "__invoke".into(),
docs: DocBlock(StdVec::new().into()),
ty: MethodType::Member,
params: vec![Parameter {
name: "args".into(),
ty: Option::Some(DataType::Mixed),
nullable: false,
variadic: true,
default: Option::None,
}]
.into(),
retval: Option::Some(Retval {
ty: DataType::Mixed,
nullable: false,
}),
r#static: false,
visibility: Visibility::Public,
r#abstract: false,
}]
.into(),
constants: StdVec::new().into(),
is_interface: false,
}
}
}
#[repr(C)]
#[derive(Debug, PartialEq)]
pub struct Enum {
pub name: RString,
pub docs: DocBlock,
pub cases: Vec<EnumCase>,
pub backing_type: Option<RString>,
}
assert_ffi_safe!(Enum, size = 72, align = 8);
#[repr(C)]
#[derive(Debug, PartialEq)]
pub struct EnumCase {
pub name: RString,
pub docs: DocBlock,
pub value: Option<RString>,
}
assert_ffi_safe!(EnumCase, size = 56, align = 8);
#[repr(C)]
#[derive(Debug, PartialEq)]
pub struct Property {
pub name: RString,
pub docs: DocBlock,
pub ty: Option<DataType>,
pub vis: Visibility,
pub static_: bool,
pub nullable: bool,
pub readonly: bool,
pub default: Option<RString>,
}
assert_ffi_safe!(Property, size = 96, align = 8);
#[repr(C)]
#[derive(Debug, PartialEq)]
pub struct Method {
pub name: RString,
pub docs: DocBlock,
pub ty: MethodType,
pub params: Vec<Parameter>,
pub retval: Option<Retval>,
pub r#static: bool,
pub visibility: Visibility,
pub r#abstract: bool,
}
assert_ffi_safe!(Method, size = 112, align = 8);
#[repr(C)]
#[derive(Debug, PartialEq)]
pub struct Retval {
pub ty: DataType,
pub nullable: bool,
}
assert_ffi_safe!(Retval, size = 32, align = 8);
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum MethodType {
Member,
Static,
Constructor,
}
assert_ffi_safe!(MethodType, size = 4, align = 4);
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Visibility {
Private,
Protected,
Public,
}
assert_ffi_safe!(Visibility, size = 4, align = 4);
#[repr(C)]
pub struct Constant {
pub name: RString,
pub docs: DocBlock,
pub value: Option<RString>,
pub visibility: Visibility,
}
assert_ffi_safe!(Constant, size = 64, align = 8);
#[cfg(test)]
mod tests {
use super::*;
assert_ffi_safe!(DocBlock, size = 16, align = 8);
#[test]
fn description_carries_the_introspection_version() {
let module = Module {
name: "test".into(),
functions: vec![].into(),
classes: vec![].into(),
enums: vec![].into(),
constants: vec![].into(),
};
let description = Description::new(module);
assert_eq!(description.version.str(), VERSION);
assert_eq!(description.module.name, "test".into());
}
#[test]
fn doc_block_from_slice() {
let docs: &'static [&'static str] = &["doc1", "doc2"];
let docs: DocBlock = docs.into();
assert_eq!(docs.0.len(), 2);
assert_eq!(docs.0[0], "doc1".into());
assert_eq!(docs.0[1], "doc2".into());
}
#[test]
fn closure_class_is_not_an_interface() {
let class = Class::closure();
assert!(!class.is_interface);
assert_eq!(class.methods.len(), 1);
}
}