Skip to content

Commit 833f2a3

Browse files
committed
Replace clang.rs iterator with generic boxed Map<Range<>>
Add functions: -ffi_call_index_iterator -> Box<ExactSizeIterator> for foreign function with unsigned length and index -ffi_call_index_iterator_check_positive -> Option<Box<ExactSizeIterator>> for foreign function with signed length and index that can be -1 These function take two closures as parameters. This interface should guide the correct usage of having thin closures arround the actual two relevant ffi functions. The ad hoc iterator where basically implementing (0..clang_getNum()).map( |id| clang_getItem( self.x, id ) ) with some additional complexity if clang_getNum() could be -1. Using these new function greatly improve maintainability since now everything is in the function getting a specific iterator, and all iterators implement ExactSizeIterator consistently. The trade off is we now have dynamic dispatch, but that should not be too problematic since we are calling a foreign function to get the item. Eventually rust will support impl trait (experimental feature conservative_impl_trait which has a very close syntax) at which point the Box can be replaced if needed and appropriate.
1 parent 1a8a2ac commit 833f2a3

File tree

1 file changed

+70
-101
lines changed

1 file changed

+70
-101
lines changed

libbindgen/src/clang.rs

+70-101
Original file line numberDiff line numberDiff line change
@@ -653,18 +653,18 @@ impl Type {
653653

654654
/// If this type is a class template specialization, return its
655655
/// template arguments. Otherwise, return None.
656-
pub fn template_args(&self) -> Option<TypeTemplateArgIterator> {
657-
let n = unsafe { clang_Type_getNumTemplateArguments(self.x) };
658-
if n >= 0 {
659-
Some(TypeTemplateArgIterator {
660-
x: self.x,
661-
length: n as u32,
662-
index: 0,
663-
})
664-
} else {
665-
debug_assert_eq!(n, -1);
666-
None
667-
}
656+
pub fn template_args<'a>
657+
(&'a self)
658+
-> Option<Box<ExactSizeIterator<Item = Type> + 'a>> {
659+
let f_len =
660+
move || unsafe { clang_Type_getNumTemplateArguments(self.x) };
661+
let f = move |i| {
662+
Type {
663+
x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, i) },
664+
}
665+
};
666+
667+
ffi_call_index_iterator_check_positive(f_len, f)
668668
}
669669

670670
/// Given that this type is a pointer type, return the type that it points
@@ -761,35 +761,6 @@ impl Type {
761761
}
762762
}
763763

764-
/// An iterator for a type's template arguments.
765-
pub struct TypeTemplateArgIterator {
766-
x: CXType,
767-
length: u32,
768-
index: u32,
769-
}
770-
771-
impl Iterator for TypeTemplateArgIterator {
772-
type Item = Type;
773-
fn next(&mut self) -> Option<Type> {
774-
if self.index < self.length {
775-
let idx = self.index as c_int;
776-
self.index += 1;
777-
Some(Type {
778-
x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, idx) },
779-
})
780-
} else {
781-
None
782-
}
783-
}
784-
}
785-
786-
impl ExactSizeIterator for TypeTemplateArgIterator {
787-
fn len(&self) -> usize {
788-
assert!(self.index <= self.length);
789-
(self.length - self.index) as usize
790-
}
791-
}
792-
793764
/// A `SourceLocation` is a file, line, column, and byte offset location for
794765
/// some source text.
795766
pub struct SourceLocation {
@@ -845,12 +816,16 @@ impl Comment {
845816
}
846817

847818
/// Get this comment's children comment
848-
pub fn get_children(&self) -> CommentChildrenIterator {
849-
CommentChildrenIterator {
850-
parent: self.x,
851-
length: unsafe { clang_Comment_getNumChildren(self.x) },
852-
index: 0,
853-
}
819+
pub fn get_children<'a>(&'a self)
820+
-> Box<ExactSizeIterator<Item = Comment> + 'a> {
821+
let f_len = move || unsafe { clang_Comment_getNumChildren(self.x) };
822+
let f = move |i| {
823+
Comment {
824+
x: unsafe { clang_Comment_getChild(self.x, i) },
825+
}
826+
};
827+
828+
ffi_call_index_iterator(f_len, f)
854829
}
855830

856831
/// Given that this comment is the start or end of an HTML tag, get its tag
@@ -860,34 +835,22 @@ impl Comment {
860835
}
861836

