From 5059cf59c6bff41c4858b4c3725d43a157f38805 Mon Sep 17 00:00:00 2001 From: fbrouille Date: Sun, 18 May 2025 17:52:13 +0000 Subject: [PATCH 1/2] Implement gio::File::set_attribute Signed-off-by: fbrouille --- gio/src/file.rs | 33 ++++++++- gio/src/file_attribute_value.rs | 126 ++++++++++++++++++++++++++++++++ gio/src/lib.rs | 2 + 3 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 gio/src/file_attribute_value.rs diff --git a/gio/src/file.rs b/gio/src/file.rs index 9085c60f7e5b..52ab7b94bd42 100644 --- a/gio/src/file.rs +++ b/gio/src/file.rs @@ -6,7 +6,9 @@ use glib::{prelude::*, translate::*}; #[cfg(feature = "v2_74")] use crate::FileIOStream; -use crate::{ffi, Cancellable, File, FileCreateFlags, FileEnumerator, FileQueryInfoFlags}; +use crate::{ + ffi, Cancellable, File, FileAttributeValue, FileCreateFlags, FileEnumerator, FileQueryInfoFlags, +}; impl File { #[cfg(feature = "v2_74")] @@ -1111,6 +1113,35 @@ pub trait FileExtManual: IsA + Sized { (fut, Box::pin(receiver)) } + + #[doc(alias = "g_file_set_attribute")] + fn set_attribute<'a>( + &self, + attribute: &str, + value: impl Into>, + flags: FileQueryInfoFlags, + cancellable: Option<&impl IsA>, + ) -> Result<(), glib::Error> { + unsafe { + let mut error = std::ptr::null_mut(); + let value: FileAttributeValue<'a> = value.into(); + let is_ok = ffi::g_file_set_attribute( + self.as_ref().to_glib_none().0, + attribute.to_glib_none().0, + value.type_().into_glib(), + value.as_ptr(), + flags.into_glib(), + cancellable.map(|p| p.as_ref()).to_glib_none().0, + &mut error, + ); + debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null()); + if error.is_null() { + Ok(()) + } else { + Err(from_glib_full(error)) + } + } + } } impl> FileExtManual for O {} diff --git a/gio/src/file_attribute_value.rs b/gio/src/file_attribute_value.rs new file mode 100644 index 000000000000..d87ed2678cdb --- /dev/null +++ b/gio/src/file_attribute_value.rs @@ -0,0 +1,126 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use glib::{ + object::ObjectType, + translate::{IntoGlib, ToGlibPtr}, +}; + +use crate::FileAttributeType; + +use std::ffi::CStr; + +#[derive(Debug)] +pub struct FileAttributeValue<'a>(FileAttributeValueInner<'a>); + +impl From<&str> for FileAttributeValue<'_> { + fn from(value: &str) -> Self { + Self(FileAttributeValueInner::String( + ToGlibPtr::<*mut libc::c_char>::to_glib_none(value).1, + )) + } +} + +impl<'a> From<&'a CStr> for FileAttributeValue<'a> { + fn from(value: &'a CStr) -> Self { + Self(FileAttributeValueInner::ByteString(value)) + } +} + +impl From for FileAttributeValue<'_> { + fn from(value: bool) -> Self { + Self(FileAttributeValueInner::Boolean(value.into_glib())) + } +} + +impl From for FileAttributeValue<'_> { + fn from(value: u32) -> Self { + Self(FileAttributeValueInner::Uint32(value)) + } +} + +impl From for FileAttributeValue<'_> { + fn from(value: i32) -> Self { + Self(FileAttributeValueInner::Int32(value)) + } +} + +impl From for FileAttributeValue<'_> { + fn from(value: u64) -> Self { + Self(FileAttributeValueInner::Uint64(value)) + } +} + +impl From for FileAttributeValue<'_> { + fn from(value: i64) -> Self { + Self(FileAttributeValueInner::Int64(value)) + } +} + +impl<'a, T: AsRef> From<&'a T> for FileAttributeValue<'a> { + fn from(value: &'a T) -> Self { + Self(FileAttributeValueInner::Object(value.as_ref())) + } +} + +impl<'a> From<&'a [&str]> for FileAttributeValue<'a> { + fn from(value: &'a [&str]) -> Self { + Self(FileAttributeValueInner::Stringv(value.into())) + } +} + +impl FileAttributeValue<'_> { + pub(crate) fn type_(&self) -> FileAttributeType { + self.0.type_() + } + + pub(crate) fn as_ptr(&self) -> glib::ffi::gpointer { + self.0.as_ptr() + } +} + +#[derive(Debug)] +pub(crate) enum FileAttributeValueInner<'a> { + #[allow(dead_code)] // TODO remove this allow attribute when Pointer will be used by this crate + Pointer(FileAttributeType, glib::ffi::gpointer), + String(<&'a str as ToGlibPtr<'a, *mut libc::c_char>>::Storage), + ByteString(&'a CStr), + Boolean(glib::ffi::gboolean), + Uint32(u32), + Int32(i32), + Uint64(u64), + Int64(i64), + Object(&'a glib::Object), + Stringv(glib::StrV), +} + +impl FileAttributeValueInner<'_> { + pub(crate) fn type_(&self) -> FileAttributeType { + match self { + Self::Pointer(type_, _) => *type_, + Self::String(_) => FileAttributeType::String, + Self::ByteString(_) => FileAttributeType::ByteString, + Self::Boolean(_) => FileAttributeType::Boolean, + Self::Uint32(_) => FileAttributeType::Uint32, + Self::Int32(_) => FileAttributeType::Int32, + Self::Uint64(_) => FileAttributeType::Uint64, + Self::Int64(_) => FileAttributeType::Int64, + Self::Object(_) => FileAttributeType::Object, + Self::Stringv(_) => FileAttributeType::Stringv, + } + } + + pub(crate) fn as_ptr(&self) -> glib::ffi::gpointer { + match self { + Self::Pointer(_, s) => *s, + Self::String(s) => s.as_ptr() as _, + Self::ByteString(s) => s.as_ptr() as _, + Self::Boolean(s) => s as *const i32 as _, + Self::Uint32(s) => s as *const u32 as _, + Self::Int32(s) => s as *const i32 as _, + Self::Uint64(s) => s as *const u64 as _, + Self::Int64(s) => s as *const i64 as _, + Self::Object(s) => s.as_ptr() as _, + Self::Stringv(s) => s.as_ptr() as _, + } + } +} diff --git a/gio/src/lib.rs b/gio/src/lib.rs index f11e3fb2338a..eb7e6fd0a48d 100644 --- a/gio/src/lib.rs +++ b/gio/src/lib.rs @@ -49,6 +49,8 @@ pub use crate::file_attribute_info::FileAttributeInfo; mod file_attribute_info_list; mod file_attribute_matcher; pub use crate::file_attribute_matcher::FileAttributematcherIter; +mod file_attribute_value; +pub use file_attribute_value::FileAttributeValue; #[cfg(unix)] mod file_descriptor_based; #[cfg(unix)] From ed44365586f8e5273b8a44fbcc276afe9b2f9621 Mon Sep 17 00:00:00 2001 From: fbrouille Date: Sun, 18 May 2025 17:57:12 +0000 Subject: [PATCH 2/2] Implement gio::FileInfo::set_attribute Closes #40 Signed-off-by: fbrouille --- gio/src/file_info.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/gio/src/file_info.rs b/gio/src/file_info.rs index 9c7297b90bda..c17cbafead16 100644 --- a/gio/src/file_info.rs +++ b/gio/src/file_info.rs @@ -7,7 +7,7 @@ use std::{ use glib::{translate::*, StrV}; -use crate::{ffi, FileInfo}; +use crate::{ffi, FileAttributeValue, FileInfo}; impl FileInfo { #[cfg_attr(feature = "v2_62", deprecated)] @@ -71,4 +71,17 @@ impl FileInfo { }); } } + + #[doc(alias = "g_file_info_set_attribute")] + pub fn set_attribute<'a>(&self, attribute: &str, value: impl Into>) { + unsafe { + let value: FileAttributeValue<'a> = value.into(); + ffi::g_file_info_set_attribute( + self.to_glib_none().0, + attribute.to_glib_none().0, + value.type_().into_glib(), + value.as_ptr(), + ); + } + } }