gio/
file.rs

1// Copyright 2013-2017, The Gtk-rs Project Developers.
2// See the COPYRIGHT file at the top-level directory of this distribution.
3// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
4
5use gio_sys;
6use glib;
7use glib::object::IsA;
8use glib::translate::*;
9use glib_sys;
10use gobject_sys;
11use std::ptr;
12use Cancellable;
13use Error;
14use File;
15use FileCreateFlags;
16
17#[cfg(feature = "futures")]
18use futures::future;
19
20pub trait FileExtManual: Sized {
21    fn replace_contents_async<
22        B: AsRef<[u8]> + Send + 'static,
23        R: FnOnce(Result<(B, glib::GString), (B, Error)>) + Send + 'static,
24    >(
25        &self,
26        contents: B,
27        etag: Option<&str>,
28        make_backup: bool,
29        flags: FileCreateFlags,
30        cancellable: Option<&Cancellable>,
31        callback: R,
32    );
33
34    #[cfg(feature = "futures")]
35    fn replace_contents_async_future<'a, B: AsRef<[u8]> + Send + 'static>(
36        &self,
37        contents: B,
38        etag: Option<&str>,
39        make_backup: bool,
40        flags: FileCreateFlags,
41    ) -> Box<dyn future::Future<Output = Result<(B, glib::GString), (B, Error)>> + std::marker::Unpin>;
42}
43
44impl<O: IsA<File>> FileExtManual for O {
45    fn replace_contents_async<
46        B: AsRef<[u8]> + Send + 'static,
47        R: FnOnce(Result<(B, glib::GString), (B, Error)>) + Send + 'static,
48    >(
49        &self,
50        contents: B,
51        etag: Option<&str>,
52        make_backup: bool,
53        flags: FileCreateFlags,
54        cancellable: Option<&Cancellable>,
55        callback: R,
56    ) {
57        let etag = etag.to_glib_none();
58        let cancellable = cancellable.to_glib_none();
59        let user_data: Box<Option<(R, B)>> = Box::new(Some((callback, contents)));
60        // Need to do this after boxing as the contents pointer might change by moving into the box
61        let (count, contents_ptr) = {
62            let contents = &(*user_data).as_ref().unwrap().1;
63            let slice = contents.as_ref();
64            (slice.len(), slice.as_ptr())
65        };
66        unsafe extern "C" fn replace_contents_async_trampoline<
67            B: AsRef<[u8]> + Send + 'static,
68            R: FnOnce(Result<(B, glib::GString), (B, Error)>) + Send + 'static,
69        >(
70            _source_object: *mut gobject_sys::GObject,
71            res: *mut gio_sys::GAsyncResult,
72            user_data: glib_sys::gpointer,
73        ) {
74            let mut user_data: Box<Option<(R, B)>> = Box::from_raw(user_data as *mut _);
75            let (callback, contents) = user_data.take().unwrap();
76
77            let mut error = ptr::null_mut();
78            let mut new_etag = ptr::null_mut();
79            let _ = gio_sys::g_file_replace_contents_finish(
80                _source_object as *mut _,
81                res,
82                &mut new_etag,
83                &mut error,
84            );
85            let result = if error.is_null() {
86                Ok((contents, from_glib_full(new_etag)))
87            } else {
88                Err((contents, from_glib_full(error)))
89            };
90            callback(result);
91        }
92        let callback = replace_contents_async_trampoline::<B, R>;
93        unsafe {
94            gio_sys::g_file_replace_contents_async(
95                self.as_ref().to_glib_none().0,
96                mut_override(contents_ptr),
97                count,
98                etag.0,
99                make_backup.to_glib(),
100                flags.to_glib(),
101                cancellable.0,
102                Some(callback),
103                Box::into_raw(user_data) as *mut _,
104            );
105        }
106    }
107
108    #[cfg(feature = "futures")]
109    fn replace_contents_async_future<B: AsRef<[u8]> + Send + 'static>(
110        &self,
111        contents: B,
112        etag: Option<&str>,
113        make_backup: bool,
114        flags: FileCreateFlags,
115    ) -> Box<dyn future::Future<Output = Result<(B, glib::GString), (B, Error)>> + std::marker::Unpin>
116    {
117        use fragile::Fragile;
118        use GioFuture;
119
120        let etag = etag.map(glib::GString::from);
121        GioFuture::new(self, move |obj, send| {
122            let cancellable = Cancellable::new();
123            let send = Fragile::new(send);
124            obj.replace_contents_async(
125                contents,
126                etag.as_ref().map(|s| s.as_str()),
127                make_backup,
128                flags,
129                Some(&cancellable),
130                move |res| {
131                    let _ = send.into_inner().send(res);
132                },
133            );
134
135            cancellable
136        })
137    }
138}