use std::any::TypeId;
use crate::value::TypeDescription;
use crate::{
Location, Value,
ast::Identifier,
runtime::{
CloneDrop, ConstantValue, Movability, RegistrationError, Rt,
extern_clone, extern_drop,
func::{FunctionDescription, RegisterableFn},
layout::Layout,
},
};
#[derive(Clone, Debug)]
pub enum Item {
Function(Function),
Type(Type),
Module(Module),
Constant(Constant),
Impl(Impl),
Use(Use),
}
pub trait Registerable: Sized {
fn into_lib(self) -> Library {
let mut lib = Library::new();
self.add_to_lib(&mut lib);
lib
}
fn add_to_lib(self, lib: &mut Library);
}
#[derive(Clone, Debug)]
pub struct Library {
pub(crate) items: Vec<Item>,
}
impl Default for Library {
fn default() -> Self {
Self::new()
}
}
impl Library {
pub fn new() -> Self {
Self { items: Vec::new() }
}
pub fn add(&mut self, item: Item) {
self.items.push(item);
}
}
impl Registerable for Library {
fn into_lib(self) -> Library {
self
}
fn add_to_lib(self, lib: &mut Library) {
lib.items.extend(self.items);
}
}
impl From<Vec<Item>> for Library {
fn from(value: Vec<Item>) -> Self {
Self { items: value }
}
}
impl Registerable for Item {
fn add_to_lib(self, lib: &mut Library) {
lib.add(self)
}
}
impl<const N: usize, T: Registerable> Registerable for [T; N] {
fn add_to_lib(self, lib: &mut Library) {
for el in self {
el.add_to_lib(lib);
}
}
}
impl<T: Registerable> Registerable for Vec<T> {
fn add_to_lib(self, lib: &mut Library) {
for el in self {
el.add_to_lib(lib);
}
}
}
#[derive(Clone, Debug)]
pub struct Module {
pub(crate) ident: Identifier,
pub(crate) doc: String,
pub(crate) children: Vec<Item>,
pub(crate) location: Location,
}
impl Module {
pub fn new(
name: impl Into<Identifier>,
doc: impl AsRef<str>,
location: Location,
) -> Result<Self, RegistrationError> {
let name = name.into();
Rt::check_name(&location, name)?;
Ok(Self {
ident: name,
doc: doc.as_ref().to_string(),
children: Vec::new(),
location,
})
}
pub fn add(&mut self, items: impl Registerable) {
self.children.extend(items.into_lib().items)
}
}
impl Registerable for Module {
fn add_to_lib(self, lib: &mut Library) {
lib.add(self.into())
}
}
impl From<Module> for Item {
fn from(value: Module) -> Self {
Item::Module(value)
}
}
#[derive(Clone, Debug)]
pub struct Type {
pub(crate) ident: Identifier,
pub(crate) rust_name: &'static str,
pub(crate) doc: String,
pub(crate) type_id: TypeId,
pub(crate) layout: Layout,
pub(crate) movability: Movability,
pub(crate) location: Location,
}
impl Type {
pub fn clone<T: Value + Clone>(
name: impl Into<Identifier>,
doc: impl AsRef<str>,
location: Location,
) -> Result<Self, RegistrationError> {
let movability = Movability::CloneDrop(CloneDrop {
clone: extern_clone::<T> as _,
drop: extern_drop::<T> as _,
});
Self::new::<T>(name, doc, movability, location)
}
pub fn copy<T: Value + Copy>(
name: impl Into<Identifier>,
doc: impl AsRef<str>,
location: Location,
) -> Result<Self, RegistrationError> {
Self::new::<T>(name, doc, Movability::Copy, location)
}
pub(crate) fn value<T: Value + Copy>(
name: impl Into<Identifier>,
doc: impl AsRef<str>,
location: Location,
) -> Result<Self, RegistrationError> {
Self::new::<T>(name, doc, Movability::Value, location)
}
fn new<T: Value>(
name: impl Into<Identifier>,
doc: impl AsRef<str>,
movability: Movability,
location: Location,
) -> Result<Self, RegistrationError> {
let name = name.into();
Rt::check_name(&location, name)?;
let ty = T::resolve();
let is_allowed = match ty.description {
TypeDescription::Leaf => true,
TypeDescription::Val(_) => true,
TypeDescription::Option(_) => false,
TypeDescription::Verdict(_, _) => false,
TypeDescription::List(_) => false,
};
if !is_allowed {
return Err(RegistrationError {
message: format!(
"Cannot register the type `{}`. Only `Val<T>` types can be registered",
ty.rust_name
),
location,
});
}
Ok(Self {
ident: name,
rust_name: std::any::type_name::<T>(),
doc: doc.as_ref().into(),
type_id: ty.type_id,
layout: ty.layout,
movability,
location,
})
}
}
impl Registerable for Type {
fn add_to_lib(self, lib: &mut Library) {
lib.add(self.into())
}
}
impl From<Type> for Item {
fn from(value: Type) -> Self {
Item::Type(value)
}
}
#[derive(Clone, Debug)]
pub struct Function {
pub(crate) ident: Identifier,
pub(crate) doc: String,
pub(crate) params: Vec<Identifier>,
pub(crate) func: FunctionDescription,
pub(crate) sig: Option<String>,
pub(crate) location: Location,
pub(crate) vtables: Vec<Identifier>,
}
impl Function {
pub fn new<F, A, R, O>(
name: impl Into<Identifier>,
doc: impl AsRef<str>,
mut params: Vec<&str>,
func: F,
location: Location,
) -> Result<Self, RegistrationError>
where
F: RegisterableFn<A, R, O>,
{
let name = name.into();
Rt::check_name(&location, name)?;
if F::HAS_OUT_PTR {
params.remove(0);
}
let func = FunctionDescription::of(func);
Ok(Self {
ident: name,
doc: doc.as_ref().into(),
params: params.into_iter().map(|p| p.into()).collect(),
sig: None,
func,
vtables: Vec::new(),
location,
})
}
pub(crate) unsafe fn new_generic<F, A, R, O>(
name: impl Into<Identifier>,
doc: impl AsRef<str>,
mut params: Vec<&str>,
func: F,
sig: &str,
vtables: Vec<&str>,
location: Location,
) -> Result<Self, RegistrationError>
where
F: RegisterableFn<A, R, O>,
{
let name = name.into();
Rt::check_name(&location, name)?;
if F::HAS_OUT_PTR {
params.remove(0);
}
let func = FunctionDescription::of(func);
Ok(Self {
ident: name,
doc: doc.as_ref().into(),
params: params.into_iter().map(|p| p.into()).collect(),
sig: Some(sig.to_owned()),
func,
vtables: vtables.into_iter().map(|p| p.into()).collect(),
location,
})
}
}
impl Registerable for Function {
fn add_to_lib(self, lib: &mut Library) {
lib.add(self.into())
}
}
impl From<Function> for Item {
fn from(value: Function) -> Self {
Item::Function(value)
}
}
#[derive(Clone, Debug)]
pub struct Constant {
pub(crate) ident: Identifier,
pub(crate) type_id: TypeId,
pub(crate) doc: String,
pub(crate) value: ConstantValue,
pub(crate) location: Location,
}
impl Constant {
pub fn new<T: Value>(
name: impl Into<Identifier>,
doc: impl AsRef<str>,
val: T,
location: Location,
) -> Result<Self, RegistrationError>
where
T::Transformed: Send + Sync + 'static,
{
let name = name.into();
Rt::check_name(&location, name)?;
let ty = T::resolve();
Ok(Self {
ident: name,
doc: doc.as_ref().into(),
type_id: ty.type_id,
value: ConstantValue::new(val.transform()),
location,
})
}
}
impl Registerable for Constant {
fn add_to_lib(self, lib: &mut Library) {
lib.add(self.into())
}
}
impl From<Constant> for Item {
fn from(value: Constant) -> Self {
Item::Constant(value)
}
}
#[derive(Clone, Debug)]
pub struct Impl {
pub(crate) ty: TypeId,
pub(crate) children: Vec<Item>,
pub(crate) location: Location,
}
impl Impl {
pub fn new<T: Value>(location: Location) -> Self {
let ty = T::resolve();
Self {
ty: ty.type_id,
children: Vec::new(),
location,
}
}
pub fn add(&mut self, items: impl Registerable) {
self.children.extend(items.into_lib().items)
}
}
impl Registerable for Impl {
fn add_to_lib(self, lib: &mut Library) {
lib.add(self.into())
}
}
impl From<Impl> for Item {
fn from(value: Impl) -> Self {
Item::Impl(value)
}
}
#[derive(Clone, Debug)]
pub struct Use {
pub(crate) imports: Vec<Vec<String>>,
pub(crate) location: Location,
}
impl Use {
pub fn new(imports: Vec<Vec<String>>, location: Location) -> Self {
Self { imports, location }
}
}
impl Registerable for Use {
fn add_to_lib(self, lib: &mut Library) {
lib.add(self.into())
}
}
impl From<Use> for Item {
fn from(value: Use) -> Self {
Item::Use(value)
}
}