Rewrite stab generation to be more extensible
This commit is contained in:
parent
ef811ecfa9
commit
c760d12c39
@ -101,7 +101,7 @@ fn generate_cdef_structure(str: &mut ItemStruct) -> Result<TokenStream> {
|
|||||||
|
|
||||||
let ffi = ffi_crate();
|
let ffi = ffi_crate();
|
||||||
let ty = &str.ident;
|
let ty = &str.ident;
|
||||||
let build = generate_cdef_build(&get_cfields(&mut str.fields)?)?;
|
let build = generate_cdef_build(&parse_cfields(&mut str.fields)?)?;
|
||||||
|
|
||||||
Ok(quote!(
|
Ok(quote!(
|
||||||
unsafe impl #ffi::Cdef for #ty {
|
unsafe impl #ffi::Cdef for #ty {
|
||||||
@ -123,7 +123,7 @@ fn generate_cdef_enum(enu: &mut ItemEnum) -> Result<TokenStream> {
|
|||||||
.variants
|
.variants
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.map(|variant| {
|
.map(|variant| {
|
||||||
let build = generate_cdef_build(&get_cfields(&mut variant.fields)?)?;
|
let build = generate_cdef_build(&parse_cfields(&mut variant.fields)?)?;
|
||||||
Ok(quote!(b.inner_struct(|b| { #build })))
|
Ok(quote!(b.inner_struct(|b| { #build })))
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>>>()?;
|
.collect::<Result<Vec<_>>>()?;
|
||||||
@ -148,7 +148,7 @@ struct CFieldAttrs {
|
|||||||
opaque: bool,
|
opaque: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_cfields(fields: &mut Fields) -> Result<Vec<CField>> {
|
fn parse_cfields(fields: &mut Fields) -> Result<Vec<CField>> {
|
||||||
match fields {
|
match fields {
|
||||||
Fields::Named(fields) => fields.named.iter_mut(),
|
Fields::Named(fields) => fields.named.iter_mut(),
|
||||||
Fields::Unnamed(fields) => fields.unnamed.iter_mut(),
|
Fields::Unnamed(fields) => fields.unnamed.iter_mut(),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
StringLike, ffi_crate, is_optionlike, is_primitivelike, is_stringlike, is_unit, pat_ident,
|
StringLike, ffi_crate, is_optionlike, is_primitivelike, is_resultlike, is_stringlike, is_unit,
|
||||||
syn_assert, syn_error, ty_name,
|
pat_ident, syn_assert, syn_error, ty_name,
|
||||||
};
|
};
|
||||||
use darling::FromMeta;
|
use darling::FromMeta;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
@ -78,7 +78,7 @@ fn generate_impls(_args: &Args, imp: &mut ItemImpl) -> Result<TokenStream> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// process extern "Lua-C" ffi functions
|
// process extern "Lua-C" ffi functions
|
||||||
for func in get_ffi_functions(imp)? {
|
for func in parse_ffi_functions(imp)? {
|
||||||
if let Some(mm) = func.attrs.metamethod {
|
if let Some(mm) = func.attrs.metamethod {
|
||||||
syn_assert!(
|
syn_assert!(
|
||||||
mms.insert(mm),
|
mms.insert(mm),
|
||||||
@ -91,7 +91,7 @@ fn generate_impls(_args: &Args, imp: &mut ItemImpl) -> Result<TokenStream> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// process extern "Lua" lua functions
|
// process extern "Lua" lua functions
|
||||||
for func in get_lua_functions(imp)? {
|
for func in parse_lua_functions(imp)? {
|
||||||
if let Some(mm) = func.attrs.metamethod {
|
if let Some(mm) = func.attrs.metamethod {
|
||||||
syn_assert!(
|
syn_assert!(
|
||||||
mms.insert(mm),
|
mms.insert(mm),
|
||||||
@ -230,8 +230,8 @@ struct FfiFunctionAttrs {
|
|||||||
metamethod: Option<Metamethod>,
|
metamethod: Option<Metamethod>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_ffi_functions(imp: &mut ItemImpl) -> Result<Vec<FfiFunction>> {
|
fn parse_ffi_functions(imp: &mut ItemImpl) -> Result<Vec<FfiFunction>> {
|
||||||
let mut funcs = vec![];
|
let mut parsed = vec![];
|
||||||
|
|
||||||
for item in imp.items.iter_mut() {
|
for item in imp.items.iter_mut() {
|
||||||
if let ImplItem::Fn(func) = item
|
if let ImplItem::Fn(func) = item
|
||||||
@ -284,22 +284,19 @@ fn get_ffi_functions(imp: &mut ItemImpl) -> Result<Vec<FfiFunction>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let attrs = parse_ffi_function_attrs(&mut func.attrs)?;
|
parsed.push(FfiFunction {
|
||||||
attrs.metamethod.map(|mm| document_metamethod(func, mm));
|
|
||||||
func.sig.asyncness.is_some().then(|| document_async(func));
|
|
||||||
document_ffi_function(func);
|
|
||||||
|
|
||||||
funcs.push(FfiFunction {
|
|
||||||
name: func.sig.ident.clone(),
|
name: func.sig.ident.clone(),
|
||||||
params,
|
params,
|
||||||
ret,
|
ret,
|
||||||
attrs,
|
attrs: parse_ffi_function_attrs(&mut func.attrs)?,
|
||||||
is_async: func.sig.asyncness.is_some(),
|
is_async: func.sig.asyncness.is_some(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document_ffi_function(func, parsed.last().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(funcs)
|
Ok(parsed)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ffi_function_attrs(attrs: &mut Vec<Attribute>) -> Result<FfiFunctionAttrs> {
|
fn parse_ffi_function_attrs(attrs: &mut Vec<Attribute>) -> Result<FfiFunctionAttrs> {
|
||||||
@ -547,8 +544,8 @@ struct LuaFunctionAttrs {
|
|||||||
metamethod: Option<Metamethod>,
|
metamethod: Option<Metamethod>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_lua_functions(imp: &mut ItemImpl) -> Result<Vec<LuaFunction>> {
|
fn parse_lua_functions(imp: &mut ItemImpl) -> Result<Vec<LuaFunction>> {
|
||||||
let mut funcs = vec![];
|
let mut parsed = vec![];
|
||||||
|
|
||||||
for item in imp.items.iter_mut() {
|
for item in imp.items.iter_mut() {
|
||||||
if let ImplItem::Fn(func) = item
|
if let ImplItem::Fn(func) = item
|
||||||
@ -582,23 +579,36 @@ fn get_lua_functions(imp: &mut ItemImpl) -> Result<Vec<LuaFunction>> {
|
|||||||
params.push(parse_quote_spanned!(variadic.span() => variadic!())); // luaify builtin macro
|
params.push(parse_quote_spanned!(variadic.span() => variadic!())); // luaify builtin macro
|
||||||
}
|
}
|
||||||
|
|
||||||
let attrs = parse_lua_function_attrs(&mut func.attrs)?;
|
parsed.push(LuaFunction {
|
||||||
attrs.metamethod.map(|mm| document_metamethod(func, mm));
|
|
||||||
func.sig.asyncness.is_some().then(|| document_async(func));
|
|
||||||
document_lua_function(func);
|
|
||||||
|
|
||||||
funcs.push(LuaFunction {
|
|
||||||
name: func.sig.ident.clone(),
|
name: func.sig.ident.clone(),
|
||||||
params,
|
params,
|
||||||
body: func.block.clone(),
|
body: func.block.clone(),
|
||||||
attrs,
|
attrs: parse_lua_function_attrs(&mut func.attrs)?,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document_lua_function(func, parsed.last().unwrap());
|
||||||
stub_lua_function(func)?;
|
stub_lua_function(func)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(funcs)
|
Ok(parsed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_lua_function_attrs(attrs: &mut Vec<Attribute>) -> Result<LuaFunctionAttrs> {
|
||||||
|
let mut parsed = LuaFunctionAttrs::default();
|
||||||
|
let mut i = 0;
|
||||||
|
while let Some(attr) = attrs.get(i) {
|
||||||
|
if let Some(name) = attr.path().get_ident()
|
||||||
|
&& let Ok(method) = Metamethod::try_from(&name.unraw())
|
||||||
|
{
|
||||||
|
parsed.metamethod = Some(method);
|
||||||
|
attrs.remove(i);
|
||||||
|
} else {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(parsed)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stub_lua_function(func: &mut ImplItemFn) -> Result<()> {
|
fn stub_lua_function(func: &mut ImplItemFn) -> Result<()> {
|
||||||
@ -649,23 +659,6 @@ fn stub_lua_function(func: &mut ImplItemFn) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_lua_function_attrs(attrs: &mut Vec<Attribute>) -> Result<LuaFunctionAttrs> {
|
|
||||||
let mut parsed = LuaFunctionAttrs::default();
|
|
||||||
let mut i = 0;
|
|
||||||
while let Some(attr) = attrs.get(i) {
|
|
||||||
if let Some(name) = attr.path().get_ident()
|
|
||||||
&& let Ok(method) = Metamethod::try_from(&name.unraw())
|
|
||||||
{
|
|
||||||
parsed.metamethod = Some(method);
|
|
||||||
attrs.remove(i);
|
|
||||||
} else {
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(parsed)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_lua_function(registry: &mut Registry, func: &LuaFunction) -> Result<()> {
|
fn add_lua_function(registry: &mut Registry, func: &LuaFunction) -> Result<()> {
|
||||||
let ffi = ffi_crate();
|
let ffi = ffi_crate();
|
||||||
let luaify = quote!(#ffi::__internal::luaify!);
|
let luaify = quote!(#ffi::__internal::luaify!);
|
||||||
@ -750,75 +743,176 @@ fn inject_merged_drop(registry: &mut Registry, lua: Option<&LuaFunction>) -> Res
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn document_ffi_function(func: &mut ImplItemFn) {
|
// the transparency makes it work in dark mode too
|
||||||
func.attrs.insert(0, parse_quote!(#[doc =
|
// const FFI_COLOR: &str = "rgba(255, 222, 118, 0.3)"; // yellow
|
||||||
r#"<span
|
// const LUA_COLOR: &str = "rgba(188, 222, 255, 0.3)"; // blue
|
||||||
class="stab"
|
const FALLIBLE_COLOR: &str = "rgba(255, 168, 168, 0.3)"; // red
|
||||||
title="This function is implemented in Rust and called via FFI."
|
const ASYNC_COLOR: &str = "rgba(188, 222, 255, 0.3)"; // blue
|
||||||
style="float: right; background: #fff5d6; font-weight: 500; margin-left: 3px; padding-left: 5px; padding-right: 5px;"
|
const METAMETHOD_COLOR: &str = "rgba(255, 222, 118, 0.3)"; // yellow
|
||||||
>FFI</span>"#
|
|
||||||
]));
|
struct StabConfig {
|
||||||
|
text: &'static str,
|
||||||
|
desc: &'static str,
|
||||||
|
color: &'static str,
|
||||||
|
strong: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn document_lua_function(func: &mut ImplItemFn) {
|
fn generate_stab(
|
||||||
func.attrs.insert(0, parse_quote!(#[doc =
|
StabConfig {
|
||||||
r#"<span
|
text,
|
||||||
class="stab"
|
desc,
|
||||||
title="This function is implemented in Lua."
|
color,
|
||||||
style="float: right; background: #ebf5ff; font-weight: 500; margin-left: 3px; padding-left: 5px; padding-right: 5px;"
|
strong,
|
||||||
>Lua</span>"#
|
}: StabConfig,
|
||||||
]));
|
) -> Attribute {
|
||||||
|
let attrs = vec![
|
||||||
|
("class", "stab".into()),
|
||||||
|
("title", desc.into()),
|
||||||
|
("aria-label", desc.into()),
|
||||||
|
("style", {
|
||||||
|
let mut style = vec![
|
||||||
|
("float", "right"),
|
||||||
|
("margin", "1px"),
|
||||||
|
("margin-left", "4px"),
|
||||||
|
("padding-left", "5px"),
|
||||||
|
("padding-right", "5px"),
|
||||||
|
("background", color),
|
||||||
|
];
|
||||||
|
|
||||||
|
if strong {
|
||||||
|
style.push(("font-weight", "600"));
|
||||||
|
}
|
||||||
|
|
||||||
|
style
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| format!("{k}: {v}"))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("; ")
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
let attrs = attrs
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| format!(r#"{k}="{v}""#))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" ");
|
||||||
|
|
||||||
|
let tag = format!(r#"<span {attrs}>{text}</span>"#);
|
||||||
|
parse_quote!(#[doc = #tag])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn document_async(func: &mut ImplItemFn) {
|
fn document_ffi_function(item: &mut ImplItemFn, func: &FfiFunction) {
|
||||||
func.attrs.insert(0, parse_quote!(#[doc =
|
let mut attrs = vec![];
|
||||||
r#"<span
|
|
||||||
class="stab"
|
// attrs.push(generate_stab(StabConfig {
|
||||||
title="This function is asynchronous and will yield the calling thread."
|
// text: "FFI",
|
||||||
style="float: right; background: #ebf5ff; margin-left: 3px; padding-left: 5px; padding-right: 5px;"
|
// desc: "This function is implemented in Rust and called via FFI.",
|
||||||
>Async</span>"#
|
// color: FFI_COLOR,
|
||||||
]));
|
// strong: true,
|
||||||
|
// }));
|
||||||
|
|
||||||
|
generate_stab_fallible(item).map(|stab| attrs.push(stab));
|
||||||
|
generate_stab_async(item).map(|stab| attrs.push(stab));
|
||||||
|
generate_stab_metamethod(func.attrs.metamethod).map(|(stab, help)| {
|
||||||
|
attrs.push(stab);
|
||||||
|
item.attrs.push(help);
|
||||||
|
});
|
||||||
|
|
||||||
|
item.attrs.splice(0..0, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn document_metamethod(func: &mut ImplItemFn, method: Metamethod) {
|
fn document_lua_function(item: &mut ImplItemFn, func: &LuaFunction) {
|
||||||
func.attrs.insert(0, parse_quote!(#[doc =
|
let mut attrs = vec![];
|
||||||
r#"<span
|
|
||||||
class="stab"
|
|
||||||
title="This function is a metamethod."
|
|
||||||
style="float: right; background: #ebf5ff; margin-left: 3px; padding-left: 5px; padding-right: 5px;"
|
|
||||||
>Metamethod</span>"#
|
|
||||||
]));
|
|
||||||
|
|
||||||
let doc = match method {
|
// attrs.push(generate_stab(StabConfig {
|
||||||
Metamethod::Eq => "This function is a metamethod which is called by the `==` operator.",
|
// text: "Lua",
|
||||||
Metamethod::Len => "This function is a metamethod which is called by the `#` operator.",
|
// desc: "This function is implemented in Lua.",
|
||||||
Metamethod::Lt => "This function is a metamethod which is called by the `<` operator.",
|
// color: LUA_COLOR,
|
||||||
Metamethod::Le => "This function is a metamethod which is called by the `<=` operator.",
|
// strong: true,
|
||||||
Metamethod::Concat => "This function is a metamethod which is called by the `..` operator.",
|
// }));
|
||||||
Metamethod::Call => {
|
|
||||||
"This function is a metamethod which can be called by calling `(...)` on the value directly."
|
|
||||||
}
|
|
||||||
Metamethod::Add => "This function is a metamethod which is called by the `+` operator.",
|
|
||||||
Metamethod::Sub => "This function is a metamethod which is called by the `-` operator.",
|
|
||||||
Metamethod::Mul => "This function is a metamethod which is called by the `*` operator.",
|
|
||||||
Metamethod::Div => "This function is a metamethod which is called by the `/` operator.",
|
|
||||||
Metamethod::Mod => "This function is a metamethod which is called by the `%` operator.",
|
|
||||||
Metamethod::Pow => "This function is a metamethod which is called by the `^` operator.",
|
|
||||||
Metamethod::Unm => "This function is a metamethod which is called by the `-` operator.",
|
|
||||||
Metamethod::ToString => {
|
|
||||||
"This function is a metamethod which is called by the [`tostring(...)`](https://www.lua.org/manual/5.1/manual.html#pdf-tostring) built-in function."
|
|
||||||
}
|
|
||||||
Metamethod::Pairs => {
|
|
||||||
"This function is a metamethod which is called by the [`pairs(...)`](https://www.lua.org/manual/5.1/manual.html#pdf-pairs) built-in function."
|
|
||||||
}
|
|
||||||
Metamethod::Ipairs => {
|
|
||||||
"This function is a metamethod which is called by the [`ipairs(...)`](https://www.lua.org/manual/5.1/manual.html#pdf-ipairs) built-in function."
|
|
||||||
}
|
|
||||||
_ => "This function is a metamethod and cannot be called directly.",
|
|
||||||
};
|
|
||||||
|
|
||||||
func.attrs.push(parse_quote!(#[doc = ""]));
|
generate_stab_fallible(item).map(|stab| attrs.push(stab));
|
||||||
func.attrs.push(parse_quote!(#[doc = "# Metamethod"]));
|
generate_stab_async(item).map(|stab| attrs.push(stab));
|
||||||
func.attrs.push(parse_quote!(#[doc = ""]));
|
generate_stab_metamethod(func.attrs.metamethod).map(|(stab, help)| {
|
||||||
func.attrs.push(parse_quote!(#[doc = #doc]));
|
attrs.push(stab);
|
||||||
|
item.attrs.push(help);
|
||||||
|
});
|
||||||
|
|
||||||
|
item.attrs.splice(0..0, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_stab_async(item: &ImplItemFn) -> Option<Attribute> {
|
||||||
|
item.sig.asyncness.as_ref().map(|_| {
|
||||||
|
generate_stab(StabConfig {
|
||||||
|
text: "Async",
|
||||||
|
desc: "This function is asynchronous and will yield the calling thread.",
|
||||||
|
color: ASYNC_COLOR,
|
||||||
|
strong: false,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_stab_fallible(item: &ImplItemFn) -> Option<Attribute> {
|
||||||
|
match item.sig.output {
|
||||||
|
ReturnType::Default => None,
|
||||||
|
ReturnType::Type(_, ref ty) => is_resultlike(ty).map(|_| {
|
||||||
|
generate_stab(StabConfig {
|
||||||
|
text: "Fallible",
|
||||||
|
desc: "This function is fallible and may throw an error on failure.",
|
||||||
|
color: FALLIBLE_COLOR,
|
||||||
|
strong: false,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_stab_metamethod(method: Option<Metamethod>) -> Option<(Attribute, Attribute)> {
|
||||||
|
method.map(|method| {
|
||||||
|
let stab = generate_stab(StabConfig {
|
||||||
|
text: "Metamethod",
|
||||||
|
desc: "This function is a metamethod.",
|
||||||
|
color: METAMETHOD_COLOR,
|
||||||
|
strong: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
let help = match method {
|
||||||
|
Metamethod::Eq => "This function is a metamethod which is called by the `==` operator.",
|
||||||
|
Metamethod::Len => "This function is a metamethod which is called by the `#` operator.",
|
||||||
|
Metamethod::Lt => "This function is a metamethod which is called by the `<` operator.",
|
||||||
|
Metamethod::Le => "This function is a metamethod which is called by the `<=` operator.",
|
||||||
|
Metamethod::Concat => {
|
||||||
|
"This function is a metamethod which is called by the `..` operator."
|
||||||
|
}
|
||||||
|
Metamethod::Call => {
|
||||||
|
"This function is a metamethod which can be called by calling \
|
||||||
|
`(...)` on the value directly."
|
||||||
|
}
|
||||||
|
Metamethod::Add => "This function is a metamethod which is called by the `+` operator.",
|
||||||
|
Metamethod::Sub => "This function is a metamethod which is called by the `-` operator.",
|
||||||
|
Metamethod::Mul => "This function is a metamethod which is called by the `*` operator.",
|
||||||
|
Metamethod::Div => "This function is a metamethod which is called by the `/` operator.",
|
||||||
|
Metamethod::Mod => "This function is a metamethod which is called by the `%` operator.",
|
||||||
|
Metamethod::Pow => "This function is a metamethod which is called by the `^` operator.",
|
||||||
|
Metamethod::Unm => "This function is a metamethod which is called by the `-` operator.",
|
||||||
|
Metamethod::ToString => {
|
||||||
|
"This function is a metamethod which is called by the \
|
||||||
|
[`tostring(...)`](https://www.lua.org/manual/5.1/manual.html#pdf-tostring) \
|
||||||
|
built-in function."
|
||||||
|
}
|
||||||
|
Metamethod::Pairs => {
|
||||||
|
"This function is a metamethod which is called by the \
|
||||||
|
[`pairs(...)`](https://www.lua.org/manual/5.1/manual.html#pdf-pairs) \
|
||||||
|
built-in function."
|
||||||
|
}
|
||||||
|
Metamethod::Ipairs => {
|
||||||
|
"This function is a metamethod which is called by the \
|
||||||
|
[`ipairs(...)`](https://www.lua.org/manual/5.1/manual.html#pdf-ipairs) \
|
||||||
|
built-in function."
|
||||||
|
}
|
||||||
|
_ => "This function is a metamethod and cannot be called directly.",
|
||||||
|
};
|
||||||
|
|
||||||
|
let help = format!("\n# Metamethod\n\n{help}");
|
||||||
|
(stab, parse_quote!(#[doc = #help]))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -163,3 +163,19 @@ pub fn is_optionlike(ty: &Type) -> Option<&Type> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_resultlike(ty: &Type) -> Option<&Type> {
|
||||||
|
if let Type::Path(path) = ty
|
||||||
|
&& path.path.leading_colon.is_none()
|
||||||
|
&& path.path.segments.len() == 1
|
||||||
|
&& let Some(segment) = path.path.segments.get(0)
|
||||||
|
&& segment.ident == "Result"
|
||||||
|
&& let PathArguments::AngleBracketed(ref angle) = segment.arguments
|
||||||
|
&& angle.args.len() <= 2 // allow Result<T, E> or Result<T>
|
||||||
|
&& let Some(GenericArgument::Type(ty)) = angle.args.get(0)
|
||||||
|
{
|
||||||
|
Some(ty)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user