From ca27ed990972693752bb928813e77bb34a079e30 Mon Sep 17 00:00:00 2001 From: Jean-Philippe DUFRAIGNE Date: Tue, 1 Nov 2016 21:15:45 +0000 Subject: [PATCH 1/5] Provider with to iterable one optional, all defined in the same place --- src/clang.rs | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/src/clang.rs b/src/clang.rs index d69c8b14b5..fcc16aaff2 100755 --- a/src/clang.rs +++ b/src/clang.rs @@ -1170,6 +1170,157 @@ impl UnsavedFile { } } +/// Provide index results. +pub trait IndexCallable { + /// Item type for Iterator trait. + type Item; + + /// Type reprensenting the number of items. + /// If signed, only create iterator if positive. + type ItemNum; + + /// Call the function retreiving number of items. + fn fetch_item_num(&self) -> Self::ItemNum; + + /// Call the function retreiving the item for the index idx. + fn fetch_item(&mut self, idx: usize) -> Self::Item; +} + +/// Tag for unsigned integer type +pub trait UnsignedInteger {} +impl UnsignedInteger for c_uint {} + +/// Tag for signed integer type +pub trait SignedInteger {} +impl SignedInteger for c_int {} + +/// An iterator for a type's template arguments +pub struct IndexCallIterator { + cxt: CxtT, + length: usize, + index: usize +} + +impl IndexCallIterator where CxtT::ItemNum: UnsignedInteger + Into{ + fn new(cxt: CxtT) -> IndexCallIterator { + let len: u32 = cxt.fetch_item_num().into(); + IndexCallIterator { cxt: cxt, length: len as usize, index: 0 } + } +} + +impl IndexCallIterator where CxtT::ItemNum: SignedInteger + Into { + fn new_check_positive(cxt: CxtT) -> Option> { + let len: i32 = cxt.fetch_item_num().into(); + if len >= 0 { + Some( IndexCallIterator { cxt: cxt, length: len as usize, index: 0 } ) + } else { + debug_assert_eq!(len, -1); // only expect -1 as invalid + None + } + } +} + +impl Iterator for IndexCallIterator { + type Item = CxtT::Item; + fn next(&mut self) -> Option { + if self.index < self.length { + let idx = self.index; + self.index += 1; + Some(self.cxt.fetch_item(idx)) + } else { + None + } + } +} + +impl ExactSizeIterator for IndexCallIterator { + fn len(&self) -> usize { + assert!(self.index <= self.length); + self.length - self.index + } +} + +struct TestIndexCallableProvider { + cxtu: c_uint, + cxti: c_int +} + +impl TestIndexCallableProvider { + fn get_unsigned_children(self) -> IndexCallIterator + { + let idx_callable = TestIndexCallable { cxt: self.cxtu }; + IndexCallIterator::new( idx_callable ) + } + + fn get_signed_children(self) -> Option> + { + let idx_callable = TestIndexCallableOption { cxt: self.cxti }; + IndexCallIterator::new_check_positive( idx_callable ) + } +} + +struct TestIndexCallable { + cxt: c_uint // FFI function context +} + +impl IndexCallable for TestIndexCallable { + type Item = i32; + type ItemNum = c_uint; + + fn fetch_item_num(&self) -> Self::ItemNum { + self.cxt // call specific FFI function + } + + fn fetch_item(&mut self, idx: usize) -> Self::Item { + idx as i32 // call specific FFI function + } +} + + +struct TestIndexCallableOption { + cxt: c_int // FFI function context +} + +impl IndexCallable for TestIndexCallableOption { + type Item = i32; + type ItemNum = c_int; + + fn fetch_item_num(&self) -> Self::ItemNum { + return self.cxt // call specific FFI function + } + + fn fetch_item(&mut self, idx: usize) -> Self::Item { + idx as i32 // call specific FFI function + } +} + +#[test] +fn test_index_call_iterator() { + let provider = TestIndexCallableProvider{ cxti: 3, cxtu: 2}; + + let values = provider.get_unsigned_children(); + let len = values.len(); + let collected = values.collect::>(); + + assert_eq!(collected, vec![0,1]); + assert_eq!(len, 2); +} + +#[test] +fn test_optional_index_call_iterator() { + let provider = TestIndexCallableProvider{ cxti: 2, cxtu: 3}; + let provider_no_children = TestIndexCallableProvider{ cxti: -1, cxtu: 3}; + + let values = provider.get_signed_children(); + let not_values = provider_no_children.get_signed_children(); + let len = values.as_ref().map(|x| x.len()); + let collected = values.map(|x| x.collect::>()); + + assert_eq!(collected, Some(vec![0,1])); + assert_eq!(len, Some(2)); + assert!(not_values.is_none()); +} + /// Convert a cursor kind into a static string. pub fn kind_to_str(x: Enum_CXCursorKind) -> &'static str { match x { From 27490f25b2e70ab811b0a82d788811061506fc04 Mon Sep 17 00:00:00 2001 From: Jean-Philippe DUFRAIGNE Date: Tue, 1 Nov 2016 21:27:16 +0000 Subject: [PATCH 2/5] Provide an extra num parameter giving back what fetch_item_num gave This allow each implmentation to panic if called with incorrect values, assuming the trait function is called with the acutal result from fetch_item_num --- src/clang.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/clang.rs b/src/clang.rs index fcc16aaff2..0b4e98c8b7 100755 --- a/src/clang.rs +++ b/src/clang.rs @@ -1183,7 +1183,9 @@ pub trait IndexCallable { fn fetch_item_num(&self) -> Self::ItemNum; /// Call the function retreiving the item for the index idx. - fn fetch_item(&mut self, idx: usize) -> Self::Item; + /// This will always be called with 0 <= idx < num. + /// num will always be the value converted from fetch_item_num. + fn fetch_item(&mut self, idx: usize, num: usize) -> Self::Item; } /// Tag for unsigned integer type @@ -1226,7 +1228,7 @@ impl Iterator for IndexCallIterator { if self.index < self.length { let idx = self.index; self.index += 1; - Some(self.cxt.fetch_item(idx)) + Some(self.cxt.fetch_item(idx, self.length)) } else { None } @@ -1240,6 +1242,9 @@ impl ExactSizeIterator for IndexCallIterator { } } +// +// Start test code +// struct TestIndexCallableProvider { cxtu: c_uint, cxti: c_int @@ -1271,7 +1276,8 @@ impl IndexCallable for TestIndexCallable { self.cxt // call specific FFI function } - fn fetch_item(&mut self, idx: usize) -> Self::Item { + fn fetch_item(&mut self, idx: usize, num: usize) -> Self::Item { + assert!(idx < num); idx as i32 // call specific FFI function } } @@ -1289,7 +1295,8 @@ impl IndexCallable for TestIndexCallableOption { return self.cxt // call specific FFI function } - fn fetch_item(&mut self, idx: usize) -> Self::Item { + fn fetch_item(&mut self, idx: usize, num: usize) -> Self::Item { + assert!(idx < num); idx as i32 // call specific FFI function } } @@ -1321,6 +1328,10 @@ fn test_optional_index_call_iterator() { assert!(not_values.is_none()); } +// +// End test code +// + /// Convert a cursor kind into a static string. pub fn kind_to_str(x: Enum_CXCursorKind) -> &'static str { match x { From ab0017c5ea14b3fc05b1dfe2d86f51321d5979f3 Mon Sep 17 00:00:00 2001 From: Jean-Philippe DUFRAIGNE Date: Tue, 1 Nov 2016 21:54:56 +0000 Subject: [PATCH 3/5] Update clang::type::template_args to use new generic --- src/clang.rs | 46 ++++++++++++++-------------------------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/src/clang.rs b/src/clang.rs index 0b4e98c8b7..737652292c 100755 --- a/src/clang.rs +++ b/src/clang.rs @@ -641,18 +641,9 @@ impl Type { /// If this type is a class template specialization, return its /// template arguments. Otherwise, return None. - pub fn template_args(&self) -> Option { - let n = unsafe { clang_Type_getNumTemplateArguments(self.x) }; - if n >= 0 { - Some(TypeTemplateArgIterator { - x: self.x, - length: n as u32, - index: 0, - }) - } else { - debug_assert_eq!(n, -1); - None - } + pub fn template_args(&self) -> Option> { + IndexCallIterator::new_check_positive( + TypeTemplateArgIndexCallable { x: self.x } ) } /// Given that this type is a pointer type, return the type that it points @@ -751,31 +742,22 @@ impl Type { } /// An iterator for a type's template arguments. -pub struct TypeTemplateArgIterator { - x: CXType, - length: u32, - index: u32, +pub struct TypeTemplateArgIndexCallable { + x: CXType } -impl Iterator for TypeTemplateArgIterator { +impl IndexCallable for TypeTemplateArgIndexCallable { type Item = Type; - fn next(&mut self) -> Option { - if self.index < self.length { - let idx = self.index as c_int; - self.index += 1; - Some(Type { - x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, idx) }, - }) - } else { - None - } + type ItemNum = c_int; + + fn fetch_item_num(&self) -> Self::ItemNum { + unsafe { clang_Type_getNumTemplateArguments(self.x) } } -} -impl ExactSizeIterator for TypeTemplateArgIterator { - fn len(&self) -> usize { - assert!(self.index <= self.length); - (self.length - self.index) as usize + fn fetch_item(&mut self, idx: usize, num: usize) -> Self::Item { + assert!(idx < num); + let i = idx as Self::ItemNum; + Type { x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, i) } } } } From 70269eba728650e1b6ca882c5447a49f40e63c34 Mon Sep 17 00:00:00 2001 From: Jean-Philippe DUFRAIGNE Date: Tue, 1 Nov 2016 22:03:46 +0000 Subject: [PATCH 4/5] Update clang::Comment::get_children to use IndexCallable --- src/clang.rs | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/src/clang.rs b/src/clang.rs index 737652292c..2adacad5d0 100755 --- a/src/clang.rs +++ b/src/clang.rs @@ -640,7 +640,7 @@ impl Type { } /// If this type is a class template specialization, return its - /// template arguments. Otherwise, return None. + /// template arguments . Otherwise, return None. pub fn template_args(&self) -> Option> { IndexCallIterator::new_check_positive( TypeTemplateArgIndexCallable { x: self.x } ) @@ -816,12 +816,8 @@ impl Comment { } /// Get this comment's children comment - pub fn get_children(&self) -> CommentChildrenIterator { - CommentChildrenIterator { - parent: self.x, - length: unsafe { clang_Comment_getNumChildren(self.x) }, - index: 0, - } + pub fn get_children(&self) -> IndexCallIterator { + IndexCallIterator::new(CommentChildrenIndexCallable { x: self.x }) } /// Given that this comment is the start or end of an HTML tag, get its tag @@ -841,24 +837,22 @@ impl Comment { } /// An iterator for a comment's children -pub struct CommentChildrenIterator { - parent: CXComment, - length: c_uint, - index: c_uint, +pub struct CommentChildrenIndexCallable { + x: CXComment } -impl Iterator for CommentChildrenIterator { +impl IndexCallable for CommentChildrenIndexCallable { type Item = Comment; - fn next(&mut self) -> Option { - if self.index < self.length { - let idx = self.index; - self.index += 1; - Some(Comment { - x: unsafe { clang_Comment_getChild(self.parent, idx) }, - }) - } else { - None - } + type ItemNum = c_uint; + + fn fetch_item_num(&self) -> Self::ItemNum { + unsafe { clang_Comment_getNumChildren(self.x) } + } + + fn fetch_item(&mut self, idx: usize, num: usize) -> Self::Item { + assert!(idx < num); + let i = idx as Self::ItemNum; + Comment { x: unsafe { clang_Comment_getChild(self.x, i) } } } } From de31ed178398bb92ff859dde155bc0729b6b545a Mon Sep 17 00:00:00 2001 From: Jean-Philippe DUFRAIGNE Date: Tue, 1 Nov 2016 22:43:12 +0000 Subject: [PATCH 5/5] update clang::Comment::get_tag_attrs() to use new pattern --- src/clang.rs | 46 +++++++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/src/clang.rs b/src/clang.rs index 2adacad5d0..fa4524e3f8 100755 --- a/src/clang.rs +++ b/src/clang.rs @@ -827,12 +827,8 @@ impl Comment { } /// Given that this comment is an HTML start tag, get its attributes. - pub fn get_tag_attrs(&self) -> CommentAttributesIterator { - CommentAttributesIterator { - x: self.x, - length: unsafe { clang_HTMLStartTag_getNumAttrs(self.x) }, - index: 0, - } + pub fn get_tag_attrs(&self) -> IndexCallIterator { + IndexCallIterator::new(CommentAttributesIndexCallable { x: self.x }) } } @@ -865,28 +861,28 @@ pub struct CommentAttribute { } /// An iterator for a comment's attributes -pub struct CommentAttributesIterator { - x: CXComment, - length: c_uint, - index: c_uint, +pub struct CommentAttributesIndexCallable { + x: CXComment } -impl Iterator for CommentAttributesIterator { +impl IndexCallable for CommentAttributesIndexCallable { type Item = CommentAttribute; - fn next(&mut self) -> Option { - if self.index < self.length { - let idx = self.index; - self.index += 1; - Some(CommentAttribute { - name: unsafe { - clang_HTMLStartTag_getAttrName(self.x, idx).into() - }, - value: unsafe { - clang_HTMLStartTag_getAttrValue(self.x, idx).into() - }, - }) - } else { - None + type ItemNum = c_uint; + + fn fetch_item_num(&self) -> Self::ItemNum { + unsafe { clang_HTMLStartTag_getNumAttrs(self.x) } + } + + fn fetch_item(&mut self, idx: usize, num: usize) -> Self::Item { + assert!(idx < num); + let i = idx as Self::ItemNum; + CommentAttribute { + name: unsafe { + clang_HTMLStartTag_getAttrName(self.x, i).into() + }, + value: unsafe { + clang_HTMLStartTag_getAttrValue(self.x, i).into() + } } } }