Skip to content

Commit c72eaa0

Browse files
committed
Dramatically simplify gix_macros::momo
And make applying support of `gix_macros::momo` truly painless by making it work out-of-the-box. Signed-off-by: Jiahao XU <[email protected]>
1 parent 95a1626 commit c72eaa0

File tree

5 files changed

+24
-163
lines changed

5 files changed

+24
-163
lines changed

gix-macros/src/lib.rs

Lines changed: 12 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
use std::collections::{HashMap, HashSet};
1+
use std::collections::HashMap;
22

33
use proc_macro::TokenStream;
44
use quote::quote;
5-
use syn::{fold::Fold, punctuated::Punctuated, spanned::Spanned, *};
5+
use syn::{punctuated::Punctuated, spanned::Spanned, *};
66

77
#[derive(Copy, Clone)]
88
// All conversions we support. Check references to this type for an idea how to add more.
@@ -13,14 +13,6 @@ enum Conversion<'a> {
1313
}
1414

1515
impl<'a> Conversion<'a> {
16-
fn target_type(&self) -> Type {
17-
match *self {
18-
Conversion::Into(ty) => ty.clone(),
19-
Conversion::AsRef(ty) => parse_quote!(&#ty),
20-
Conversion::AsMut(ty) => parse_quote!(&mut #ty),
21-
}
22-
}
23-
2416
fn conversion_expr(&self, i: Ident) -> Expr {
2517
match *self {
2618
Conversion::Into(_) => parse_quote!(#i.into()),
@@ -62,58 +54,29 @@ fn parse_bounds(bounds: &Punctuated<TypeParamBound, Token![+]>) -> Option<Conver
6254
}
6355

6456
// create a map from generic type to Conversion
65-
fn parse_generics(decl: &Signature) -> (HashMap<Ident, Conversion<'_>>, Generics) {
57+
fn parse_generics(decl: &Signature) -> HashMap<Ident, Conversion<'_>> {
6658
let mut ty_conversions = HashMap::new();
67-
let mut params = Punctuated::new();
6859
for gp in decl.generics.params.iter() {
6960
if let GenericParam::Type(ref tp) = gp {
7061
if let Some(conversion) = parse_bounds(&tp.bounds) {
7162
ty_conversions.insert(tp.ident.clone(), conversion);
7263
continue;
7364
}
7465
}
75-
params.push(gp.clone());
7666
}
77-
let where_clause = if let Some(ref wc) = decl.generics.where_clause {
78-
let mut idents_to_remove = HashSet::new();
79-
let mut predicates = Punctuated::new();
67+
if let Some(ref wc) = decl.generics.where_clause {
8068
for wp in wc.predicates.iter() {
8169
if let WherePredicate::Type(ref pt) = wp {
8270
if let Some(ident) = parse_bounded_type(&pt.bounded_ty) {
8371
if let Some(conversion) = parse_bounds(&pt.bounds) {
84-
idents_to_remove.insert(ident.clone());
8572
ty_conversions.insert(ident, conversion);
8673
continue;
8774
}
8875
}
8976
}
90-
predicates.push(wp.clone());
9177
}
92-
params = params
93-
.into_iter()
94-
.filter(|param| {
95-
if let GenericParam::Type(type_param) = param {
96-
!idents_to_remove.contains(&type_param.ident)
97-
} else {
98-
true
99-
}
100-
})
101-
.collect();
102-
Some(WhereClause {
103-
predicates,
104-
..wc.clone()
105-
})
106-
} else {
107-
None
108-
};
109-
(
110-
ty_conversions,
111-
Generics {
112-
params,
113-
where_clause,
114-
..decl.generics.clone()
115-
},
116-
)
78+
}
79+
ty_conversions
11780
}
11881

11982
fn pat_to_ident(pat: &Pat) -> Ident {
@@ -131,140 +94,36 @@ fn pat_to_expr(pat: &Pat) -> Expr {
13194
fn convert<'a>(
13295
inputs: &'a Punctuated<FnArg, Token![,]>,
13396
ty_conversions: &HashMap<Ident, Conversion<'a>>,
134-
) -> (
135-
Punctuated<FnArg, Token![,]>,
136-
Conversions,
137-
Punctuated<Expr, Token![,]>,
138-
bool,
139-
) {
140-
let mut argtypes = Punctuated::new();
141-
let mut conversions = Conversions {
142-
intos: Vec::new(),
143-
as_refs: Vec::new(),
144-
as_muts: Vec::new(),
145-
};
97+
) -> (Punctuated<Expr, Token![,]>, bool) {
14698
let mut argexprs = Punctuated::new();
14799
let mut has_self = false;
148100
inputs.iter().for_each(|input| match input {
149101
FnArg::Receiver(..) => {
150102
has_self = true;
151-
argtypes.push(input.clone());
152103
}
153-
FnArg::Typed(PatType {
154-
ref pat,
155-
ref ty,
156-
ref colon_token,
157-
..
158-
}) => match **ty {
104+
FnArg::Typed(PatType { ref pat, ref ty, .. }) => match **ty {
159105
Type::ImplTrait(TypeImplTrait { ref bounds, .. }) => {
160106
if let Some(conv) = parse_bounds(bounds) {
161-
argtypes.push(FnArg::Typed(PatType {
162-
attrs: Vec::new(),
163-
pat: pat.clone(),
164-
colon_token: *colon_token,
165-
ty: Box::new(conv.target_type()),
166-
}));
167107
let ident = pat_to_ident(pat);
168-
conversions.add(ident.clone(), conv);
169108
argexprs.push(conv.conversion_expr(ident));
170109
} else {
171-
argtypes.push(input.clone());
172110
argexprs.push(pat_to_expr(pat));
173111
}
174112
}
175113
Type::Path(..) => {
176114
if let Some(conv) = parse_bounded_type(ty).and_then(|ident| ty_conversions.get(&ident)) {
177-
argtypes.push(FnArg::Typed(PatType {
178-
attrs: Vec::new(),
179-
pat: pat.clone(),
180-
colon_token: *colon_token,
181-
ty: Box::new(conv.target_type()),
182-
}));
183115
let ident = pat_to_ident(pat);
184-
conversions.add(ident.clone(), *conv);
185116
argexprs.push(conv.conversion_expr(ident));
186117
} else {
187-
argtypes.push(input.clone());
188118
argexprs.push(pat_to_expr(pat));
189119
}
190120
}
191121
_ => {
192-
argtypes.push(input.clone());
193122
argexprs.push(pat_to_expr(pat));
194123
}
195124
},
196125
});
197-
(argtypes, conversions, argexprs, has_self)
198-
}
199-
200-
struct Conversions {
201-
intos: Vec<Ident>,
202-
as_refs: Vec<Ident>,
203-
as_muts: Vec<Ident>,
204-
}
205-
206-
impl Conversions {
207-
fn add(&mut self, ident: Ident, conv: Conversion) {
208-
match conv {
209-
Conversion::Into(_) => self.intos.push(ident),
210-
Conversion::AsRef(_) => self.as_refs.push(ident),
211-
Conversion::AsMut(_) => self.as_muts.push(ident),
212-
}
213-
}
214-
}
215-
216-
fn has_conversion(idents: &[Ident], expr: &Expr) -> bool {
217-
if let Expr::Path(ExprPath { ref path, .. }) = *expr {
218-
if path.segments.len() == 1 {
219-
let seg = path.segments.iter().last().unwrap();
220-
return idents.iter().any(|i| i == &seg.ident);
221-
}
222-
}
223-
false
224-
}
225-
226-
#[allow(clippy::collapsible_if)]
227-
impl Fold for Conversions {
228-
fn fold_expr(&mut self, expr: Expr) -> Expr {
229-
//TODO: Also catch `Expr::Call` with suitable paths & args
230-
match expr {
231-
Expr::MethodCall(mc) if mc.args.is_empty() => match &*mc.method.to_string() {
232-
"into" if has_conversion(&self.intos, &mc.receiver) => *mc.receiver,
233-
234-
"as_ref" if has_conversion(&self.as_refs, &mc.receiver) => *mc.receiver,
235-
"as_mut" if has_conversion(&self.as_muts, &mc.receiver) => *mc.receiver,
236-
237-
_ => syn::fold::fold_expr(self, Expr::MethodCall(mc)),
238-
},
239-
Expr::Call(call) if call.args.len() == 1 => match &*call.func {
240-
Expr::Path(ExprPath {
241-
path: Path { segments, .. },
242-
..
243-
}) if segments.len() == 2 => match (&*segments[0].ident.to_string(), &*segments[1].ident.to_string()) {
244-
("Into", "into") if has_conversion(&self.intos, &call.args[0]) => call.args[0].clone(),
245-
246-
("AsRef", "as_ref") if matches!(&call.args[0], Expr::Reference(ExprReference { expr, mutability: None, .. }) if has_conversion(&self.as_refs, expr)) => {
247-
if let Expr::Reference(ExprReference { expr, .. }) = &call.args[0] {
248-
(**expr).clone()
249-
} else {
250-
panic!("expr must be Reference")
251-
}
252-
}
253-
("AsMut", "as_mut") if matches!(&call.args[0], Expr::Reference(ExprReference { expr, mutability: Some(_), .. }) if has_conversion(&self.as_muts, expr)) => {
254-
if let Expr::Reference(ExprReference { expr, .. }) = &call.args[0] {
255-
(**expr).clone()
256-
} else {
257-
panic!("expr must be Reference")
258-
}
259-
}
260-
261-
_ => syn::fold::fold_expr(self, Expr::Call(call)),
262-
},
263-
_ => syn::fold::fold_expr(self, Expr::Call(call)),
264-
},
265-
_ => syn::fold::fold_expr(self, expr),
266-
}
267-
}
126+
(argexprs, has_self)
268127
}
269128

270129
fn contains_self_type_path(path: &Path) -> bool {
@@ -339,8 +198,8 @@ fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
339198
};
340199

341200
if let Item::Fn(item_fn) = fn_item {
342-
let (ty_conversions, generics) = parse_generics(&item_fn.sig);
343-
let (argtypes, mut conversions, argexprs, has_self) = convert(&item_fn.sig.inputs, &ty_conversions);
201+
let ty_conversions = parse_generics(&item_fn.sig);
202+
let (argexprs, has_self) = convert(&item_fn.sig.inputs, &ty_conversions);
344203

345204
let uses_self = has_self
346205
|| item_fn.sig.inputs.iter().any(has_self_type)
@@ -367,11 +226,9 @@ fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
367226
vis: Visibility::Inherited,
368227
sig: Signature {
369228
ident: inner_ident.clone(),
370-
generics,
371-
inputs: argtypes,
372229
..item_fn.sig.clone()
373230
},
374-
block: Box::new(conversions.fold_block(*item_fn.block)),
231+
block: item_fn.block,
375232
});
376233

377234
if uses_self {

gix/src/repository/config/transport.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,13 @@ impl crate::Repository {
2323
)),
2424
allow(unused_variables)
2525
)]
26-
#[allow(clippy::needless_lifetimes)]
2726
#[momo]
2827
pub fn transport_options<'a>(
2928
&self,
3029
url: impl Into<&'a BStr>,
3130
remote_name: Option<&BStr>,
3231
) -> Result<Option<Box<dyn Any>>, crate::config::transport::Error> {
33-
let url = gix_url::parse(url)?;
32+
let url = gix_url::parse(url.into())?;
3433
use gix_url::Scheme::*;
3534

3635
match &url.scheme {

gix/src/repository/object.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ impl crate::Repository {
2424
/// Loose object could be partially decoded, even though that's not implemented.
2525
#[momo]
2626
pub fn find_object(&self, id: impl Into<ObjectId>) -> Result<Object<'_>, object::find::existing::Error> {
27+
let id = id.into();
2728
if id == gix_hash::ObjectId::empty_tree(self.object_hash()) {
2829
return Ok(Object {
2930
id,
@@ -43,6 +44,7 @@ impl crate::Repository {
4344
#[doc(alias = "read_header", alias = "git2")]
4445
#[momo]
4546
pub fn find_header(&self, id: impl Into<ObjectId>) -> Result<gix_odb::find::Header, object::find::existing::Error> {
47+
let id = id.into();
4648
if id == gix_hash::ObjectId::empty_tree(self.object_hash()) {
4749
return Ok(gix_odb::find::Header::Loose {
4850
kind: gix_object::Kind::Tree,
@@ -60,6 +62,7 @@ impl crate::Repository {
6062
&self,
6163
id: impl Into<ObjectId>,
6264
) -> Result<Option<gix_odb::find::Header>, object::find::Error> {
65+
let id = id.into();
6366
if id == gix_hash::ObjectId::empty_tree(self.object_hash()) {
6467
return Ok(Some(gix_odb::find::Header::Loose {
6568
kind: gix_object::Kind::Tree,
@@ -72,6 +75,7 @@ impl crate::Repository {
7275
/// Try to find the object with `id` or return `None` if it wasn't found.
7376
#[momo]
7477
pub fn try_find_object(&self, id: impl Into<ObjectId>) -> Result<Option<Object<'_>>, object::find::Error> {
78+
let id = id.into();
7579
if id == gix_hash::ObjectId::empty_tree(self.object_hash()) {
7680
return Ok(Some(Object {
7781
id,
@@ -175,11 +179,11 @@ impl crate::Repository {
175179
constraint: PreviousValue,
176180
) -> Result<Reference<'_>, tag::Error> {
177181
let tag = gix_object::Tag {
178-
target: target.into(),
182+
target: target.as_ref().into(),
179183
target_kind,
180-
name: name.into(),
184+
name: name.as_ref().into(),
181185
tagger: tagger.map(|t| t.to_owned()),
182-
message: message.into(),
186+
message: message.as_ref().into(),
183187
pgp_signature: None,
184188
};
185189
let tag_id = self.write_object(&tag)?;

gix/src/repository/reference.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ impl crate::Repository {
2222
target: impl Into<ObjectId>,
2323
constraint: PreviousValue,
2424
) -> Result<Reference<'_>, reference::edit::Error> {
25-
let id = target;
25+
let id = target.into();
2626
let mut edits = self.edit_reference(RefEdit {
2727
change: Change::Update {
2828
log: Default::default(),
2929
expected: constraint,
3030
new: Target::Peeled(id),
3131
},
32-
name: format!("refs/tags/{name}").try_into()?,
32+
name: format!("refs/tags/{}", name.as_ref()).try_into()?,
3333
deref: false,
3434
})?;
3535
assert_eq!(edits.len(), 1, "reference splits should ever happen");

gix/src/repository/worktree.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,11 @@ impl crate::Repository {
6363
id: impl Into<gix_hash::ObjectId>,
6464
) -> Result<(gix_worktree_stream::Stream, gix_index::File), crate::repository::worktree_stream::Error> {
6565
use gix_odb::{FindExt, HeaderExt};
66+
let id = id.into();
6667
let header = self.objects.header(id)?;
6768
if !header.kind().is_tree() {
6869
return Err(crate::repository::worktree_stream::Error::NotATree {
69-
id: id.to_owned(),
70+
id,
7071
actual: header.kind(),
7172
});
7273
}

0 commit comments

Comments
 (0)