862837
/// Given that this comment is an HTML start tag, get its attributes.
863-
pub fn get_tag_attrs(&self) -> CommentAttributesIterator {
864-
CommentAttributesIterator {
865-
x: self.x,
866-
length: unsafe { clang_HTMLStartTag_getNumAttrs(self.x) },
867-
index: 0,
868-
}
869-
}
870-
}
871-
872-
/// An iterator for a comment's children
873-
pub struct CommentChildrenIterator {
874-
parent: CXComment,
875-
length: c_uint,
876-
index: c_uint,
877-
}
838+
pub fn get_tag_attrs<'a>
839+
(&'a self)
840+
-> Box<ExactSizeIterator<Item = CommentAttribute> + 'a> {
841+
let f_len = move || unsafe { clang_HTMLStartTag_getNumAttrs(self.x) };
842+
let f = move |i| {
843+
CommentAttribute {
844+
name: unsafe {
845+
clang_HTMLStartTag_getAttrName(self.x, i).into()
846+
},
847+
value: unsafe {
848+
clang_HTMLStartTag_getAttrValue(self.x, i).into()
849+
},
850+
}
851+
};
878852

879-
impl Iterator for CommentChildrenIterator {
880-
type Item = Comment;
881-
fn next(&mut self) -> Option<Comment> {
882-
if self.index < self.length {
883-
let idx = self.index;
884-
self.index += 1;
885-
Some(Comment {
886-
x: unsafe { clang_Comment_getChild(self.parent, idx) },
887-
})
888-
} else {
889-
None
890-
}
853+
ffi_call_index_iterator(f_len, f)
891854
}
892855
}
893856

@@ -899,33 +862,6 @@ pub struct CommentAttribute {
899862
pub value: String,
900863
}
901864

902-
/// An iterator for a comment's attributes
903-
pub struct CommentAttributesIterator {
904-
x: CXComment,
905-
length: c_uint,
906-
index: c_uint,
907-
}
908-
909-
impl Iterator for CommentAttributesIterator {
910-
type Item = CommentAttribute;
911-
fn next(&mut self) -> Option<CommentAttribute> {
912-
if self.index < self.length {
913-
let idx = self.index;
914-
self.index += 1;
915-
Some(CommentAttribute {
916-
name: unsafe {
917-
clang_HTMLStartTag_getAttrName(self.x, idx).into()
918-
},
919-
value: unsafe {
920-
clang_HTMLStartTag_getAttrValue(self.x, idx).into()
921-
},
922-
})
923-
} else {
924-
None
925-
}
926-
}
927-
}
928-
929865
/// A source file.
930866
pub struct File {
931867
x: CXFile,
@@ -1343,3 +1279,36 @@ impl Drop for EvalResult {
13431279
unsafe { clang_EvalResult_dispose(self.x) };
13441280
}
13451281
}
1282+
1283+
/// Provide a boxed iterator for foreign function call
1284+
/// Iterate over 0..f_len() and map using f
1285+
/// This function can be used with c_uint index
1286+
fn ffi_call_index_iterator<'a, FLen, F, T>
1287+
(f_len: FLen,
1288+
f: F)
1289+
-> Box<ExactSizeIterator<Item = T> + 'a>
1290+
where FLen: Fn() -> c_uint + 'a,
1291+
F: Fn(c_uint) -> T + 'a,
1292+
{
1293+
Box::new((0..f_len()).map(f))
1294+
}
1295+
1296+
/// Provide an option boxed iterator for foreign function call
1297+
/// Iterate over 0..f_len() and map using f
1298+
/// This function can be used with c_int index and only
1299+
/// returns an iterator if f_len() is positive.
1300+
fn ffi_call_index_iterator_check_positive<'a, FLen, F, T>
1301+
(f_len: FLen,
1302+
f: F)
1303+
-> Option<Box<ExactSizeIterator<Item = T> + 'a>>
1304+
where FLen: Fn() -> c_int + 'a,
1305+
F: Fn(c_int) -> T + 'a,
1306+
{
1307+
let len = f_len();
1308+
if len >= 0 {
1309+
Some(Box::new((0..len).map(f)))
1310+
} else {
1311+
assert_eq!(len, -1); // only expect -1 as invalid
1312+
None
1313+
}
1314+
}

0 commit comments

Comments
 (0)