Skip to content

Commit 3ce3935

Browse files
committed
Add gio::FileEnumerator subclass
Signed-off-by: fbrouille <[email protected]>
1 parent 63875ab commit 3ce3935

File tree

4 files changed

+533
-0
lines changed

4 files changed

+533
-0
lines changed

gio/src/subclass/file_enumerator.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// Take a look at the license at the top of the repository in the LICENSE file.
2+
3+
use glib::{prelude::*, subclass::prelude::*, translate::*, Error};
4+
5+
use crate::{ffi, traits::FileEnumeratorExt, Cancellable, FileEnumerator, FileInfo, IOErrorEnum};
6+
7+
// Support custom implementation of virtual functions defined in `gio::ffi::GFileEnumeratorClass` except pairs `xxx_async/xxx_finish` for which GIO provides a default implementation.
8+
pub trait FileEnumeratorImpl: ObjectImpl + ObjectSubclass<Type: IsA<FileEnumerator>> {
9+
fn next_file(&self, cancellable: Option<&Cancellable>) -> Result<Option<FileInfo>, Error> {
10+
self.parent_next_file(cancellable)
11+
}
12+
13+
fn close(&self, cancellable: Option<&Cancellable>) -> Result<(), Error> {
14+
self.parent_close(cancellable)
15+
}
16+
}
17+
18+
// Support parent implementation of virtual functions defined in `gio::ffi::GFileEnumeratorClass` except pairs `xxx_async/xxx_finish` for which GIO provides a default implementation.
19+
pub trait FileEnumeratorImplExt: FileEnumeratorImpl {
20+
fn parent_next_file(
21+
&self,
22+
cancellable: Option<&Cancellable>,
23+
) -> Result<Option<FileInfo>, Error> {
24+
if self.obj().is_closed() {
25+
Err(Error::new::<IOErrorEnum>(
26+
IOErrorEnum::Closed,
27+
"Enumerator is closed",
28+
))
29+
} else {
30+
unsafe {
31+
let data = Self::type_data();
32+
let parent_class = data.as_ref().parent_class() as *const ffi::GFileEnumeratorClass;
33+
34+
let f = (*parent_class)
35+
.next_file
36+
.expect("No parent class implementation for \"next_file\"");
37+
38+
let mut error = std::ptr::null_mut();
39+
let res = f(
40+
self.obj()
41+
.unsafe_cast_ref::<FileEnumerator>()
42+
.to_glib_none()
43+
.0,
44+
cancellable.as_ref().to_glib_none().0,
45+
&mut error,
46+
);
47+
if error.is_null() {
48+
Ok(from_glib_full(res))
49+
} else {
50+
Err(from_glib_full(error))
51+
}
52+
}
53+
}
54+
}
55+
56+
fn parent_close(&self, cancellable: Option<&Cancellable>) -> Result<(), Error> {
57+
unsafe {
58+
let data = Self::type_data();
59+
let parent_class = data.as_ref().parent_class() as *const ffi::GFileEnumeratorClass;
60+
61+
let f = (*parent_class)
62+
.close_fn
63+
.expect("No parent class implementation for \"close_fn\"");
64+
65+
// get the corresponding object instance without checking the reference count because the object might just be finalized.
66+
let obj = {
67+
let offset = -data.as_ref().impl_offset();
68+
let ptr = self as *const Self as usize;
69+
let ptr = if offset < 0 {
70+
ptr - (-offset) as usize
71+
} else {
72+
ptr + offset as usize
73+
} as *const <Self::Type as ObjectType>::GlibType;
74+
glib::BorrowedObject::<Self::Type>::new(mut_override(ptr))
75+
};
76+
77+
let mut error = std::ptr::null_mut();
78+
let is_ok = f(
79+
obj.unsafe_cast_ref::<FileEnumerator>().to_glib_none().0,
80+
cancellable.as_ref().to_glib_none().0,
81+
&mut error,
82+
);
83+
debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
84+
if error.is_null() {
85+
Ok(())
86+
} else {
87+
Err(from_glib_full(error))
88+
}
89+
}
90+
}
91+
}
92+
93+
impl<T: FileEnumeratorImpl> FileEnumeratorImplExt for T {}
94+
95+
// Implement virtual functions defined in `gio::ffi::GFileEnumeratorClass` except pairs `xxx_async/xxx_finish` for which GIO provides a default implementation.
96+
unsafe impl<T: FileEnumeratorImpl> IsSubclassable<T> for FileEnumerator {
97+
fn class_init(class: &mut ::glib::Class<Self>) {
98+
Self::parent_class_init::<T>(class);
99+
100+
let klass = class.as_mut();
101+
klass.next_file = Some(next_file::<T>);
102+
klass.close_fn = Some(close_fn::<T>);
103+
// `GFileEnumerator` already implements `xxx_async/xxx_finish` vfuncs and this should be ok.
104+
// TODO: when needed, override the `GFileEnumerator` implementation of the following vfuncs:
105+
// klass.next_files_async = Some(next_files_async::<T>);
106+
// klass.next_files_finish = Some(next_files_finish::<T>);
107+
// klass.close_async = Some(close_async::<T>);
108+
// klass.close_finish = Some(close_finish::<T>);
109+
}
110+
}
111+
112+
unsafe extern "C" fn next_file<T: FileEnumeratorImpl>(
113+
enumerator: *mut ffi::GFileEnumerator,
114+
cancellable: *mut ffi::GCancellable,
115+
error: *mut *mut glib::ffi::GError,
116+
) -> *mut ffi::GFileInfo {
117+
let instance = &*(enumerator as *mut T::Instance);
118+
let imp = instance.imp();
119+
let cancellable = Option::<Cancellable>::from_glib_none(cancellable);
120+
121+
let res = imp.next_file(cancellable.as_ref());
122+
123+
match res {
124+
Ok(fileinfo) => fileinfo.to_glib_full(),
125+
Err(err) => {
126+
if !error.is_null() {
127+
*error = err.to_glib_full()
128+
}
129+
std::ptr::null_mut()
130+
}
131+
}
132+
}
133+
134+
unsafe extern "C" fn close_fn<T: FileEnumeratorImpl>(
135+
enumerator: *mut ffi::GFileEnumerator,
136+
cancellable: *mut ffi::GCancellable,
137+
error: *mut *mut glib::ffi::GError,
138+
) -> glib::ffi::gboolean {
139+
let instance = &*(enumerator as *mut T::Instance);
140+
let imp = instance.imp();
141+
let cancellable = Option::<Cancellable>::from_glib_none(cancellable);
142+
143+
let res = imp.close(cancellable.as_ref());
144+
145+
match res {
146+
Ok(_) => true.into_glib(),
147+
Err(err) => {
148+
if !error.is_null() {
149+
*error = err.to_glib_full()
150+
}
151+
false.into_glib()
152+
}
153+
}
154+
}

gio/src/subclass/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod action_group;
44
mod action_map;
55
mod application;
66
mod async_initable;
7+
mod file_enumerator;
78
mod file_monitor;
89
mod initable;
910
mod input_stream;
@@ -24,6 +25,7 @@ pub mod prelude {
2425
action_map::{ActionMapImpl, ActionMapImplExt},
2526
application::{ApplicationImpl, ApplicationImplExt},
2627
async_initable::{AsyncInitableImpl, AsyncInitableImplExt},
28+
file_enumerator::{FileEnumeratorImpl, FileEnumeratorImplExt},
2729
file_monitor::{FileMonitorImpl, FileMonitorImplExt},
2830
initable::{InitableImpl, InitableImplExt},
2931
input_stream::{InputStreamImpl, InputStreamImplExt},

0 commit comments

Comments
 (0)