Skip to content

Commit bd715b5

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 likely support unboxed closure at which point the Box can be replaced if needed and appropriate.
1 parent f498903 commit bd715b5

File tree

1 file changed

+64
-101
lines changed

1 file changed

+64
-101
lines changed

src/clang.rs

Lines changed: 64 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -623,18 +623,16 @@ impl Type {
623623

624624
/// If this type is a class template specialization, return its
625625
/// template arguments. Otherwise, return None.
626-
pub fn template_args(&self) -> Option<TypeTemplateArgIterator> {
627-
let n = unsafe { clang_Type_getNumTemplateArguments(self.x) };
628-
if n >= 0 {
629-
Some(TypeTemplateArgIterator {
630-
x: self.x,
631-
length: n as u32,
632-
index: 0,
633-
})
634-
} else {
635-
debug_assert_eq!(n, -1);
636-
None
637-
}
626+
pub fn template_args(&self) -> Option<Box<ExactSizeIterator<Item = Type>>> {
627+
let x = self.x;
628+
let f_len = || unsafe { clang_Type_getNumTemplateArguments(x) };
629+
let f = move |i| {
630+
Type {
631+
x: unsafe { clang_Type_getTemplateArgumentAsType(x, i) },
632+
}
633+
};
634+
635+
ffi_call_index_iterator_check_positive(f_len, f)
638636
}
639637

640638
/// Given that this type is a pointer type, return the type that it points
@@ -717,35 +715,6 @@ impl Type {
717715
}
718716
}
719717

720-
/// An iterator for a type's template arguments.
721-
pub struct TypeTemplateArgIterator {
722-
x: CXType,
723-
length: u32,
724-
index: u32,
725-
}
726-
727-
impl Iterator for TypeTemplateArgIterator {
728-
type Item = Type;
729-
fn next(&mut self) -> Option<Type> {
730-
if self.index < self.length {
731-
let idx = self.index as c_int;
732-
self.index += 1;
733-
Some(Type {
734-
x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, idx) },
735-
})
736-
} else {
737-
None
738-
}
739-
}
740-
}
741-
742-
impl ExactSizeIterator for TypeTemplateArgIterator {
743-
fn len(&self) -> usize {
744-
assert!(self.index <= self.length);
745-
(self.length - self.index) as usize
746-
}
747-
}
748-
749718
/// A `SourceLocation` is a file, line, column, and byte offset location for
750719
/// some source text.
751720
pub struct SourceLocation {
@@ -801,12 +770,16 @@ impl Comment {
801770
}
802771

803772
/// Get this comment's children comment
804-
pub fn get_children(&self) -> CommentChildrenIterator {
805-
CommentChildrenIterator {
806-
parent: self.x,
807-
length: unsafe { clang_Comment_getNumChildren(self.x) },
808-
index: 0,
809-
}
773+
pub fn get_children(&self) -> Box<ExactSizeIterator<Item = Comment>> {
774+
let x = self.x;
775+
let f_len = || unsafe { clang_Comment_getNumChildren(x) };
776+
let f = move |i| {
777+
Comment {
778+
x: unsafe { clang_Comment_getChild(x, i) },
779+
}
780+
};
781+
782+
ffi_call_index_iterator(f_len, f)
810783
}
811784

812785
/// Given that this comment is the start or end of an HTML tag, get its tag
@@ -816,34 +789,18 @@ impl Comment {
816789
}
817790

818791
/// Given that this comment is an HTML start tag, get its attributes.
819-
pub fn get_tag_attrs(&self) -> CommentAttributesIterator {
820-
CommentAttributesIterator {
821-
x: self.x,
822-
length: unsafe { clang_HTMLStartTag_getNumAttrs(self.x) },
823-
index: 0,
824-
}
825-
}
826-
}
827-
828-
/// An iterator for a comment's children
829-
pub struct CommentChildrenIterator {
830-
parent: CXComment,
831-
length: c_uint,
832-
index: c_uint,
833-
}
792+
pub fn get_tag_attrs(&self)
793+
-> Box<ExactSizeIterator<Item = CommentAttribute>> {
794+
let x = self.x;
795+
let f_len = || unsafe { clang_HTMLStartTag_getNumAttrs(x) };
796+
let f = move |i| {
797+
CommentAttribute {
798+
name: unsafe { clang_HTMLStartTag_getAttrName(x, i).into() },
799+
value: unsafe { clang_HTMLStartTag_getAttrValue(x, i).into() },
800+
}
801+
};
834802

835-
impl Iterator for CommentChildrenIterator {
836-
type Item = Comment;
837-
fn next(&mut self) -> Option<Comment> {
838-
if self.index < self.length {
839-
let idx = self.index;
840-
self.index += 1;
841-
Some(Comment {
842-
x: unsafe { clang_Comment_getChild(self.parent, idx) },
843-
})
844-
} else {
845-
None
846-
}
803+
ffi_call_index_iterator(f_len, f)
847804
}
848805
}
849806

@@ -855,33 +812,6 @@ pub struct CommentAttribute {
855812
pub value: String,
856813
}
857814

858-
/// An iterator for a comment's attributes
859-
pub struct CommentAttributesIterator {
860-
x: CXComment,
861-
length: c_uint,
862-
index: c_uint,
863-
}
864-
865-
impl Iterator for CommentAttributesIterator {
866-
type Item = CommentAttribute;
867-
fn next(&mut self) -> Option<CommentAttribute> {
868-
if self.index < self.length {
869-
let idx = self.index;
870-
self.index += 1;
871-
Some(CommentAttribute {
872-
name: unsafe {
873-
clang_HTMLStartTag_getAttrName(self.x, idx).into()
874-
},
875-
value: unsafe {
876-
clang_HTMLStartTag_getAttrValue(self.x, idx).into()
877-
},
878-
})
879-
} else {
880-
None
881-
}
882-
}
883-
}
884-
885815
/// A source file.
886816
pub struct File {
887817
x: CXFile,
@@ -1172,3 +1102,36 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> Enum_CXVisitorResult {
11721102
pub fn extract_clang_version() -> String {
11731103
unsafe { clang_getClangVersion().into() }
11741104
}
1105+
1106+
/// Provide a boxed iterator for foreign function call
1107+
/// Iterate over 0..f_len() and map using f
1108+
/// This function can be used with c_uint index
1109+
fn ffi_call_index_iterator<'a, FLen, F, T>
1110+
(f_len: FLen,
1111+
f: F)
1112+
-> Box<ExactSizeIterator<Item = T> + 'a>
1113+
where F: Fn(c_uint) -> T + 'a,
1114+
FLen: Fn() -> c_uint,
1115+
{
1116+
Box::new((0..f_len()).map(f))
1117+
}
1118+
1119+
/// Provide an option boxed iterator for foreign function call
1120+
/// Iterate over 0..f_len() and map using f
1121+
/// This function can be used with c_int index and only
1122+
/// returns an iterator if f_len() is positive.
1123+
fn ffi_call_index_iterator_check_positive<'a, FLen, F, T>
1124+
(f_len: FLen,
1125+
f: F)
1126+
-> Option<Box<ExactSizeIterator<Item = T> + 'a>>
1127+
where F: Fn(c_int) -> T + 'a,
1128+
FLen: Fn() -> c_int,
1129+
{
1130+
let len = f_len();
1131+
if len >= 0 {
1132+
Some(Box::new((0..len).map(f)))
1133+
} else {
1134+
assert_eq!(len, -1); // only expect -1 as invalid
1135+
None
1136+
}
1137+
}

0 commit comments

Comments
 (0)