Skip to content

Commit bbfa6db

Browse files
committed
Add gio::Vfs subclass
Signed-off-by: fbrouille <[email protected]>
1 parent b997026 commit bbfa6db

File tree

2 files changed

+306
-0
lines changed

2 files changed

+306
-0
lines changed

gio/src/subclass/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ mod list_model;
1313
mod output_stream;
1414
mod seekable;
1515
mod socket_control_message;
16+
mod vfs;
1617

1718
pub use self::application::ArgumentList;
1819

@@ -34,5 +35,6 @@ pub mod prelude {
3435
output_stream::{OutputStreamImpl, OutputStreamImplExt},
3536
seekable::{SeekableImpl, SeekableImplExt},
3637
socket_control_message::{SocketControlMessageImpl, SocketControlMessageImplExt},
38+
vfs::{VfsImpl, VfsImplExt},
3739
};
3840
}

gio/src/subclass/vfs.rs

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
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::*, GString};
4+
5+
use libc::c_char;
6+
7+
use crate::{ffi, File, Vfs};
8+
9+
pub trait VfsImpl: ObjectImpl + ObjectSubclass<Type: IsA<Vfs>> {
10+
fn is_active(&self) -> bool {
11+
self.parent_is_active()
12+
}
13+
14+
fn get_file_for_path(&self, path: &GString) -> File {
15+
self.parent_get_file_for_path(path)
16+
}
17+
18+
fn get_file_for_uri(&self, uri: &GString) -> File {
19+
self.parent_get_file_for_uri(uri)
20+
}
21+
22+
fn get_supported_uri_schemes(&self) -> Vec<GString> {
23+
self.parent_get_supported_uri_schemes()
24+
}
25+
26+
fn parse_name(&self, parse_name: &GString) -> File {
27+
self.parent_parse_name(parse_name)
28+
}
29+
}
30+
31+
pub trait VfsImplExt: VfsImpl {
32+
fn parent_is_active(&self) -> bool {
33+
unsafe {
34+
let data = Self::type_data();
35+
let parent_class = data.as_ref().parent_class() as *const ffi::GVfsClass;
36+
37+
let f = (*parent_class)
38+
.is_active
39+
.expect("No parent class implementation for \"is_active\"");
40+
41+
let res = f(self.obj().unsafe_cast_ref::<Vfs>().to_glib_none().0);
42+
from_glib(res)
43+
}
44+
}
45+
46+
fn parent_get_file_for_path(&self, path: &GString) -> File {
47+
unsafe {
48+
let data = Self::type_data();
49+
let parent_class = data.as_ref().parent_class() as *const ffi::GVfsClass;
50+
51+
let f = (*parent_class)
52+
.get_file_for_path
53+
.expect("No parent class implementation for \"get_file_for_path\"");
54+
55+
let res = f(
56+
self.obj().unsafe_cast_ref::<Vfs>().to_glib_none().0,
57+
path.to_glib_none().0,
58+
);
59+
from_glib_full(res)
60+
}
61+
}
62+
63+
fn parent_get_file_for_uri(&self, uri: &GString) -> File {
64+
unsafe {
65+
let data = Self::type_data();
66+
let parent_class = data.as_ref().parent_class() as *const ffi::GVfsClass;
67+
68+
let f = (*parent_class)
69+
.get_file_for_uri
70+
.expect("No parent class implementation for \"get_file_for_uri\"");
71+
72+
let res = f(
73+
self.obj().unsafe_cast_ref::<Vfs>().to_glib_none().0,
74+
uri.to_glib_none().0,
75+
);
76+
from_glib_full(res)
77+
}
78+
}
79+
80+
fn parent_get_supported_uri_schemes(&self) -> Vec<GString> {
81+
unsafe {
82+
let data = Self::type_data();
83+
let parent_class = data.as_ref().parent_class() as *const ffi::GVfsClass;
84+
85+
let f = (*parent_class)
86+
.get_supported_uri_schemes
87+
.expect("No parent class implementation for \"get_supported_uri_schemes\"");
88+
89+
let res = f(self.obj().unsafe_cast_ref::<Vfs>().to_glib_none().0);
90+
FromGlibPtrContainer::from_glib_none(res)
91+
}
92+
}
93+
94+
fn parent_parse_name(&self, parse_name: &GString) -> File {
95+
unsafe {
96+
let data = Self::type_data();
97+
let parent_class = data.as_ref().parent_class() as *const ffi::GVfsClass;
98+
99+
let f = (*parent_class)
100+
.parse_name
101+
.expect("No parent class implementation for \"parse_name\"");
102+
103+
let res = f(
104+
self.obj().unsafe_cast_ref::<Vfs>().to_glib_none().0,
105+
parse_name.to_glib_none().0,
106+
);
107+
from_glib_full(res)
108+
}
109+
}
110+
}
111+
112+
impl<T: VfsImpl> VfsImplExt for T {}
113+
114+
unsafe impl<T: VfsImpl> IsSubclassable<T> for Vfs {
115+
fn class_init(class: &mut ::glib::Class<Self>) {
116+
Self::parent_class_init::<T>(class);
117+
118+
let klass = class.as_mut();
119+
klass.is_active = Some(is_active::<T>);
120+
klass.get_file_for_path = Some(get_file_for_path::<T>);
121+
klass.get_file_for_uri = Some(get_file_for_uri::<T>);
122+
klass.get_supported_uri_schemes = Some(get_supported_uri_schemes::<T>);
123+
klass.parse_name = Some(parse_name::<T>);
124+
}
125+
}
126+
127+
unsafe extern "C" fn is_active<T: VfsImpl>(vfs: *mut ffi::GVfs) -> glib::ffi::gboolean {
128+
let instance = &*(vfs as *mut T::Instance);
129+
let imp = instance.imp();
130+
131+
let res = imp.is_active();
132+
133+
res.into_glib()
134+
}
135+
136+
unsafe extern "C" fn get_file_for_path<T: VfsImpl>(
137+
vfs: *mut ffi::GVfs,
138+
path: *const c_char,
139+
) -> *mut ffi::GFile {
140+
let instance = &*(vfs as *mut T::Instance);
141+
let imp = instance.imp();
142+
143+
let file = imp.get_file_for_path(&from_glib_borrow(path));
144+
145+
file.to_glib_full()
146+
}
147+
148+
unsafe extern "C" fn get_file_for_uri<T: VfsImpl>(
149+
vfs: *mut ffi::GVfs,
150+
uri: *const c_char,
151+
) -> *mut ffi::GFile {
152+
let instance = &*(vfs as *mut T::Instance);
153+
let imp = instance.imp();
154+
155+
let file = imp.get_file_for_uri(&from_glib_borrow(uri));
156+
157+
file.to_glib_full()
158+
}
159+
160+
unsafe extern "C" fn get_supported_uri_schemes<T: VfsImpl>(
161+
vfs: *mut ffi::GVfs,
162+
) -> *const *const c_char {
163+
let instance = &*(vfs as *mut T::Instance);
164+
let imp = instance.imp();
165+
166+
let supported_uri_schemes = imp.get_supported_uri_schemes();
167+
168+
supported_uri_schemes.to_glib_full()
169+
}
170+
171+
unsafe extern "C" fn parse_name<T: VfsImpl>(
172+
vfs: *mut ffi::GVfs,
173+
parse_name: *const c_char,
174+
) -> *mut ffi::GFile {
175+
let instance = &*(vfs as *mut T::Instance);
176+
let imp = instance.imp();
177+
178+
let file = imp.parse_name(&from_glib_borrow(parse_name));
179+
180+
file.to_glib_full()
181+
}
182+
183+
#[cfg(test)]
184+
mod tests {
185+
use std::cell::RefCell;
186+
use std::path::{Path, PathBuf};
187+
188+
use glib::object::ObjectSubclassIs;
189+
190+
use super::*;
191+
use crate::prelude::*;
192+
193+
mod imp {
194+
use super::*;
195+
196+
#[derive(Default)]
197+
pub struct MyVfs {
198+
pub active: RefCell<bool>,
199+
}
200+
201+
#[glib::object_subclass]
202+
impl ObjectSubclass for MyVfs {
203+
const NAME: &'static str = "MyVfs";
204+
type Type = super::MyVfs;
205+
type ParentType = Vfs;
206+
}
207+
208+
impl ObjectImpl for MyVfs {}
209+
210+
impl VfsImpl for MyVfs {
211+
fn is_active(&self) -> bool {
212+
*self.active.borrow()
213+
}
214+
215+
fn get_file_for_path(&self, path: &GString) -> File {
216+
let path = path.strip_prefix("/").unwrap_or(path);
217+
File::for_path(Path::new(&format!("/{}", Self::NAME)).join(path))
218+
}
219+
220+
fn get_file_for_uri(&self, uri: &GString) -> File {
221+
if let Some(path) = uri.to_string().strip_prefix(&format!("{}:", Self::NAME)) {
222+
self.get_file_for_path(&GString::from(path))
223+
} else {
224+
File::for_uri(uri)
225+
}
226+
}
227+
228+
fn get_supported_uri_schemes(&self) -> Vec<GString> {
229+
vec![GString::from(Self::NAME)]
230+
}
231+
232+
fn parse_name(&self, parse_name: &GString) -> File {
233+
if let Some(path) = parse_name
234+
.to_string()
235+
.strip_prefix(&format!("/{}", Self::NAME))
236+
{
237+
self.get_file_for_path(&GString::from(path))
238+
} else {
239+
File::for_parse_name(parse_name)
240+
}
241+
}
242+
}
243+
}
244+
245+
glib::wrapper! {
246+
pub struct MyVfs(ObjectSubclass<imp::MyVfs>) @extends Vfs;
247+
}
248+
249+
impl MyVfs {
250+
pub fn set_active(&self, active: bool) {
251+
self.imp().active.replace(active);
252+
}
253+
254+
pub fn uri_scheme(&self) -> &'static str {
255+
<Self as ObjectSubclassIs>::Subclass::NAME
256+
}
257+
}
258+
259+
#[test]
260+
fn test_is_active() {
261+
let vfs = glib::Object::new::<MyVfs>();
262+
vfs.set_active(true);
263+
assert!(vfs.is_active());
264+
vfs.set_active(false);
265+
assert!(!vfs.is_active());
266+
}
267+
268+
#[test]
269+
fn test_get_file_for_path() {
270+
let vfs = glib::Object::new::<MyVfs>();
271+
let file = vfs.file_for_path("/my_file");
272+
assert_eq!(
273+
file.path(),
274+
Some(PathBuf::from(&format!("/{}", vfs.uri_scheme())).join("my_file"))
275+
);
276+
}
277+
278+
#[test]
279+
fn test_get_file_for_uri() {
280+
let vfs = glib::Object::new::<MyVfs>();
281+
let file = vfs.file_for_uri(&format!("{}:/my_file", vfs.uri_scheme()));
282+
assert_eq!(
283+
file.path(),
284+
Some(PathBuf::from(&format!("/{}", vfs.uri_scheme())).join("my_file"))
285+
);
286+
}
287+
288+
#[test]
289+
fn test_get_supported_uri_schemes() {
290+
let vfs = glib::Object::new::<MyVfs>();
291+
let uri_schemes = vfs.supported_uri_schemes();
292+
assert!(uri_schemes.contains(&GString::from(vfs.uri_scheme())));
293+
}
294+
295+
#[test]
296+
fn test_parse_name() {
297+
let vfs = glib::Object::new::<MyVfs>();
298+
let file = vfs.parse_name(&format!("/{}/my_file", vfs.uri_scheme()));
299+
assert_eq!(
300+
file.path(),
301+
Some(PathBuf::from(&format!("/{}", vfs.uri_scheme())).join("my_file"))
302+
);
303+
}
304+
}

0 commit comments

Comments
 (0)