@@ -92,32 +92,36 @@ impl Drop for Dir {
92
92
}
93
93
}
94
94
95
+ fn next ( dir : & mut Dir ) -> Option < Result < Entry > > {
96
+ unsafe {
97
+ // Note: POSIX specifies that portable applications should dynamically allocate a
98
+ // buffer with room for a `d_name` field of size `pathconf(..., _PC_NAME_MAX)` plus 1
99
+ // for the NUL byte. It doesn't look like the std library does this; it just uses
100
+ // fixed-sized buffers (and libc's dirent seems to be sized so this is appropriate).
101
+ // Probably fine here too then.
102
+ let mut ent = std:: mem:: MaybeUninit :: < dirent > :: uninit ( ) ;
103
+ let mut result = ptr:: null_mut ( ) ;
104
+ if let Err ( e) = Errno :: result (
105
+ readdir_r ( dir. 0 . as_ptr ( ) , ent. as_mut_ptr ( ) , & mut result) )
106
+ {
107
+ return Some ( Err ( e) ) ;
108
+ }
109
+ if result. is_null ( ) {
110
+ return None ;
111
+ }
112
+ assert_eq ! ( result, ent. as_mut_ptr( ) ) ;
113
+ Some ( Ok ( Entry ( ent. assume_init ( ) ) ) )
114
+ }
115
+ }
116
+
95
117
#[ derive( Debug , Eq , Hash , PartialEq ) ]
96
118
pub struct Iter < ' d > ( & ' d mut Dir ) ;
97
119
98
120
impl < ' d > Iterator for Iter < ' d > {
99
121
type Item = Result < Entry > ;
100
122
101
123
fn next ( & mut self ) -> Option < Self :: Item > {
102
- unsafe {
103
- // Note: POSIX specifies that portable applications should dynamically allocate a
104
- // buffer with room for a `d_name` field of size `pathconf(..., _PC_NAME_MAX)` plus 1
105
- // for the NUL byte. It doesn't look like the std library does this; it just uses
106
- // fixed-sized buffers (and libc's dirent seems to be sized so this is appropriate).
107
- // Probably fine here too then.
108
- let mut ent = std:: mem:: MaybeUninit :: < dirent > :: uninit ( ) ;
109
- let mut result = ptr:: null_mut ( ) ;
110
- if let Err ( e) = Errno :: result (
111
- readdir_r ( ( self . 0 ) . 0 . as_ptr ( ) , ent. as_mut_ptr ( ) , & mut result) )
112
- {
113
- return Some ( Err ( e) ) ;
114
- }
115
- if result. is_null ( ) {
116
- return None ;
117
- }
118
- assert_eq ! ( result, ent. as_mut_ptr( ) ) ;
119
- Some ( Ok ( Entry ( ent. assume_init ( ) ) ) )
120
- }
124
+ next ( self . 0 )
121
125
}
122
126
}
123
127
@@ -127,6 +131,43 @@ impl<'d> Drop for Iter<'d> {
127
131
}
128
132
}
129
133
134
+ /// The return type of [Dir::into_iter]
135
+ #[ derive( Debug , Eq , Hash , PartialEq ) ]
136
+ pub struct OwningIter ( Dir ) ;
137
+
138
+ impl Iterator for OwningIter {
139
+ type Item = Result < Entry > ;
140
+
141
+ fn next ( & mut self ) -> Option < Self :: Item > {
142
+ next ( & mut self . 0 )
143
+ }
144
+ }
145
+
146
+ impl IntoIterator for Dir {
147
+ type Item = Result < Entry > ;
148
+ type IntoIter = OwningIter ;
149
+
150
+ /// Creates a owning iterator, that is, one that takes ownership of the
151
+ /// `Dir`. The `Dir` cannot be used after calling this. This can be useful
152
+ /// when you have a function that both creates a `Dir` instance and returns
153
+ /// an `Iterator`.
154
+ ///
155
+ /// Example:
156
+ ///
157
+ /// ```
158
+ /// use nix::{dir::Dir, fcntl::OFlag, sys::stat::Mode};
159
+ /// use std::{iter::Iterator, string::String};
160
+ ///
161
+ /// fn ls_upper(dirname: &str) -> impl Iterator<Item=String> {
162
+ /// let d = Dir::open(dirname, OFlag::O_DIRECTORY, Mode::S_IXUSR).unwrap();
163
+ /// d.into_iter().map(|x| x.unwrap().file_name().as_ref().to_string_lossy().to_ascii_uppercase())
164
+ /// }
165
+ /// ```
166
+ fn into_iter ( self ) -> Self :: IntoIter {
167
+ OwningIter ( self )
168
+ }
169
+ }
170
+
130
171
/// A directory entry, similar to `std::fs::DirEntry`.
131
172
///
132
173
/// Note that unlike the std version, this may represent the `.` or `..` entries.
0 commit comments