pub(crate) mod composer;
pub(crate) mod composers;
pub(crate) mod constants;
pub(crate) mod conversion;
pub(crate) mod fermentate;
pub(crate) mod presentation;
#[allow(unused)]
pub(crate) mod writer;
mod xcproj;
pub(crate) mod presentable;
mod composable;
mod formatter;
mod dictionary;
use std::fmt::{Debug, Display, Formatter};
use quote::{quote, ToTokens};
use syn::__private::TokenStream2;
use syn::{Generics, Item, Lifetime};
use crate::error;
use crate::lang::{CrateTreeConsumer, Specification};
use crate::lang::objc::composers::AttrWrapper;
use crate::lang::objc::fermentate::InterfaceImplementation;
use crate::lang::objc::presentable::TypeContext;
use crate::tree::{CrateTree, ScopeTree, ScopeTreeItem};
pub use fermentate::Fermentate as ObjCFermentate;
#[cfg(feature = "objc")]
pub use xcproj::Config as XCodeConfig;
use crate::ast::{Depunctuated, SemiPunctuated};
use crate::composable::CfgAttributes;
use crate::composer::{SourceComposable, GenericComposer, MaybeComposer, SourceAccessible, SourceFermentable};
use crate::kind::expand_attributes;
use crate::presentable::Expression;
use crate::presentation::{FFIVariable, Name};
#[derive(Clone, Debug)]
pub struct ObjCSpecification;
impl Specification for ObjCSpecification {
type Attr = AttrWrapper;
type Gen = Option<Generics>;
type Lt = Vec<Lifetime>;
type TYC = TypeContext;
type Interface = InterfaceImplementation;
type Expr = Expression<Self>;
type Var = FFIVariable<Self, TokenStream2>;
type Name = Name<Self>;
type Fermentate = ObjCFermentate;
}
#[derive(Debug, Clone)]
pub struct Config {
pub xcode: XCodeConfig,
}
impl Config {
pub fn new(xcode: XCodeConfig) -> Self {
Self {
xcode,
}
}
pub fn class_prefix(&self) -> &str {
&self.xcode.class_prefix
}
}
impl Display for Config {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("[objc::Config]\n\txcode: {}", self.xcode))
}
}
impl CrateTreeConsumer for Config {
fn generate(&self, _crate_tree: &CrateTree) -> Result<(), error::Error> {
Ok(())
}
}
impl SourceFermentable<ObjCFermentate> for CrateTree {
fn ferment(&self) -> ObjCFermentate {
let Self { attrs: _, crates, generics_tree: ScopeTree { imported, .. }} = self;
let source = self.source_ref();
let reg_conversions = Depunctuated::from_iter(crates.iter().map(SourceFermentable::<ObjCFermentate>::ferment));
let _generic_imports = SemiPunctuated::from_iter(imported.iter().cloned());
let global = source.context.borrow();
let config = global.config.maybe_objc_config().expect("Expected ObjC config");
let prefix = config.class_prefix();
let generic_conversions = Depunctuated::from_iter(
global.refined_mixins
.iter()
.filter_map(|(mixin, attrs)| {
let attrs = expand_attributes(attrs);
let ty_context = TypeContext::mixin(mixin, prefix, attrs.cfg_attributes());
GenericComposer::<ObjCSpecification>::new(mixin, ty_context, attrs, self.context())
})
.flat_map(|composer| composer.borrow().compose(&source)));
ObjCFermentate::TokenStream(quote! {
#reg_conversions
#generic_conversions
})
}
}
impl SourceFermentable<ObjCFermentate> for ScopeTree {
fn ferment(&self) -> ObjCFermentate {
let mut fermentate = Depunctuated::<ObjCFermentate>::new();
self.exported
.values()
.for_each(|item| match item {
ScopeTreeItem::Item { item, scope, scope_context } =>
if let Some(composer) = <Item as MaybeComposer<ObjCSpecification>>::maybe_composer(item, scope, scope_context) {
fermentate.push(composer.ferment())
},
ScopeTreeItem::Tree { tree} =>
fermentate.push(tree.ferment())
});
ObjCFermentate::TokenStream(fermentate.to_token_stream())
}
}