fix: compile error when using enum in flutter
This commit is contained in:
353
libs/flutter_rust_bridge_codegen/src/parser/mod.rs
Normal file
353
libs/flutter_rust_bridge_codegen/src/parser/mod.rs
Normal file
@@ -0,0 +1,353 @@
|
||||
mod ty;
|
||||
|
||||
use std::string::String;
|
||||
|
||||
use log::debug;
|
||||
use quote::quote;
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::*;
|
||||
|
||||
use crate::ir::*;
|
||||
|
||||
use crate::generator::rust::HANDLER_NAME;
|
||||
use crate::parser::ty::TypeParser;
|
||||
use crate::source_graph::Crate;
|
||||
|
||||
const STREAM_SINK_IDENT: &str = "StreamSink";
|
||||
const RESULT_IDENT: &str = "Result";
|
||||
|
||||
pub fn parse(source_rust_content: &str, file: File, manifest_path: &str) -> IrFile {
|
||||
let crate_map = Crate::new(manifest_path);
|
||||
|
||||
let src_fns = extract_fns_from_file(&file);
|
||||
let src_structs = crate_map.root_module.collect_structs_to_vec();
|
||||
let src_enums = crate_map.root_module.collect_enums_to_vec();
|
||||
|
||||
let parser = Parser::new(TypeParser::new(src_structs, src_enums));
|
||||
parser.parse(source_rust_content, src_fns)
|
||||
}
|
||||
|
||||
struct Parser<'a> {
|
||||
type_parser: TypeParser<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
pub fn new(type_parser: TypeParser<'a>) -> Self {
|
||||
Parser { type_parser }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
fn parse(mut self, source_rust_content: &str, src_fns: Vec<&ItemFn>) -> IrFile {
|
||||
let funcs = src_fns.iter().map(|f| self.parse_function(f)).collect();
|
||||
|
||||
let has_executor = source_rust_content.contains(HANDLER_NAME);
|
||||
|
||||
let (struct_pool, enum_pool) = self.type_parser.consume();
|
||||
|
||||
IrFile {
|
||||
funcs,
|
||||
struct_pool,
|
||||
enum_pool,
|
||||
has_executor,
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to parse the type from the return part of a function signature. There is a special
|
||||
/// case for top-level `Result` types.
|
||||
pub fn try_parse_fn_output_type(&mut self, ty: &syn::Type) -> Option<IrFuncOutput> {
|
||||
let inner = ty::SupportedInnerType::try_from_syn_type(ty)?;
|
||||
|
||||
match inner {
|
||||
ty::SupportedInnerType::Path(ty::SupportedPathType {
|
||||
ident,
|
||||
generic: Some(generic),
|
||||
}) if ident == RESULT_IDENT => Some(IrFuncOutput::ResultType(
|
||||
self.type_parser.convert_to_ir_type(*generic)?,
|
||||
)),
|
||||
_ => Some(IrFuncOutput::Type(
|
||||
self.type_parser.convert_to_ir_type(inner)?,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to parse the type from an argument of a function signature. There is a special
|
||||
/// case for top-level `StreamSink` types.
|
||||
pub fn try_parse_fn_arg_type(&mut self, ty: &syn::Type) -> Option<IrFuncArg> {
|
||||
match ty {
|
||||
syn::Type::Path(syn::TypePath { path, .. }) => {
|
||||
let last_segment = path.segments.last().unwrap();
|
||||
if last_segment.ident == STREAM_SINK_IDENT {
|
||||
match &last_segment.arguments {
|
||||
syn::PathArguments::AngleBracketed(
|
||||
syn::AngleBracketedGenericArguments { args, .. },
|
||||
) if args.len() == 1 => {
|
||||
// Unwrap is safe here because args.len() == 1
|
||||
match args.last().unwrap() {
|
||||
syn::GenericArgument::Type(t) => {
|
||||
Some(IrFuncArg::StreamSinkType(self.type_parser.parse_type(t)))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
Some(IrFuncArg::Type(self.type_parser.parse_type(ty)))
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_function(&mut self, func: &ItemFn) -> IrFunc {
|
||||
debug!("parse_function function name: {:?}", func.sig.ident);
|
||||
|
||||
let sig = &func.sig;
|
||||
let func_name = sig.ident.to_string();
|
||||
|
||||
let mut inputs = Vec::new();
|
||||
let mut output = None;
|
||||
let mut mode = None;
|
||||
let mut fallible = true;
|
||||
|
||||
for sig_input in &sig.inputs {
|
||||
if let FnArg::Typed(ref pat_type) = sig_input {
|
||||
let name = if let Pat::Ident(ref pat_ident) = *pat_type.pat {
|
||||
format!("{}", pat_ident.ident)
|
||||
} else {
|
||||
panic!("unexpected pat_type={:?}", pat_type)
|
||||
};
|
||||
|
||||
match self.try_parse_fn_arg_type(&pat_type.ty).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Failed to parse function argument type `{}`",
|
||||
type_to_string(&pat_type.ty)
|
||||
)
|
||||
}) {
|
||||
IrFuncArg::StreamSinkType(ty) => {
|
||||
output = Some(ty);
|
||||
mode = Some(IrFuncMode::Stream);
|
||||
}
|
||||
IrFuncArg::Type(ty) => {
|
||||
inputs.push(IrField {
|
||||
name: IrIdent::new(name),
|
||||
ty,
|
||||
is_final: true,
|
||||
comments: extract_comments(&pat_type.attrs),
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("unexpected sig_input={:?}", sig_input);
|
||||
}
|
||||
}
|
||||
|
||||
if output.is_none() {
|
||||
output = Some(match &sig.output {
|
||||
ReturnType::Type(_, ty) => {
|
||||
match self.try_parse_fn_output_type(ty).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Failed to parse function output type `{}`",
|
||||
type_to_string(ty)
|
||||
)
|
||||
}) {
|
||||
IrFuncOutput::ResultType(ty) => ty,
|
||||
IrFuncOutput::Type(ty) => {
|
||||
fallible = false;
|
||||
ty
|
||||
}
|
||||
}
|
||||
}
|
||||
ReturnType::Default => {
|
||||
fallible = false;
|
||||
IrType::Primitive(IrTypePrimitive::Unit)
|
||||
}
|
||||
});
|
||||
mode = Some(
|
||||
if let Some(IrType::Delegate(IrTypeDelegate::SyncReturnVecU8)) = output {
|
||||
IrFuncMode::Sync
|
||||
} else {
|
||||
IrFuncMode::Normal
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// let comments = func.attrs.iter().filter_map(extract_comments).collect();
|
||||
|
||||
IrFunc {
|
||||
name: func_name,
|
||||
inputs,
|
||||
output: output.expect("unsupported output"),
|
||||
fallible,
|
||||
mode: mode.expect("unsupported mode"),
|
||||
comments: extract_comments(&func.attrs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_fns_from_file(file: &File) -> Vec<&ItemFn> {
|
||||
let mut src_fns = Vec::new();
|
||||
|
||||
for item in file.items.iter() {
|
||||
if let Item::Fn(ref item_fn) = item {
|
||||
if let Visibility::Public(_) = &item_fn.vis {
|
||||
src_fns.push(item_fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
src_fns
|
||||
}
|
||||
|
||||
fn extract_comments(attrs: &[Attribute]) -> Vec<IrComment> {
|
||||
attrs
|
||||
.iter()
|
||||
.filter_map(|attr| match attr.parse_meta() {
|
||||
Ok(Meta::NameValue(MetaNameValue {
|
||||
path,
|
||||
lit: Lit::Str(lit),
|
||||
..
|
||||
})) if path.is_ident("doc") => Some(IrComment::from(lit.value().as_ref())),
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub mod frb_keyword {
|
||||
syn::custom_keyword!(mirror);
|
||||
syn::custom_keyword!(non_final);
|
||||
syn::custom_keyword!(dart_metadata);
|
||||
syn::custom_keyword!(import);
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NamedOption<K, V> {
|
||||
pub name: K,
|
||||
pub value: V,
|
||||
}
|
||||
|
||||
impl<K: Parse + std::fmt::Debug, V: Parse> Parse for NamedOption<K, V> {
|
||||
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
||||
let name: K = input.parse()?;
|
||||
let _: Token![=] = input.parse()?;
|
||||
let value = input.parse()?;
|
||||
Ok(Self { name, value })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MirrorOption(Path);
|
||||
|
||||
impl Parse for MirrorOption {
|
||||
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
let path: Path = content.parse()?;
|
||||
Ok(Self(path))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MetadataAnnotations(Vec<IrDartAnnotation>);
|
||||
|
||||
impl Parse for IrDartAnnotation {
|
||||
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
||||
let annotation: LitStr = input.parse()?;
|
||||
let library = if input.peek(frb_keyword::import) {
|
||||
let _ = input.parse::<frb_keyword::import>()?;
|
||||
let library: IrDartImport = input.parse()?;
|
||||
Some(library)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Ok(Self {
|
||||
content: annotation.value(),
|
||||
library,
|
||||
})
|
||||
}
|
||||
}
|
||||
impl Parse for MetadataAnnotations {
|
||||
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
let annotations =
|
||||
Punctuated::<IrDartAnnotation, syn::Token![,]>::parse_terminated(&content)?
|
||||
.into_iter()
|
||||
.collect();
|
||||
Ok(Self(annotations))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DartImports(Vec<IrDartImport>);
|
||||
|
||||
impl Parse for IrDartImport {
|
||||
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
||||
let uri: LitStr = input.parse()?;
|
||||
let alias: Option<String> = if input.peek(token::As) {
|
||||
let _ = input.parse::<token::As>()?;
|
||||
let alias: Ident = input.parse()?;
|
||||
Some(alias.to_string())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Ok(Self {
|
||||
uri: uri.value(),
|
||||
alias,
|
||||
})
|
||||
}
|
||||
}
|
||||
impl Parse for DartImports {
|
||||
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
let imports = Punctuated::<IrDartImport, syn::Token![,]>::parse_terminated(&content)?
|
||||
.into_iter()
|
||||
.collect();
|
||||
Ok(Self(imports))
|
||||
}
|
||||
}
|
||||
|
||||
enum FrbOption {
|
||||
Mirror(MirrorOption),
|
||||
NonFinal,
|
||||
Metadata(NamedOption<frb_keyword::dart_metadata, MetadataAnnotations>),
|
||||
}
|
||||
|
||||
impl Parse for FrbOption {
|
||||
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
||||
let lookahead = input.lookahead1();
|
||||
if lookahead.peek(frb_keyword::mirror) {
|
||||
input.parse().map(FrbOption::Mirror)
|
||||
} else if lookahead.peek(frb_keyword::non_final) {
|
||||
input
|
||||
.parse::<frb_keyword::non_final>()
|
||||
.map(|_| FrbOption::NonFinal)
|
||||
} else if lookahead.peek(frb_keyword::dart_metadata) {
|
||||
input.parse().map(FrbOption::Metadata)
|
||||
} else {
|
||||
Err(lookahead.error())
|
||||
}
|
||||
}
|
||||
}
|
||||
fn extract_metadata(attrs: &[Attribute]) -> Vec<IrDartAnnotation> {
|
||||
attrs
|
||||
.iter()
|
||||
.filter(|attr| attr.path.is_ident("frb"))
|
||||
.map(|attr| attr.parse_args::<FrbOption>())
|
||||
.flat_map(|frb_option| match frb_option {
|
||||
Ok(FrbOption::Metadata(NamedOption {
|
||||
name: _,
|
||||
value: MetadataAnnotations(annotations),
|
||||
})) => annotations,
|
||||
_ => vec![],
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// syn -> string https://github.com/dtolnay/syn/issues/294
|
||||
fn type_to_string(ty: &Type) -> String {
|
||||
quote!(#ty).to_string().replace(' ', "")
|
||||
}
|
||||
392
libs/flutter_rust_bridge_codegen/src/parser/ty.rs
Normal file
392
libs/flutter_rust_bridge_codegen/src/parser/ty.rs
Normal file
@@ -0,0 +1,392 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::string::String;
|
||||
|
||||
use syn::*;
|
||||
|
||||
use crate::ir::IrType::*;
|
||||
use crate::ir::*;
|
||||
|
||||
use crate::markers;
|
||||
|
||||
use crate::source_graph::{Enum, Struct};
|
||||
|
||||
use crate::parser::{extract_comments, extract_metadata, type_to_string};
|
||||
|
||||
pub struct TypeParser<'a> {
|
||||
src_structs: HashMap<String, &'a Struct>,
|
||||
src_enums: HashMap<String, &'a Enum>,
|
||||
|
||||
parsing_or_parsed_struct_names: HashSet<String>,
|
||||
struct_pool: IrStructPool,
|
||||
|
||||
parsed_enums: HashSet<String>,
|
||||
enum_pool: IrEnumPool,
|
||||
}
|
||||
|
||||
impl<'a> TypeParser<'a> {
|
||||
pub fn new(
|
||||
src_structs: HashMap<String, &'a Struct>,
|
||||
src_enums: HashMap<String, &'a Enum>,
|
||||
) -> Self {
|
||||
TypeParser {
|
||||
src_structs,
|
||||
src_enums,
|
||||
struct_pool: HashMap::new(),
|
||||
enum_pool: HashMap::new(),
|
||||
parsing_or_parsed_struct_names: HashSet::new(),
|
||||
parsed_enums: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn consume(self) -> (IrStructPool, IrEnumPool) {
|
||||
(self.struct_pool, self.enum_pool)
|
||||
}
|
||||
}
|
||||
|
||||
/// Generic intermediate representation of a type that can appear inside a function signature.
|
||||
#[derive(Debug)]
|
||||
pub enum SupportedInnerType {
|
||||
/// Path types with up to 1 generic type argument on the final segment. All segments before
|
||||
/// the last segment are ignored. The generic type argument must also be a valid
|
||||
/// `SupportedInnerType`.
|
||||
Path(SupportedPathType),
|
||||
/// Array type
|
||||
Array(Box<Self>, usize),
|
||||
/// The unit type `()`.
|
||||
Unit,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SupportedInnerType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Path(p) => write!(f, "{}", p),
|
||||
Self::Array(u, len) => write!(f, "[{}; {}]", u, len),
|
||||
Self::Unit => write!(f, "()"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a named type, with an optional path and up to 1 generic type argument.
|
||||
#[derive(Debug)]
|
||||
pub struct SupportedPathType {
|
||||
pub ident: syn::Ident,
|
||||
pub generic: Option<Box<SupportedInnerType>>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SupportedPathType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let ident = self.ident.to_string();
|
||||
if let Some(generic) = &self.generic {
|
||||
write!(f, "{}<{}>", ident, generic)
|
||||
} else {
|
||||
write!(f, "{}", ident)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SupportedInnerType {
|
||||
/// Given a `syn::Type`, returns a simplified representation of the type if it's supported,
|
||||
/// or `None` otherwise.
|
||||
pub fn try_from_syn_type(ty: &syn::Type) -> Option<Self> {
|
||||
match ty {
|
||||
syn::Type::Path(syn::TypePath { path, .. }) => {
|
||||
let last_segment = path.segments.last().unwrap().clone();
|
||||
match last_segment.arguments {
|
||||
syn::PathArguments::None => Some(SupportedInnerType::Path(SupportedPathType {
|
||||
ident: last_segment.ident,
|
||||
generic: None,
|
||||
})),
|
||||
syn::PathArguments::AngleBracketed(a) => {
|
||||
let generic = match a.args.into_iter().next() {
|
||||
Some(syn::GenericArgument::Type(t)) => {
|
||||
Some(Box::new(SupportedInnerType::try_from_syn_type(&t)?))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
Some(SupportedInnerType::Path(SupportedPathType {
|
||||
ident: last_segment.ident,
|
||||
generic,
|
||||
}))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
syn::Type::Array(syn::TypeArray { elem, len, .. }) => {
|
||||
let len: usize = match len {
|
||||
syn::Expr::Lit(lit) => match &lit.lit {
|
||||
syn::Lit::Int(x) => x.base10_parse().unwrap(),
|
||||
_ => panic!("Cannot parse array length"),
|
||||
},
|
||||
_ => panic!("Cannot parse array length"),
|
||||
};
|
||||
Some(SupportedInnerType::Array(
|
||||
Box::new(SupportedInnerType::try_from_syn_type(elem)?),
|
||||
len,
|
||||
))
|
||||
}
|
||||
syn::Type::Tuple(syn::TypeTuple { elems, .. }) if elems.is_empty() => {
|
||||
Some(SupportedInnerType::Unit)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TypeParser<'a> {
|
||||
pub fn parse_type(&mut self, ty: &syn::Type) -> IrType {
|
||||
let supported_type = SupportedInnerType::try_from_syn_type(ty)
|
||||
.unwrap_or_else(|| panic!("Unsupported type `{}`", type_to_string(ty)));
|
||||
|
||||
self.convert_to_ir_type(supported_type)
|
||||
.unwrap_or_else(|| panic!("parse_type failed for ty={}", type_to_string(ty)))
|
||||
}
|
||||
|
||||
/// Converts an inner type into an `IrType` if possible.
|
||||
pub fn convert_to_ir_type(&mut self, ty: SupportedInnerType) -> Option<IrType> {
|
||||
match ty {
|
||||
SupportedInnerType::Path(p) => self.convert_path_to_ir_type(p),
|
||||
SupportedInnerType::Array(p, len) => self.convert_array_to_ir_type(*p, len),
|
||||
SupportedInnerType::Unit => Some(IrType::Primitive(IrTypePrimitive::Unit)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts an array type into an `IrType` if possible.
|
||||
pub fn convert_array_to_ir_type(
|
||||
&mut self,
|
||||
generic: SupportedInnerType,
|
||||
_len: usize,
|
||||
) -> Option<IrType> {
|
||||
self.convert_to_ir_type(generic).map(|inner| match inner {
|
||||
Primitive(primitive) => PrimitiveList(IrTypePrimitiveList { primitive }),
|
||||
others => GeneralList(IrTypeGeneralList {
|
||||
inner: Box::new(others),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
/// Converts a path type into an `IrType` if possible.
|
||||
pub fn convert_path_to_ir_type(&mut self, p: SupportedPathType) -> Option<IrType> {
|
||||
let p_as_str = format!("{}", &p);
|
||||
let ident_string = &p.ident.to_string();
|
||||
if let Some(generic) = p.generic {
|
||||
match ident_string.as_str() {
|
||||
"SyncReturn" => {
|
||||
// Special-case SyncReturn<Vec<u8>>. SyncReturn for any other type is not
|
||||
// supported.
|
||||
match *generic {
|
||||
SupportedInnerType::Path(SupportedPathType {
|
||||
ident,
|
||||
generic: Some(generic),
|
||||
}) if ident == "Vec" => match *generic {
|
||||
SupportedInnerType::Path(SupportedPathType {
|
||||
ident,
|
||||
generic: None,
|
||||
}) if ident == "u8" => {
|
||||
Some(IrType::Delegate(IrTypeDelegate::SyncReturnVecU8))
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
"Vec" => {
|
||||
// Special-case Vec<String> as StringList
|
||||
if matches!(*generic, SupportedInnerType::Path(SupportedPathType { ref ident, .. }) if ident == "String")
|
||||
{
|
||||
Some(IrType::Delegate(IrTypeDelegate::StringList))
|
||||
} else {
|
||||
self.convert_to_ir_type(*generic).map(|inner| match inner {
|
||||
Primitive(primitive) => {
|
||||
PrimitiveList(IrTypePrimitiveList { primitive })
|
||||
}
|
||||
others => GeneralList(IrTypeGeneralList {
|
||||
inner: Box::new(others),
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
"ZeroCopyBuffer" => {
|
||||
let inner = self.convert_to_ir_type(*generic);
|
||||
if let Some(IrType::PrimitiveList(IrTypePrimitiveList { primitive })) = inner {
|
||||
Some(IrType::Delegate(
|
||||
IrTypeDelegate::ZeroCopyBufferVecPrimitive(primitive),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
"Box" => self.convert_to_ir_type(*generic).map(|inner| {
|
||||
Boxed(IrTypeBoxed {
|
||||
exist_in_real_api: true,
|
||||
inner: Box::new(inner),
|
||||
})
|
||||
}),
|
||||
"Option" => {
|
||||
// Disallow nested Option
|
||||
if matches!(*generic, SupportedInnerType::Path(SupportedPathType { ref ident, .. }) if ident == "Option")
|
||||
{
|
||||
panic!(
|
||||
"Nested optionals without indirection are not supported. (Option<Option<{}>>)",
|
||||
p_as_str
|
||||
);
|
||||
}
|
||||
self.convert_to_ir_type(*generic).map(|inner| match inner {
|
||||
Primitive(prim) => IrType::Optional(IrTypeOptional::new_prim(prim)),
|
||||
st @ StructRef(_) => {
|
||||
IrType::Optional(IrTypeOptional::new_ptr(Boxed(IrTypeBoxed {
|
||||
inner: Box::new(st),
|
||||
exist_in_real_api: false,
|
||||
})))
|
||||
}
|
||||
other => IrType::Optional(IrTypeOptional::new_ptr(other)),
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
IrTypePrimitive::try_from_rust_str(ident_string)
|
||||
.map(Primitive)
|
||||
.or_else(|| {
|
||||
if ident_string == "String" {
|
||||
Some(IrType::Delegate(IrTypeDelegate::String))
|
||||
} else if self.src_structs.contains_key(ident_string) {
|
||||
if !self.parsing_or_parsed_struct_names.contains(ident_string) {
|
||||
self.parsing_or_parsed_struct_names
|
||||
.insert(ident_string.to_owned());
|
||||
let api_struct = self.parse_struct_core(&p.ident);
|
||||
self.struct_pool.insert(ident_string.to_owned(), api_struct);
|
||||
}
|
||||
|
||||
Some(StructRef(IrTypeStructRef {
|
||||
name: ident_string.to_owned(),
|
||||
freezed: self
|
||||
.struct_pool
|
||||
.get(ident_string)
|
||||
.map(IrStruct::using_freezed)
|
||||
.unwrap_or(false),
|
||||
}))
|
||||
} else if self.src_enums.contains_key(ident_string) {
|
||||
if self.parsed_enums.insert(ident_string.to_owned()) {
|
||||
let enu = self.parse_enum_core(&p.ident);
|
||||
self.enum_pool.insert(ident_string.to_owned(), enu);
|
||||
}
|
||||
|
||||
Some(EnumRef(IrTypeEnumRef {
|
||||
name: ident_string.to_owned(),
|
||||
is_struct: self
|
||||
.enum_pool
|
||||
.get(ident_string)
|
||||
.map(IrEnum::is_struct)
|
||||
.unwrap_or(true),
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TypeParser<'a> {
|
||||
fn parse_enum_core(&mut self, ident: &syn::Ident) -> IrEnum {
|
||||
let src_enum = self.src_enums[&ident.to_string()];
|
||||
let name = src_enum.ident.to_string();
|
||||
let wrapper_name = if src_enum.mirror {
|
||||
Some(format!("mirror_{}", name))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let path = src_enum.path.clone();
|
||||
let comments = extract_comments(&src_enum.src.attrs);
|
||||
let variants = src_enum
|
||||
.src
|
||||
.variants
|
||||
.iter()
|
||||
.map(|variant| IrVariant {
|
||||
name: IrIdent::new(variant.ident.to_string()),
|
||||
comments: extract_comments(&variant.attrs),
|
||||
kind: match variant.fields.iter().next() {
|
||||
None => IrVariantKind::Value,
|
||||
Some(Field {
|
||||
attrs,
|
||||
ident: field_ident,
|
||||
..
|
||||
}) => {
|
||||
let variant_ident = variant.ident.to_string();
|
||||
IrVariantKind::Struct(IrStruct {
|
||||
name: variant_ident,
|
||||
wrapper_name: None,
|
||||
path: None,
|
||||
is_fields_named: field_ident.is_some(),
|
||||
dart_metadata: extract_metadata(attrs),
|
||||
comments: extract_comments(attrs),
|
||||
fields: variant
|
||||
.fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, field)| IrField {
|
||||
name: IrIdent::new(
|
||||
field
|
||||
.ident
|
||||
.as_ref()
|
||||
.map(ToString::to_string)
|
||||
.unwrap_or_else(|| format!("field{}", idx)),
|
||||
),
|
||||
ty: self.parse_type(&field.ty),
|
||||
is_final: true,
|
||||
comments: extract_comments(&field.attrs),
|
||||
})
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
.collect();
|
||||
IrEnum::new(name, wrapper_name, path, comments, variants)
|
||||
}
|
||||
|
||||
fn parse_struct_core(&mut self, ident: &syn::Ident) -> IrStruct {
|
||||
let src_struct = self.src_structs[&ident.to_string()];
|
||||
let mut fields = Vec::new();
|
||||
|
||||
let (is_fields_named, struct_fields) = match &src_struct.src.fields {
|
||||
Fields::Named(FieldsNamed { named, .. }) => (true, named),
|
||||
Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => (false, unnamed),
|
||||
_ => panic!("unsupported type: {:?}", src_struct.src.fields),
|
||||
};
|
||||
|
||||
for (idx, field) in struct_fields.iter().enumerate() {
|
||||
let field_name = field
|
||||
.ident
|
||||
.as_ref()
|
||||
.map_or(format!("field{}", idx), ToString::to_string);
|
||||
let field_type = self.parse_type(&field.ty);
|
||||
fields.push(IrField {
|
||||
name: IrIdent::new(field_name),
|
||||
ty: field_type,
|
||||
is_final: !markers::has_non_final(&field.attrs),
|
||||
comments: extract_comments(&field.attrs),
|
||||
});
|
||||
}
|
||||
|
||||
let name = src_struct.ident.to_string();
|
||||
let wrapper_name = if src_struct.mirror {
|
||||
Some(format!("mirror_{}", name))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let path = Some(src_struct.path.clone());
|
||||
let metadata = extract_metadata(&src_struct.src.attrs);
|
||||
let comments = extract_comments(&src_struct.src.attrs);
|
||||
IrStruct {
|
||||
name,
|
||||
wrapper_name,
|
||||
path,
|
||||
fields,
|
||||
is_fields_named,
|
||||
dart_metadata: metadata,
|
||||
comments,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user