@@ -23,8 +23,39 @@ pub struct ConfigEntry<'cfg> {
2323}
2424
2525/// An iterator over the `ConfigEntry` values of a `Config` structure.
26+ ///
27+ /// Due to lifetime restrictions, `ConfigEntries` does not implement the
28+ /// standard [`Iterator`] trait. It provides a [`next`] function which only
29+ /// allows access to one entry at a time. [`for_each`] is available as a
30+ /// convenience function.
31+ ///
32+ /// [`next`]: ConfigEntries::next
33+ /// [`for_each`]: ConfigEntries::for_each
34+ ///
35+ /// # Example
36+ ///
37+ /// ```
38+ /// // Example of how to collect all entries.
39+ /// use git2::Config;
40+ ///
41+ /// let config = Config::new()?;
42+ /// let iter = config.entries(None)?;
43+ /// let mut entries = Vec::new();
44+ /// iter
45+ /// .for_each(|entry| {
46+ /// let name = entry.name().unwrap().to_string();
47+ /// let value = entry.value().unwrap_or("").to_string();
48+ /// entries.push((name, value))
49+ /// })?;
50+ /// for entry in &entries {
51+ /// println!("{} = {}", entry.0, entry.1);
52+ /// }
53+ /// # Ok::<(), git2::Error>(())
54+ ///
55+ /// ```
2656pub struct ConfigEntries < ' cfg > {
2757 raw : * mut raw:: git_config_iterator ,
58+ current : Option < ConfigEntry < ' cfg > > ,
2859 _marker : marker:: PhantomData < & ' cfg Config > ,
2960}
3061
@@ -280,15 +311,18 @@ impl Config {
280311 /// the variable name: the section and variable parts are lower-cased. The
281312 /// subsection is left unchanged.
282313 ///
314+ /// Due to lifetime restrictions, the returned value does not implement
315+ /// the standard [`Iterator`] trait. See [`ConfigEntries`] for more.
316+ ///
283317 /// # Example
284318 ///
285319 /// ```
286- /// # #![allow(unstable)]
287320 /// use git2::Config;
288321 ///
289322 /// let cfg = Config::new().unwrap();
290323 ///
291- /// for entry in &cfg.entries(None).unwrap() {
324+ /// let mut entries = cfg.entries(None).unwrap();
325+ /// while let Some(entry) = entries.next() {
292326 /// let entry = entry.unwrap();
293327 /// println!("{} => {}", entry.name().unwrap(), entry.value().unwrap());
294328 /// }
@@ -317,6 +351,9 @@ impl Config {
317351 /// The regular expression is applied case-sensitively on the normalized form of
318352 /// the variable name: the section and variable parts are lower-cased. The
319353 /// subsection is left unchanged.
354+ ///
355+ /// Due to lifetime restrictions, the returned value does not implement
356+ /// the standard [`Iterator`] trait. See [`ConfigEntries`] for more.
320357 pub fn multivar ( & self , name : & str , regexp : Option < & str > ) -> Result < ConfigEntries < ' _ > , Error > {
321358 let mut ret = ptr:: null_mut ( ) ;
322359 let name = CString :: new ( name) ?;
@@ -550,6 +587,7 @@ impl<'cfg> Binding for ConfigEntries<'cfg> {
550587 unsafe fn from_raw ( raw : * mut raw:: git_config_iterator ) -> ConfigEntries < ' cfg > {
551588 ConfigEntries {
552589 raw,
590+ current : None ,
553591 _marker : marker:: PhantomData ,
554592 }
555593 }
@@ -558,24 +596,33 @@ impl<'cfg> Binding for ConfigEntries<'cfg> {
558596 }
559597}
560598
561- // entries are only valid until the iterator is freed, so this impl is for
562- // `&'b T` instead of `T` to have a lifetime to tie them to.
563- //
564- // It's also not implemented for `&'b mut T` so we can have multiple entries
565- // (ok).
566- impl < ' cfg , ' b > Iterator for & ' b ConfigEntries < ' cfg > {
567- type Item = Result < ConfigEntry < ' b > , Error > ;
568- fn next ( & mut self ) -> Option < Result < ConfigEntry < ' b > , Error > > {
599+ impl < ' cfg > ConfigEntries < ' cfg > {
600+ /// Advances the iterator and returns the next value.
601+ ///
602+ /// Returns `None` when iteration is finished.
603+ pub fn next ( & mut self ) -> Option < Result < & ConfigEntry < ' cfg > , Error > > {
569604 let mut raw = ptr:: null_mut ( ) ;
605+ drop ( self . current . take ( ) ) ;
570606 unsafe {
571607 try_call_iter ! ( raw:: git_config_next( & mut raw, self . raw) ) ;
572- Some ( Ok ( ConfigEntry {
608+ let entry = ConfigEntry {
573609 owned : false ,
574610 raw,
575611 _marker : marker:: PhantomData ,
576- } ) )
612+ } ;
613+ self . current = Some ( entry) ;
614+ Some ( Ok ( self . current . as_ref ( ) . unwrap ( ) ) )
577615 }
578616 }
617+
618+ /// Calls the given closure for each remaining entry in the iterator.
619+ pub fn for_each < F : FnMut ( & ConfigEntry < ' cfg > ) > ( mut self , mut f : F ) -> Result < ( ) , Error > {
620+ while let Some ( entry) = self . next ( ) {
621+ let entry = entry?;
622+ f ( entry) ;
623+ }
624+ Ok ( ( ) )
625+ }
579626}
580627
581628impl < ' cfg > Drop for ConfigEntries < ' cfg > {
@@ -628,7 +675,8 @@ mod tests {
628675 assert_eq ! ( cfg. get_i64( "foo.k3" ) . unwrap( ) , 2 ) ;
629676 assert_eq ! ( cfg. get_str( "foo.k4" ) . unwrap( ) , "bar" ) ;
630677
631- for entry in & cfg. entries ( None ) . unwrap ( ) {
678+ let mut entries = cfg. entries ( None ) . unwrap ( ) ;
679+ while let Some ( entry) = entries. next ( ) {
632680 let entry = entry. unwrap ( ) ;
633681 entry. name ( ) ;
634682 entry. value ( ) ;
@@ -649,39 +697,42 @@ mod tests {
649697 cfg. set_multivar ( "foo.baz" , "^$" , "oki" ) . unwrap ( ) ;
650698
651699 // `entries` filters by name
652- let mut entries: Vec < String > = cfg
653- . entries ( Some ( "foo.bar" ) )
700+ let mut entries: Vec < String > = Vec :: new ( ) ;
701+ cfg . entries ( Some ( "foo.bar" ) )
654702 . unwrap ( )
655- . into_iter ( )
656- . map ( |entry| entry. unwrap ( ) . value ( ) . unwrap ( ) . into ( ) )
657- . collect ( ) ;
703+ . for_each ( |entry| entries. push ( entry. value ( ) . unwrap ( ) . to_string ( ) ) )
704+ . unwrap ( ) ;
658705 entries. sort ( ) ;
659706 assert_eq ! ( entries, [ "baz" , "quux" , "qux" ] ) ;
660707
661708 // which is the same as `multivar` without a regex
662- let mut multivals: Vec < String > = cfg
663- . multivar ( "foo.bar" , None )
709+ let mut multivals = Vec :: new ( ) ;
710+ cfg . multivar ( "foo.bar" , None )
664711 . unwrap ( )
665- . into_iter ( )
666- . map ( |entry| entry. unwrap ( ) . value ( ) . unwrap ( ) . into ( ) )
667- . collect ( ) ;
712+ . for_each ( |entry| multivals. push ( entry. value ( ) . unwrap ( ) . to_string ( ) ) )
713+ . unwrap ( ) ;
668714 multivals. sort ( ) ;
669715 assert_eq ! ( multivals, entries) ;
670716
671717 // yet _with_ a regex, `multivar` filters by value
672- let mut quxish: Vec < String > = cfg
673- . multivar ( "foo.bar" , Some ( "qu.*x" ) )
718+ let mut quxish = Vec :: new ( ) ;
719+ cfg . multivar ( "foo.bar" , Some ( "qu.*x" ) )
674720 . unwrap ( )
675- . into_iter ( )
676- . map ( |entry| entry. unwrap ( ) . value ( ) . unwrap ( ) . into ( ) )
677- . collect ( ) ;
721+ . for_each ( |entry| quxish. push ( entry. value ( ) . unwrap ( ) . to_string ( ) ) )
722+ . unwrap ( ) ;
678723 quxish. sort ( ) ;
679724 assert_eq ! ( quxish, [ "quux" , "qux" ] ) ;
680725
681726 cfg. remove_multivar ( "foo.bar" , ".*" ) . unwrap ( ) ;
682727
683- assert_eq ! ( cfg. entries( Some ( "foo.bar" ) ) . unwrap( ) . count( ) , 0 ) ;
684- assert_eq ! ( cfg. multivar( "foo.bar" , None ) . unwrap( ) . count( ) , 0 ) ;
728+ let count = |entries : super :: ConfigEntries < ' _ > | -> usize {
729+ let mut c = 0 ;
730+ entries. for_each ( |_| c += 1 ) . unwrap ( ) ;
731+ c
732+ } ;
733+
734+ assert_eq ! ( count( cfg. entries( Some ( "foo.bar" ) ) . unwrap( ) ) , 0 ) ;
735+ assert_eq ! ( count( cfg. multivar( "foo.bar" , None ) . unwrap( ) ) , 0 ) ;
685736 }
686737
687738 #[ test]
0 commit comments