glib-0.14.8/.cargo_vcs_info.json0000644000000001120000000000100120350ustar { "git": { "sha1": "9364a9538de344056ea14c2678229f76b197161e" } } glib-0.14.8/COPYRIGHT000064400000000000000000000012130072674642500121530ustar 00000000000000The gtk-rs Project is licensed under the MIT license, see the LICENSE file or . Copyrights in the gtk-rs Project project are retained by their contributors. No copyright assignment is required to contribute to the gtk-rs Project project. For full authorship information, see the version control history. This project provides interoperability with various GNOME libraries but doesn't distribute any parts of them. Distributing compiled libraries and executables that link to those libraries may be subject to terms of the GNU LGPL or other licenses. For more information check the license of each GNOME library. glib-0.14.8/Cargo.toml0000644000000041600000000000100100420ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "glib" version = "0.14.8" authors = ["The gtk-rs Project Developers"] exclude = ["gir-files/*"] description = "Rust bindings for the GLib library" homepage = "https://gtk-rs.org/" documentation = "https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/" readme = "README.md" keywords = ["glib", "gtk-rs", "gnome", "GUI"] license = "MIT" repository = "https://github.com/gtk-rs/gtk-rs-core" [package.metadata.docs.rs] features = ["dox"] [lib] name = "glib" [dependencies.bitflags] version = "1.0" [dependencies.ffi] version = "0.14.0" package = "glib-sys" [dependencies.futures-channel] version = "0.3" [dependencies.futures-core] version = "0.3" default-features = false [dependencies.futures-executor] version = "0.3" [dependencies.futures-task] version = "0.3" default-features = false [dependencies.glib-macros] version = "0.14.0" [dependencies.gobject_ffi] version = "0.14.0" package = "gobject-sys" [dependencies.libc] version = "0.2" [dependencies.once_cell] version = "1.0" [dependencies.rs-log] version = "0.4" optional = true package = "log" [dependencies.smallvec] version = "1.0" [dev-dependencies.futures-util] version = "0.3" [dev-dependencies.tempfile] version = "3" [features] dox = ["ffi/dox", "gobject_ffi/dox", "log_macros"] log = ["rs-log"] log_macros = ["log"] v2_50 = ["ffi/v2_50"] v2_52 = ["v2_50", "ffi/v2_52"] v2_54 = ["v2_52", "ffi/v2_54", "gobject_ffi/v2_54"] v2_56 = ["v2_54", "ffi/v2_56"] v2_58 = ["v2_56", "ffi/v2_58", "gobject_ffi/v2_58"] v2_60 = ["v2_58", "ffi/v2_60"] v2_62 = ["v2_60", "ffi/v2_62", "gobject_ffi/v2_62"] v2_64 = ["v2_62", "ffi/v2_64"] v2_66 = ["v2_64", "ffi/v2_66"] v2_68 = ["v2_66", "ffi/v2_68"] glib-0.14.8/Cargo.toml.orig000064400000000000000000000030260072674642500135530ustar 00000000000000[package] name = "glib" documentation = "https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/" homepage = "https://gtk-rs.org/" authors = ["The gtk-rs Project Developers"] description = "Rust bindings for the GLib library" readme = "README.md" version = "0.14.8" keywords = ["glib", "gtk-rs", "gnome", "GUI"] repository = "https://github.com/gtk-rs/gtk-rs-core" license = "MIT" exclude = [ "gir-files/*", ] edition = "2018" [lib] name = "glib" [dependencies] once_cell = "1.0" libc = "0.2" bitflags = "1.0" futures-core = { version = "0.3", default-features = false } futures-task = { version = "0.3", default-features = false } futures-executor = "0.3" futures-channel = "0.3" ffi = {package = "glib-sys", path = "../glib/sys", version = "0.14.0"} gobject_ffi = {package = "gobject-sys", path = "../glib/gobject-sys", version = "0.14.0"} glib-macros = {version = "0.14.0", path = "./../glib-macros"} rs-log = { package = "log", version = "0.4", optional = true } smallvec = "1.0" [dev-dependencies] futures-util = "0.3" tempfile = "3" [features] v2_50 = ["ffi/v2_50"] v2_52 = ["v2_50", "ffi/v2_52"] v2_54 = ["v2_52", "ffi/v2_54", "gobject_ffi/v2_54"] v2_56 = ["v2_54", "ffi/v2_56"] v2_58 = ["v2_56", "ffi/v2_58", "gobject_ffi/v2_58"] v2_60 = ["v2_58", "ffi/v2_60"] v2_62 = ["v2_60", "ffi/v2_62", "gobject_ffi/v2_62"] v2_64 = ["v2_62", "ffi/v2_64"] v2_66 = ["v2_64", "ffi/v2_66"] v2_68 = ["v2_66", "ffi/v2_68"] log = ["rs-log"] log_macros = ["log"] dox = ["ffi/dox", "gobject_ffi/dox", "log_macros"] [package.metadata.docs.rs] features = ["dox"] glib-0.14.8/Gir.toml000064400000000000000000000363350072674642500123130ustar 00000000000000[options] girs_directories = ["../gir-files"] library = "GLib" version = "2.0" min_cfg_version = "2.48" target_path = "." work_mode = "normal" single_version_file = true deprecate_by_min_version = true trust_return_value_nullability = true generate = [ "GLib.DateDay", "GLib.DateMonth", "GLib.DateWeekday", "GLib.DateYear", "GLib.FileSetContentsFlags", "GLib.FormatSizeFlags", "GLib.KeyFileError", "GLib.KeyFileFlags", "GLib.LogLevelFlags", "GLib.OptionArg", "GLib.OptionFlags", "GLib.SeekType", "GLib.SpawnFlags", "GLib.Time", "GLib.TimeType", "GLib.TimeSpan", "GLib.FileTest", "GLib.IOCondition", "GLib.UriError", "GLib.UriFlags", "GLib.UriHideFlags", "GLib.UriParamsFlags", ] ignore = [ ] manual = [ "GLib.Bytes", "GLib.ByteArray", "GLib.Error", "GLib.Variant", "GLib.VariantType", "GLib.UserDirectory", "GObject.Object", ] [[object]] name = "GLib.*" status = "generate" [[object.function]] name = "propagate_error" #empty first parameter ignore = true [[object.function]] name = "set_error_literal" #empty first parameter ignore = true [[object.function]] pattern = "atomic_.+" ignore = true [[object.function]] pattern = "bit_.*lock" ignore = true [[object.function]] name = "get_filename_charsets" #string ignore = true [[object.function]] pattern = "str.+v" #string ignore = true [[object.function]] name = "strv_length" #string ignore = true [[object.function]] pattern = "str.+" ignore = true [[object.function]] pattern = "ucs4_.+" ignore = true [[object.function]] pattern = "utf16_.+" ignore = true [[object.function]] pattern = "utf8_.+" ignore = true [[object.function]] pattern = "unichar_.+" ignore = true [[object.function]] pattern = "ascii_.+" ignore = true [[object.function]] name = "assertion_message_error" #Quark ignore = true [[object.function]] name = "assertion_message_expr" ignore = true # function is useless [[object.function]] pattern = "test_.+" ignore = true # functions are useless [[object.function]] pattern = ".+_error_quark" #Quark ignore = true [[object.function]] pattern = "quark_.+_string" #Quark ignore = true [[object.function]] name = "spawn_close_pid" #Pid ignore = true [[object.function]] name = "get_current_dir" #manual ignore = true [[object.function]] pattern = "[gs]et_prgname" #manual pathbuf ignore = true [[object.function]] name = "filename_from_utf8" #not in 64bit lib for Windows ignore = true [[object.function]] name = "get_user_name" #manual pathbuf is_windows_utf8 ignore = true [[object.function]] pattern = "[gs]etenv" #manual is_windows_utf8 ignore = true [[object.function]] name = "unsetenv" #manual is_windows_utf8 ignore = true [[object.function]] name = "filename_to_uri" #manual is_windows_utf8 ignore = true [[object.function]] name = "filename_from_uri" #manual is_windows_utf8 ignore = true [[object.function]] name = "find_program_in_path" #manual is_windows_utf8 ignore = true [[object.function]] name = "get_home_dir" #manual is_windows_utf8 ignore = true [[object.function]] name = "get_real_name" #manual pathbuf? is_windows_utf8 ignore = true [[object.function]] name = "get_tmp_dir" #manual is_windows_utf8 ignore = true [[object.function]] name = "mkstemp" #manual is_windows_utf8 ignore = true [[object.function]] name = "strdup" #not needed ignore = true [[object.function]] pattern = "unix_.+" cfg_condition = "unix" [[object.function]] name = "spawn_command_line_async" cfg_condition = "unix" [[object.function.parameter]] name = "command_line" string_type = "os_string" [[object.function]] name = "unix_open_pipe" manual = true [[object.function]] name = "convert_with_fallback" #out param not in .gir ignore = true [[object.function]] name = "unicode_canonical_decomposition" #out param not in .gir ignore = true [[object.function]] name = "unicode_canonical_ordering" #UCS-4 encoded string ignore = true [[object.function]] name = "convert" #unusable ignore = true [[object.function]] name = "filename_to_utf8" #unusable ignore = true [[object.function]] name = "locale_from_utf8" #unusable ignore = true [[object.function]] name = "locale_to_utf8" #unusable ignore = true [[object.function]] name = "child_watch_source_new" # Need manual bindings to be useful ignore = true [[object.function]] name = "idle_source_new" # Need manual bindings to be useful ignore = true [[object.function]] name = "timeout_source_new" # Need manual bindings to be useful ignore = true [[object.function]] name = "timeout_source_new_seconds" # Need manual bindings to be useful ignore = true [[object.function]] name = "unix_signal_source_new" # Need manual bindings to be useful ignore = true [[object.function]] pattern = "unix_fd.*" # Need manual binding for RawFd ignore = true [[object.function]] name = "close" # Need manual binding for RawFd ignore = true [[object.function]] name = "log_writer_is_journald" # Need manual binding for RawFd ignore = true [[object.function]] name = "log_writer_supports_color" # Need manual binding for RawFd ignore = true [[object.function]] name = "unix_set_fd_nonblocking" # Need manual binding for RawFd ignore = true [[object.function]] name = "environ_getenv" # manual input &[OsString] ignore = true [[object.function]] pattern = "environ_(un)?setenv" # unusable ignore = true [[object.function]] name = "get_charset" # boolean return value ignore = true [[object.function]] name = "get_environ" [object.function.return] string_type = "os_string" [[object.function]] name = "listenv" [object.function.return] string_type = "os_string" [[object.function]] name = "shell_parse_argv" [[object.function.parameter]] name = "command_line" string_type = "os_string" [[object.function.parameter]] name = "argvp" string_type = "os_string" [[object.function]] name = "shell_quote" [[object.function.parameter]] name = "unquoted_string" string_type = "os_string" [object.function.return] string_type = "os_string" [[object.function]] name = "shell_unquote" [[object.function.parameter]] name = "quoted_string" string_type = "os_string" [object.function.return] string_type = "os_string" [[object.function]] name = "intern_static_string" ignore = true [[object.function]] name = "intern_string" ignore = true [[object.function]] # Pid conversion issue name = "child_watch_add" ignore = true [[object.function]] # Pid conversion issue name = "child_watch_add_full" ignore = true [[object.function]] name = "idle_add" ignore = true [[object.function]] name = "idle_add_full" ignore = true [[object.function]] name = "timeout_add" ignore = true [[object.function]] name = "timeout_add_full" ignore = true [[object.function]] name = "timeout_add_seconds" ignore = true [[object.function]] name = "timeout_add_seconds_full" ignore = true [[object.function]] name = "unix_signal_add" ignore = true [[object.function]] name = "unix_signal_add_full" ignore = true [[object.function]] pattern = "rc_box_.+" #need manual implementation ignore = true [[object.function]] pattern = "ref_count_.+" #need manual implementation ignore = true [[object.function]] pattern = "ref_string_.+" #need manual implementation ignore = true [[object.function]] name = "spawn_async_with_fds" # generates invalid FDs ignore = true [[object.function]] name = "spawn_async_with_pipes" # generates invalid FDs ignore = true [[object.function]] name = "log_set_handler" # leaks closure ignore = true [[object.function]] name = "log_default_handler" # last argument is unused ignore = true [[object.function]] name = "log_set_handler_full" # from_glib_borrow on non-pointer objects ignore = true [[object.function]] name = "log_set_writer_func" # from_glib_borrow on non-pointer objects ignore = true [[object.function]] name = "log_structured" # implemented with a macro because of var args and weird arguments pairing ignore = true [[object.function]] name = "log" # implemented with a macro because of var args ignore = true [[object.function]] name = "log_set_default_handler" # It returned the old callback, which is problematic ignore = true [[object.function]] name = "log_remove_handler" # Change handler_id parameter type to LogHandlerId ignore = true [[object.function]] name = "log_set_always_fatal" # update of arguments and return type ignore = true [[object.function]] name = "log_variant" # usage of LogLevelFlags ignore = true [[object.function]] name = "log_set_fatal_mask" # update of arguments and return type ignore = true [[object.constant]] pattern = "DIR_SEPARATOR(_S)?" #not cross-platform ignore = true [[object.constant]] pattern = "SEARCHPATH_SEPARATOR(_S)?" #not cross-platform ignore = true [[object.constant]] name = "MODULE_SUFFIX" #not cross-platform ignore = true [[object.constant]] pattern = "GU?INT(16)?(32)?(64)?(PTR)?_FORMAT" #for C printf ignore = true [[object.constant]] pattern = "GU?INT(16)?(32)?(64)?(PTR)?_MODIFIER" #for C printf ignore = true [[object.constant]] pattern = "GS?SIZE_(FORMAT)?(MODIFIER)?" #for C printf ignore = true [[object.constant]] pattern = "GNUC_(PRETTY_)?FUNCTION" #for C printf ignore = true [[object.constant]] pattern = "PID_FORMAT" #for C printf ignore = true [[object.constant]] pattern = "POLLFD_FORMAT" #for C printf ignore = true [[object.function]] name = "variant_get_gtype" # get_type() function that should be used in StaticType impl instead ignore = true [[object]] name = "GLib.Checksum" status = "generate" concurrency = "send+sync" [[object.function]] name = "get_digest" #wrong array definition manual = true [[object.function]] name = "get_string" #consume manual = true [[object]] name = "GLib.ChecksumType" status = "generate" [[object.member]] name = "sha384" version = "2.52" [[object]] name = "GLib.KeyFile" status = "generate" [[object.function]] name = "load_from_data_dirs" manual = true [[object.function]] name = "load_from_dirs" manual = true [[object.function]] name = "save_to_file" # file parameter needs to be a PathBuf manual = true [[object.function]] name = "set_locale_string_list" #[&str] to *mut i8 ignore = true [[object.function]] name = "set_string_list" #[&str] to *mut i8 ignore = true [[object.function]] name = "to_data" manual = true [[object.function]] name = "set_double_list" #wrong array type ignore = true [[object.function]] name = "set_integer_list" #wrong array type ignore = true [[object.function]] name = "get_boolean" #boolean return value needs to be returned manual = true [[object.function]] name = "has_key" #boolean return value needs to be returned manual = true [[object.function]] name = "get_boolean_list" #boolean array needs to be converted to Vec manual = true [[object.function]] name = "get_string" # can return an error but still a value to be freed manual = true [[object.function]] name = "get_string_list" # can return an error but still a value to be freed manual = true [[object.function]] name = "get_locale_string" # can return an error but still a value to be freed manual = true [[object.function]] name = "get_locale_string_list" # can return an error but still a value to be freed manual = true [[object.function]] name = "get_comment" [[object.function.parameter]] name = "key" nullable = true # Fixed in GLib 2.66.2 [[object.function]] name = "get_start_group" [object.function.return] nullable = true [[object]] name = "GLib.DateTime" status = "generate" concurrency = "send+sync" [[object.function]] pattern = ".+" [object.function.return] nullable_return_is_error = "Invalid date" [[object]] name = "GLib.MainContext" status = "generate" concurrency = "send+sync" [[object.function]] name = "prepare" # out parameter not marked as such manual = true [[object.function]] name = "find_source_by_id" # source id is a newtype manual = true [[object.function]] name = "invoke" manual = true [[object.function]] name = "invoke_full" ignore = true # Fixed in GLib 2.66.2 [[object.function]] name = "get_thread_default" [object.function.return] nullable = true # Fixed in GLib 2.66.2 [[object.function]] name = "current_source" [object.function.return] nullable = true [[object.function]] name = "acquire" # implemented with a guard type manual = true [[object.function]] name = "release" # implemented with a guard type manual = true [[object]] name = "GLib.MainLoop" status = "generate" concurrency = "send+sync" [[object]] name = "GLib.Source" status = "generate" concurrency = "send+sync" [[object.function]] pattern = "set_.+" # Setters are generally not thread-safe # while GSource itself is ignore = true [[object.function]] pattern = "attach" # return type ignore = true [[object.function]] pattern = "get_id" # unsafe as it would allow multiple times to remove ignore = true [[object.function]] pattern = "remove" # parameter type ignore = true # Fixed in GLib 2.66.2 [[object.function]] name = "get_name" [object.function.return] nullable = true [[object]] name = "GLib.TimeZone" status = "generate" concurrency = "send+sync" [[object.function]] name = "adjust_time" # in-out parameter ignore = true [[object]] name = "GLib.Uri" status = "generate" concurrency = "send+sync" # Fixed in GLib 2.66.2 [[object.function]] name = "unescape_string" [object.function.return] nullable = true # Fixed in GLib 2.66.2 [[object.function]] name = "unescape_segment" [object.function.return] nullable = true glib-0.14.8/Gir_GObject.toml000064400000000000000000000024450072674642500137030ustar 00000000000000[options] girs_dir = "gir-files" library = "GObject" version = "2.0" min_cfg_version = "2.42" target_path = "." auto_path = "src/gobject/auto" work_mode = "normal" single_version_file = true deprecate_by_min_version = true trust_return_value_nullability = true girs_directories = ["../gir-files"] generate = [ "GObject.BindingFlags", "GObject.SignalFlags", ] ignore = [ ] manual = [ "GObject.Object", "GObject.Value", "GObject.ParamFlags", ] [[object]] name = "GObject.Binding" status = "generate" trait = false concurrency = "send+sync" [[object.function]] name = "get_source" # Not thread-safe, see https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1745 # Using the GObject properties will be automatically safe with GLib 2.68. ignore = true [[object.function]] name = "get_target" # Not thread-safe, see https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1745 # Using the GObject properties will be automatically safe with GLib 2.68. ignore = true [[object.property]] name = "source" # So we can implement setter/getter with the correct name ignore = true [[object.property]] name = "target" # So we can implement setter/getter with the correct name ignore = true [[object]] name = "GObject.*" status = "ignore" glib-0.14.8/LICENSE000064400000000000000000000020000072674642500116600ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. glib-0.14.8/README.md000064400000000000000000000021220072674642500121370ustar 00000000000000# glib __Rust__ bindings and wrappers for __GLib__, part of [gtk-rs-core](https://github.com/gtk-rs/gtk-rs-core). ## Minimum supported Rust version Currently, the minimum supported Rust version is `1.51.0`. ## Documentation * [Rust API - Stable](https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/) * [Rust API - Development](https://gtk-rs.org/gtk-rs-core/git/docs/glib) * [C API](https://developer.gnome.org/glib/stable/) * [GTK Installation instructions](https://www.gtk.org/docs/installations/) ## Using We recommend using [crates from crates.io](https://crates.io/keywords/gtk-rs), as [demonstrated here](https://gtk-rs.org/#using). If you want to track the bleeding edge, use the git dependency instead: ```toml [dependencies] glib = { git = "https://github.com/gtk-rs/gtk-rs-core.git", package = "glib" } ``` Avoid mixing versioned and git crates like this: ```toml # This will not compile [dependencies] glib = "0.13" glib = { git = "https://github.com/gtk-rs/gtk-rs-core.git", package = "glib" } ``` ## License __glib__ is available under the MIT License, please refer to it. glib-0.14.8/src/array.rs000064400000000000000000000022200072674642500131320ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::*; use std::fmt; wrapper! { #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GArray")] pub struct Array(Shared); match fn { ref => |ptr| ffi::g_array_ref(ptr), unref => |ptr| ffi::g_array_unref(ptr), type_ => || ffi::g_array_get_type(), } } impl Array { pub fn len(&self) -> usize { unsafe { (*self.to_glib_none().0).len as usize } } pub fn is_empty(&self) -> bool { self.len() == 0 } pub fn data(&self) -> *mut libc::c_void { unsafe { (*self.to_glib_none().0).data as _ } } #[doc(alias = "g_array_get_element_size")] pub fn element_size(&self) -> usize { unsafe { ffi::g_array_get_element_size(self.to_glib_none().0) as usize } } } impl fmt::Debug for Array { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Array") .field("len", &self.len()) .field("data", &self.data()) .field("element_size", &self.element_size()) .finish() } } glib-0.14.8/src/auto/alias.rs000064400000000000000000000004260072674642500140630ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT #[allow(unused_imports)] use crate::auto::*; pub type DateDay = u8; pub type DateYear = u16; pub type Time = i32; pub type TimeSpan = i64; glib-0.14.8/src/auto/checksum.rs000064400000000000000000000025450072674642500146000ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::translate::*; use crate::ChecksumType; crate::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Checksum(Boxed); match fn { copy => |ptr| ffi::g_checksum_copy(ptr), free => |ptr| ffi::g_checksum_free(ptr), type_ => || ffi::g_checksum_get_type(), } } impl Checksum { #[doc(alias = "g_checksum_new")] pub fn new(checksum_type: ChecksumType) -> Option { unsafe { from_glib_full(ffi::g_checksum_new(checksum_type.into_glib())) } } #[doc(alias = "g_checksum_reset")] pub fn reset(&mut self) { unsafe { ffi::g_checksum_reset(self.to_glib_none_mut().0); } } #[doc(alias = "g_checksum_update")] pub fn update(&mut self, data: &[u8]) { let length = data.len() as isize; unsafe { ffi::g_checksum_update(self.to_glib_none_mut().0, data.to_glib_none().0, length); } } #[doc(alias = "g_checksum_type_get_length")] pub fn type_get_length(checksum_type: ChecksumType) -> isize { unsafe { ffi::g_checksum_type_get_length(checksum_type.into_glib()) } } } unsafe impl Send for Checksum {} unsafe impl Sync for Checksum {} glib-0.14.8/src/auto/constants.rs000064400000000000000000000222010072674642500150010ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use std::ffi::CStr; #[doc(alias = "G_CSET_A_2_Z")] pub static CSET_A_2_Z: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_CSET_A_2_Z).to_str().unwrap() }); #[doc(alias = "G_CSET_DIGITS")] pub static CSET_DIGITS: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_CSET_DIGITS).to_str().unwrap() }); #[doc(alias = "G_CSET_a_2_z")] pub static CSET_a_2_z: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_CSET_a_2_z).to_str().unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_GROUP")] pub static KEY_FILE_DESKTOP_GROUP: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_GROUP) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_ACTIONS")] pub static KEY_FILE_DESKTOP_KEY_ACTIONS: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_ACTIONS) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_CATEGORIES")] pub static KEY_FILE_DESKTOP_KEY_CATEGORIES: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_CATEGORIES) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_COMMENT")] pub static KEY_FILE_DESKTOP_KEY_COMMENT: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_COMMENT) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE")] pub static KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_EXEC")] pub static KEY_FILE_DESKTOP_KEY_EXEC: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_EXEC) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_GENERIC_NAME")] pub static KEY_FILE_DESKTOP_KEY_GENERIC_NAME: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_GENERIC_NAME) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_HIDDEN")] pub static KEY_FILE_DESKTOP_KEY_HIDDEN: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_HIDDEN) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_ICON")] pub static KEY_FILE_DESKTOP_KEY_ICON: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_ICON) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_MIME_TYPE")] pub static KEY_FILE_DESKTOP_KEY_MIME_TYPE: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_MIME_TYPE) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_NAME")] pub static KEY_FILE_DESKTOP_KEY_NAME: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_NAME) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN")] pub static KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY")] pub static KEY_FILE_DESKTOP_KEY_NO_DISPLAY: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN")] pub static KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_PATH")] pub static KEY_FILE_DESKTOP_KEY_PATH: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_PATH) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY")] pub static KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS")] pub static KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_TERMINAL")] pub static KEY_FILE_DESKTOP_KEY_TERMINAL: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_TERMINAL) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_TRY_EXEC")] pub static KEY_FILE_DESKTOP_KEY_TRY_EXEC: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_TRY_EXEC) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_TYPE")] pub static KEY_FILE_DESKTOP_KEY_TYPE: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_TYPE) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_URL")] pub static KEY_FILE_DESKTOP_KEY_URL: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_URL) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_VERSION")] pub static KEY_FILE_DESKTOP_KEY_VERSION: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_KEY_VERSION) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_TYPE_APPLICATION")] pub static KEY_FILE_DESKTOP_TYPE_APPLICATION: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_TYPE_APPLICATION) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_TYPE_DIRECTORY")] pub static KEY_FILE_DESKTOP_TYPE_DIRECTORY: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_TYPE_DIRECTORY) .to_str() .unwrap() }); #[doc(alias = "G_KEY_FILE_DESKTOP_TYPE_LINK")] pub static KEY_FILE_DESKTOP_TYPE_LINK: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_KEY_FILE_DESKTOP_TYPE_LINK) .to_str() .unwrap() }); #[doc(alias = "G_OPTION_REMAINING")] pub static OPTION_REMAINING: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_OPTION_REMAINING).to_str().unwrap() }); #[doc(alias = "G_STR_DELIMITERS")] pub static STR_DELIMITERS: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_STR_DELIMITERS).to_str().unwrap() }); #[cfg(any(feature = "v2_60", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_60")))] #[doc(alias = "G_TEST_OPTION_ISOLATE_DIRS")] pub static TEST_OPTION_ISOLATE_DIRS: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_TEST_OPTION_ISOLATE_DIRS) .to_str() .unwrap() }); #[doc(alias = "G_URI_RESERVED_CHARS_GENERIC_DELIMITERS")] pub static URI_RESERVED_CHARS_GENERIC_DELIMITERS: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_URI_RESERVED_CHARS_GENERIC_DELIMITERS) .to_str() .unwrap() }); #[doc(alias = "G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS")] pub static URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS: once_cell::sync::Lazy<&'static str> = once_cell::sync::Lazy::new(|| unsafe { CStr::from_ptr(ffi::G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS) .to_str() .unwrap() }); glib-0.14.8/src/auto/date_time.rs000064400000000000000000000376110072674642500147330ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::translate::*; use crate::BoolError; use crate::TimeSpan; use crate::TimeZone; use std::cmp; use std::hash; use std::mem; crate::wrapper! { #[derive(Debug)] pub struct DateTime(Shared); match fn { ref => |ptr| ffi::g_date_time_ref(ptr), unref => |ptr| ffi::g_date_time_unref(ptr), type_ => || ffi::g_date_time_get_type(), } } impl DateTime { #[doc(alias = "g_date_time_new")] pub fn new( tz: &TimeZone, year: i32, month: i32, day: i32, hour: i32, minute: i32, seconds: f64, ) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new( tz.to_glib_none().0, year, month, day, hour, minute, seconds, )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[cfg(any(feature = "v2_56", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_56")))] #[doc(alias = "g_date_time_new_from_iso8601")] #[doc(alias = "new_from_iso8601")] pub fn from_iso8601(text: &str, default_tz: Option<&TimeZone>) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new_from_iso8601( text.to_glib_none().0, default_tz.to_glib_none().0, )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } //#[cfg_attr(feature = "v2_62", deprecated = "Since 2.62")] //#[doc(alias = "g_date_time_new_from_timeval_local")] //#[doc(alias = "new_from_timeval_local")] //pub fn from_timeval_local(tv: /*Ignored*/&TimeVal) -> Result { // unsafe { TODO: call ffi:g_date_time_new_from_timeval_local() } //} //#[cfg_attr(feature = "v2_62", deprecated = "Since 2.62")] //#[doc(alias = "g_date_time_new_from_timeval_utc")] //#[doc(alias = "new_from_timeval_utc")] //pub fn from_timeval_utc(tv: /*Ignored*/&TimeVal) -> Result { // unsafe { TODO: call ffi:g_date_time_new_from_timeval_utc() } //} #[doc(alias = "g_date_time_new_from_unix_local")] #[doc(alias = "new_from_unix_local")] pub fn from_unix_local(t: i64) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new_from_unix_local(t)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_new_from_unix_utc")] #[doc(alias = "new_from_unix_utc")] pub fn from_unix_utc(t: i64) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new_from_unix_utc(t)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_new_local")] pub fn new_local( year: i32, month: i32, day: i32, hour: i32, minute: i32, seconds: f64, ) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new_local( year, month, day, hour, minute, seconds, )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_new_now")] pub fn new_now(tz: &TimeZone) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new_now(tz.to_glib_none().0)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_new_now_local")] pub fn new_now_local() -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new_now_local()) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_new_now_utc")] pub fn new_now_utc() -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new_now_utc()) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_new_utc")] pub fn new_utc( year: i32, month: i32, day: i32, hour: i32, minute: i32, seconds: f64, ) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new_utc( year, month, day, hour, minute, seconds, )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_add")] pub fn add(&self, timespan: TimeSpan) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_add(self.to_glib_none().0, timespan)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_add_days")] pub fn add_days(&self, days: i32) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_add_days(self.to_glib_none().0, days)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_add_full")] pub fn add_full( &self, years: i32, months: i32, days: i32, hours: i32, minutes: i32, seconds: f64, ) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_add_full( self.to_glib_none().0, years, months, days, hours, minutes, seconds, )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_add_hours")] pub fn add_hours(&self, hours: i32) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_add_hours(self.to_glib_none().0, hours)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_add_minutes")] pub fn add_minutes(&self, minutes: i32) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_add_minutes( self.to_glib_none().0, minutes, )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_add_months")] pub fn add_months(&self, months: i32) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_add_months(self.to_glib_none().0, months)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_add_seconds")] pub fn add_seconds(&self, seconds: f64) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_add_seconds( self.to_glib_none().0, seconds, )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_add_weeks")] pub fn add_weeks(&self, weeks: i32) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_add_weeks(self.to_glib_none().0, weeks)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_add_years")] pub fn add_years(&self, years: i32) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_add_years(self.to_glib_none().0, years)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_compare")] fn compare(&self, dt2: &DateTime) -> i32 { unsafe { ffi::g_date_time_compare( ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(self).0 as ffi::gconstpointer, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(dt2).0 as ffi::gconstpointer, ) } } #[doc(alias = "g_date_time_difference")] pub fn difference(&self, begin: &DateTime) -> TimeSpan { unsafe { ffi::g_date_time_difference(self.to_glib_none().0, begin.to_glib_none().0) } } #[doc(alias = "g_date_time_equal")] fn equal(&self, dt2: &DateTime) -> bool { unsafe { from_glib(ffi::g_date_time_equal( ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(self).0 as ffi::gconstpointer, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(dt2).0 as ffi::gconstpointer, )) } } #[doc(alias = "g_date_time_format")] pub fn format(&self, format: &str) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_format( self.to_glib_none().0, format.to_glib_none().0, )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[cfg(any(feature = "v2_62", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_62")))] #[doc(alias = "g_date_time_format_iso8601")] pub fn format_iso8601(&self) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_format_iso8601(self.to_glib_none().0)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_get_day_of_month")] #[doc(alias = "get_day_of_month")] pub fn day_of_month(&self) -> i32 { unsafe { ffi::g_date_time_get_day_of_month(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_day_of_week")] #[doc(alias = "get_day_of_week")] pub fn day_of_week(&self) -> i32 { unsafe { ffi::g_date_time_get_day_of_week(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_day_of_year")] #[doc(alias = "get_day_of_year")] pub fn day_of_year(&self) -> i32 { unsafe { ffi::g_date_time_get_day_of_year(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_hour")] #[doc(alias = "get_hour")] pub fn hour(&self) -> i32 { unsafe { ffi::g_date_time_get_hour(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_microsecond")] #[doc(alias = "get_microsecond")] pub fn microsecond(&self) -> i32 { unsafe { ffi::g_date_time_get_microsecond(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_minute")] #[doc(alias = "get_minute")] pub fn minute(&self) -> i32 { unsafe { ffi::g_date_time_get_minute(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_month")] #[doc(alias = "get_month")] pub fn month(&self) -> i32 { unsafe { ffi::g_date_time_get_month(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_second")] #[doc(alias = "get_second")] pub fn second(&self) -> i32 { unsafe { ffi::g_date_time_get_second(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_seconds")] #[doc(alias = "get_seconds")] pub fn seconds(&self) -> f64 { unsafe { ffi::g_date_time_get_seconds(self.to_glib_none().0) } } #[cfg(any(feature = "v2_58", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_58")))] #[doc(alias = "g_date_time_get_timezone")] #[doc(alias = "get_timezone")] pub fn timezone(&self) -> TimeZone { unsafe { from_glib_none(ffi::g_date_time_get_timezone(self.to_glib_none().0)) } } #[doc(alias = "g_date_time_get_timezone_abbreviation")] #[doc(alias = "get_timezone_abbreviation")] pub fn timezone_abbreviation(&self) -> crate::GString { unsafe { from_glib_none(ffi::g_date_time_get_timezone_abbreviation( self.to_glib_none().0, )) } } #[doc(alias = "g_date_time_get_utc_offset")] #[doc(alias = "get_utc_offset")] pub fn utc_offset(&self) -> TimeSpan { unsafe { ffi::g_date_time_get_utc_offset(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_week_numbering_year")] #[doc(alias = "get_week_numbering_year")] pub fn week_numbering_year(&self) -> i32 { unsafe { ffi::g_date_time_get_week_numbering_year(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_week_of_year")] #[doc(alias = "get_week_of_year")] pub fn week_of_year(&self) -> i32 { unsafe { ffi::g_date_time_get_week_of_year(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_year")] #[doc(alias = "get_year")] pub fn year(&self) -> i32 { unsafe { ffi::g_date_time_get_year(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_ymd")] #[doc(alias = "get_ymd")] pub fn ymd(&self) -> (i32, i32, i32) { unsafe { let mut year = mem::MaybeUninit::uninit(); let mut month = mem::MaybeUninit::uninit(); let mut day = mem::MaybeUninit::uninit(); ffi::g_date_time_get_ymd( self.to_glib_none().0, year.as_mut_ptr(), month.as_mut_ptr(), day.as_mut_ptr(), ); let year = year.assume_init(); let month = month.assume_init(); let day = day.assume_init(); (year, month, day) } } #[doc(alias = "g_date_time_hash")] fn hash(&self) -> u32 { unsafe { ffi::g_date_time_hash( ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(self).0 as ffi::gconstpointer, ) } } #[doc(alias = "g_date_time_is_daylight_savings")] pub fn is_daylight_savings(&self) -> bool { unsafe { from_glib(ffi::g_date_time_is_daylight_savings(self.to_glib_none().0)) } } #[doc(alias = "g_date_time_to_local")] pub fn to_local(&self) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_to_local(self.to_glib_none().0)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } //#[cfg_attr(feature = "v2_62", deprecated = "Since 2.62")] //#[doc(alias = "g_date_time_to_timeval")] //pub fn to_timeval(&self, tv: /*Ignored*/&mut TimeVal) -> bool { // unsafe { TODO: call ffi:g_date_time_to_timeval() } //} #[doc(alias = "g_date_time_to_timezone")] pub fn to_timezone(&self, tz: &TimeZone) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_to_timezone( self.to_glib_none().0, tz.to_glib_none().0, )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_to_unix")] pub fn to_unix(&self) -> i64 { unsafe { ffi::g_date_time_to_unix(self.to_glib_none().0) } } #[doc(alias = "g_date_time_to_utc")] pub fn to_utc(&self) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_to_utc(self.to_glib_none().0)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } } impl PartialOrd for DateTime { #[inline] fn partial_cmp(&self, other: &Self) -> Option { self.compare(other).partial_cmp(&0) } } impl Ord for DateTime { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { self.compare(other).cmp(&0) } } impl PartialEq for DateTime { #[inline] fn eq(&self, other: &Self) -> bool { self.equal(other) } } impl Eq for DateTime {} impl hash::Hash for DateTime { #[inline] fn hash(&self, state: &mut H) where H: hash::Hasher, { hash::Hash::hash(&self.hash(), state) } } unsafe impl Send for DateTime {} unsafe impl Sync for DateTime {} glib-0.14.8/src/auto/enums.rs000064400000000000000000000516140072674642500141260ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::error::ErrorDomain; use crate::translate::*; use crate::Quark; use std::fmt; #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GChecksumType")] pub enum ChecksumType { #[doc(alias = "G_CHECKSUM_MD5")] Md5, #[doc(alias = "G_CHECKSUM_SHA1")] Sha1, #[doc(alias = "G_CHECKSUM_SHA256")] Sha256, #[doc(alias = "G_CHECKSUM_SHA512")] Sha512, #[cfg(any(feature = "v2_52", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_52")))] #[doc(alias = "G_CHECKSUM_SHA384")] Sha384, #[doc(hidden)] __Unknown(i32), } impl fmt::Display for ChecksumType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "ChecksumType::{}", match *self { Self::Md5 => "Md5", Self::Sha1 => "Sha1", Self::Sha256 => "Sha256", Self::Sha512 => "Sha512", #[cfg(any(feature = "v2_52", feature = "dox"))] Self::Sha384 => "Sha384", _ => "Unknown", } ) } } #[doc(hidden)] impl IntoGlib for ChecksumType { type GlibType = ffi::GChecksumType; fn into_glib(self) -> ffi::GChecksumType { match self { Self::Md5 => ffi::G_CHECKSUM_MD5, Self::Sha1 => ffi::G_CHECKSUM_SHA1, Self::Sha256 => ffi::G_CHECKSUM_SHA256, Self::Sha512 => ffi::G_CHECKSUM_SHA512, #[cfg(any(feature = "v2_52", feature = "dox"))] Self::Sha384 => ffi::G_CHECKSUM_SHA384, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for ChecksumType { unsafe fn from_glib(value: ffi::GChecksumType) -> Self { match value { ffi::G_CHECKSUM_MD5 => Self::Md5, ffi::G_CHECKSUM_SHA1 => Self::Sha1, ffi::G_CHECKSUM_SHA256 => Self::Sha256, ffi::G_CHECKSUM_SHA512 => Self::Sha512, #[cfg(any(feature = "v2_52", feature = "dox"))] ffi::G_CHECKSUM_SHA384 => Self::Sha384, value => Self::__Unknown(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GDateMonth")] pub enum DateMonth { #[doc(alias = "G_DATE_BAD_MONTH")] BadMonth, #[doc(alias = "G_DATE_JANUARY")] January, #[doc(alias = "G_DATE_FEBRUARY")] February, #[doc(alias = "G_DATE_MARCH")] March, #[doc(alias = "G_DATE_APRIL")] April, #[doc(alias = "G_DATE_MAY")] May, #[doc(alias = "G_DATE_JUNE")] June, #[doc(alias = "G_DATE_JULY")] July, #[doc(alias = "G_DATE_AUGUST")] August, #[doc(alias = "G_DATE_SEPTEMBER")] September, #[doc(alias = "G_DATE_OCTOBER")] October, #[doc(alias = "G_DATE_NOVEMBER")] November, #[doc(alias = "G_DATE_DECEMBER")] December, #[doc(hidden)] __Unknown(i32), } impl fmt::Display for DateMonth { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "DateMonth::{}", match *self { Self::BadMonth => "BadMonth", Self::January => "January", Self::February => "February", Self::March => "March", Self::April => "April", Self::May => "May", Self::June => "June", Self::July => "July", Self::August => "August", Self::September => "September", Self::October => "October", Self::November => "November", Self::December => "December", _ => "Unknown", } ) } } #[doc(hidden)] impl IntoGlib for DateMonth { type GlibType = ffi::GDateMonth; fn into_glib(self) -> ffi::GDateMonth { match self { Self::BadMonth => ffi::G_DATE_BAD_MONTH, Self::January => ffi::G_DATE_JANUARY, Self::February => ffi::G_DATE_FEBRUARY, Self::March => ffi::G_DATE_MARCH, Self::April => ffi::G_DATE_APRIL, Self::May => ffi::G_DATE_MAY, Self::June => ffi::G_DATE_JUNE, Self::July => ffi::G_DATE_JULY, Self::August => ffi::G_DATE_AUGUST, Self::September => ffi::G_DATE_SEPTEMBER, Self::October => ffi::G_DATE_OCTOBER, Self::November => ffi::G_DATE_NOVEMBER, Self::December => ffi::G_DATE_DECEMBER, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for DateMonth { unsafe fn from_glib(value: ffi::GDateMonth) -> Self { match value { ffi::G_DATE_BAD_MONTH => Self::BadMonth, ffi::G_DATE_JANUARY => Self::January, ffi::G_DATE_FEBRUARY => Self::February, ffi::G_DATE_MARCH => Self::March, ffi::G_DATE_APRIL => Self::April, ffi::G_DATE_MAY => Self::May, ffi::G_DATE_JUNE => Self::June, ffi::G_DATE_JULY => Self::July, ffi::G_DATE_AUGUST => Self::August, ffi::G_DATE_SEPTEMBER => Self::September, ffi::G_DATE_OCTOBER => Self::October, ffi::G_DATE_NOVEMBER => Self::November, ffi::G_DATE_DECEMBER => Self::December, value => Self::__Unknown(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GDateWeekday")] pub enum DateWeekday { #[doc(alias = "G_DATE_BAD_WEEKDAY")] BadWeekday, #[doc(alias = "G_DATE_MONDAY")] Monday, #[doc(alias = "G_DATE_TUESDAY")] Tuesday, #[doc(alias = "G_DATE_WEDNESDAY")] Wednesday, #[doc(alias = "G_DATE_THURSDAY")] Thursday, #[doc(alias = "G_DATE_FRIDAY")] Friday, #[doc(alias = "G_DATE_SATURDAY")] Saturday, #[doc(alias = "G_DATE_SUNDAY")] Sunday, #[doc(hidden)] __Unknown(i32), } impl fmt::Display for DateWeekday { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "DateWeekday::{}", match *self { Self::BadWeekday => "BadWeekday", Self::Monday => "Monday", Self::Tuesday => "Tuesday", Self::Wednesday => "Wednesday", Self::Thursday => "Thursday", Self::Friday => "Friday", Self::Saturday => "Saturday", Self::Sunday => "Sunday", _ => "Unknown", } ) } } #[doc(hidden)] impl IntoGlib for DateWeekday { type GlibType = ffi::GDateWeekday; fn into_glib(self) -> ffi::GDateWeekday { match self { Self::BadWeekday => ffi::G_DATE_BAD_WEEKDAY, Self::Monday => ffi::G_DATE_MONDAY, Self::Tuesday => ffi::G_DATE_TUESDAY, Self::Wednesday => ffi::G_DATE_WEDNESDAY, Self::Thursday => ffi::G_DATE_THURSDAY, Self::Friday => ffi::G_DATE_FRIDAY, Self::Saturday => ffi::G_DATE_SATURDAY, Self::Sunday => ffi::G_DATE_SUNDAY, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for DateWeekday { unsafe fn from_glib(value: ffi::GDateWeekday) -> Self { match value { ffi::G_DATE_BAD_WEEKDAY => Self::BadWeekday, ffi::G_DATE_MONDAY => Self::Monday, ffi::G_DATE_TUESDAY => Self::Tuesday, ffi::G_DATE_WEDNESDAY => Self::Wednesday, ffi::G_DATE_THURSDAY => Self::Thursday, ffi::G_DATE_FRIDAY => Self::Friday, ffi::G_DATE_SATURDAY => Self::Saturday, ffi::G_DATE_SUNDAY => Self::Sunday, value => Self::__Unknown(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GKeyFileError")] pub enum KeyFileError { #[doc(alias = "G_KEY_FILE_ERROR_UNKNOWN_ENCODING")] UnknownEncoding, #[doc(alias = "G_KEY_FILE_ERROR_PARSE")] Parse, #[doc(alias = "G_KEY_FILE_ERROR_NOT_FOUND")] NotFound, #[doc(alias = "G_KEY_FILE_ERROR_KEY_NOT_FOUND")] KeyNotFound, #[doc(alias = "G_KEY_FILE_ERROR_GROUP_NOT_FOUND")] GroupNotFound, #[doc(alias = "G_KEY_FILE_ERROR_INVALID_VALUE")] InvalidValue, #[doc(hidden)] __Unknown(i32), } impl fmt::Display for KeyFileError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "KeyFileError::{}", match *self { Self::UnknownEncoding => "UnknownEncoding", Self::Parse => "Parse", Self::NotFound => "NotFound", Self::KeyNotFound => "KeyNotFound", Self::GroupNotFound => "GroupNotFound", Self::InvalidValue => "InvalidValue", _ => "Unknown", } ) } } #[doc(hidden)] impl IntoGlib for KeyFileError { type GlibType = ffi::GKeyFileError; fn into_glib(self) -> ffi::GKeyFileError { match self { Self::UnknownEncoding => ffi::G_KEY_FILE_ERROR_UNKNOWN_ENCODING, Self::Parse => ffi::G_KEY_FILE_ERROR_PARSE, Self::NotFound => ffi::G_KEY_FILE_ERROR_NOT_FOUND, Self::KeyNotFound => ffi::G_KEY_FILE_ERROR_KEY_NOT_FOUND, Self::GroupNotFound => ffi::G_KEY_FILE_ERROR_GROUP_NOT_FOUND, Self::InvalidValue => ffi::G_KEY_FILE_ERROR_INVALID_VALUE, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for KeyFileError { unsafe fn from_glib(value: ffi::GKeyFileError) -> Self { match value { ffi::G_KEY_FILE_ERROR_UNKNOWN_ENCODING => Self::UnknownEncoding, ffi::G_KEY_FILE_ERROR_PARSE => Self::Parse, ffi::G_KEY_FILE_ERROR_NOT_FOUND => Self::NotFound, ffi::G_KEY_FILE_ERROR_KEY_NOT_FOUND => Self::KeyNotFound, ffi::G_KEY_FILE_ERROR_GROUP_NOT_FOUND => Self::GroupNotFound, ffi::G_KEY_FILE_ERROR_INVALID_VALUE => Self::InvalidValue, value => Self::__Unknown(value), } } } impl ErrorDomain for KeyFileError { fn domain() -> Quark { unsafe { from_glib(ffi::g_key_file_error_quark()) } } fn code(self) -> i32 { self.into_glib() } fn from(code: i32) -> Option { match code { ffi::G_KEY_FILE_ERROR_UNKNOWN_ENCODING => Some(Self::UnknownEncoding), ffi::G_KEY_FILE_ERROR_PARSE => Some(Self::Parse), ffi::G_KEY_FILE_ERROR_NOT_FOUND => Some(Self::NotFound), ffi::G_KEY_FILE_ERROR_KEY_NOT_FOUND => Some(Self::KeyNotFound), ffi::G_KEY_FILE_ERROR_GROUP_NOT_FOUND => Some(Self::GroupNotFound), ffi::G_KEY_FILE_ERROR_INVALID_VALUE => Some(Self::InvalidValue), value => Some(Self::__Unknown(value)), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GOptionArg")] pub enum OptionArg { #[doc(alias = "G_OPTION_ARG_NONE")] None, #[doc(alias = "G_OPTION_ARG_STRING")] String, #[doc(alias = "G_OPTION_ARG_INT")] Int, #[doc(alias = "G_OPTION_ARG_CALLBACK")] Callback, #[doc(alias = "G_OPTION_ARG_FILENAME")] Filename, #[doc(alias = "G_OPTION_ARG_STRING_ARRAY")] StringArray, #[doc(alias = "G_OPTION_ARG_FILENAME_ARRAY")] FilenameArray, #[doc(alias = "G_OPTION_ARG_DOUBLE")] Double, #[doc(alias = "G_OPTION_ARG_INT64")] Int64, #[doc(hidden)] __Unknown(i32), } impl fmt::Display for OptionArg { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "OptionArg::{}", match *self { Self::None => "None", Self::String => "String", Self::Int => "Int", Self::Callback => "Callback", Self::Filename => "Filename", Self::StringArray => "StringArray", Self::FilenameArray => "FilenameArray", Self::Double => "Double", Self::Int64 => "Int64", _ => "Unknown", } ) } } #[doc(hidden)] impl IntoGlib for OptionArg { type GlibType = ffi::GOptionArg; fn into_glib(self) -> ffi::GOptionArg { match self { Self::None => ffi::G_OPTION_ARG_NONE, Self::String => ffi::G_OPTION_ARG_STRING, Self::Int => ffi::G_OPTION_ARG_INT, Self::Callback => ffi::G_OPTION_ARG_CALLBACK, Self::Filename => ffi::G_OPTION_ARG_FILENAME, Self::StringArray => ffi::G_OPTION_ARG_STRING_ARRAY, Self::FilenameArray => ffi::G_OPTION_ARG_FILENAME_ARRAY, Self::Double => ffi::G_OPTION_ARG_DOUBLE, Self::Int64 => ffi::G_OPTION_ARG_INT64, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for OptionArg { unsafe fn from_glib(value: ffi::GOptionArg) -> Self { match value { ffi::G_OPTION_ARG_NONE => Self::None, ffi::G_OPTION_ARG_STRING => Self::String, ffi::G_OPTION_ARG_INT => Self::Int, ffi::G_OPTION_ARG_CALLBACK => Self::Callback, ffi::G_OPTION_ARG_FILENAME => Self::Filename, ffi::G_OPTION_ARG_STRING_ARRAY => Self::StringArray, ffi::G_OPTION_ARG_FILENAME_ARRAY => Self::FilenameArray, ffi::G_OPTION_ARG_DOUBLE => Self::Double, ffi::G_OPTION_ARG_INT64 => Self::Int64, value => Self::__Unknown(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GSeekType")] pub enum SeekType { #[doc(alias = "G_SEEK_CUR")] Cur, #[doc(alias = "G_SEEK_SET")] Set, #[doc(alias = "G_SEEK_END")] End, #[doc(hidden)] __Unknown(i32), } impl fmt::Display for SeekType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "SeekType::{}", match *self { Self::Cur => "Cur", Self::Set => "Set", Self::End => "End", _ => "Unknown", } ) } } #[doc(hidden)] impl IntoGlib for SeekType { type GlibType = ffi::GSeekType; fn into_glib(self) -> ffi::GSeekType { match self { Self::Cur => ffi::G_SEEK_CUR, Self::Set => ffi::G_SEEK_SET, Self::End => ffi::G_SEEK_END, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for SeekType { unsafe fn from_glib(value: ffi::GSeekType) -> Self { match value { ffi::G_SEEK_CUR => Self::Cur, ffi::G_SEEK_SET => Self::Set, ffi::G_SEEK_END => Self::End, value => Self::__Unknown(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GTimeType")] pub enum TimeType { #[doc(alias = "G_TIME_TYPE_STANDARD")] Standard, #[doc(alias = "G_TIME_TYPE_DAYLIGHT")] Daylight, #[doc(alias = "G_TIME_TYPE_UNIVERSAL")] Universal, #[doc(hidden)] __Unknown(i32), } impl fmt::Display for TimeType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "TimeType::{}", match *self { Self::Standard => "Standard", Self::Daylight => "Daylight", Self::Universal => "Universal", _ => "Unknown", } ) } } #[doc(hidden)] impl IntoGlib for TimeType { type GlibType = ffi::GTimeType; fn into_glib(self) -> ffi::GTimeType { match self { Self::Standard => ffi::G_TIME_TYPE_STANDARD, Self::Daylight => ffi::G_TIME_TYPE_DAYLIGHT, Self::Universal => ffi::G_TIME_TYPE_UNIVERSAL, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for TimeType { unsafe fn from_glib(value: ffi::GTimeType) -> Self { match value { ffi::G_TIME_TYPE_STANDARD => Self::Standard, ffi::G_TIME_TYPE_DAYLIGHT => Self::Daylight, ffi::G_TIME_TYPE_UNIVERSAL => Self::Universal, value => Self::__Unknown(value), } } } #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GUriError")] pub enum UriError { #[doc(alias = "G_URI_ERROR_FAILED")] Failed, #[doc(alias = "G_URI_ERROR_BAD_SCHEME")] BadScheme, #[doc(alias = "G_URI_ERROR_BAD_USER")] BadUser, #[doc(alias = "G_URI_ERROR_BAD_PASSWORD")] BadPassword, #[doc(alias = "G_URI_ERROR_BAD_AUTH_PARAMS")] BadAuthParams, #[doc(alias = "G_URI_ERROR_BAD_HOST")] BadHost, #[doc(alias = "G_URI_ERROR_BAD_PORT")] BadPort, #[doc(alias = "G_URI_ERROR_BAD_PATH")] BadPath, #[doc(alias = "G_URI_ERROR_BAD_QUERY")] BadQuery, #[doc(alias = "G_URI_ERROR_BAD_FRAGMENT")] BadFragment, #[doc(hidden)] __Unknown(i32), } #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] impl fmt::Display for UriError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "UriError::{}", match *self { Self::Failed => "Failed", Self::BadScheme => "BadScheme", Self::BadUser => "BadUser", Self::BadPassword => "BadPassword", Self::BadAuthParams => "BadAuthParams", Self::BadHost => "BadHost", Self::BadPort => "BadPort", Self::BadPath => "BadPath", Self::BadQuery => "BadQuery", Self::BadFragment => "BadFragment", _ => "Unknown", } ) } } #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl IntoGlib for UriError { type GlibType = ffi::GUriError; fn into_glib(self) -> ffi::GUriError { match self { Self::Failed => ffi::G_URI_ERROR_FAILED, Self::BadScheme => ffi::G_URI_ERROR_BAD_SCHEME, Self::BadUser => ffi::G_URI_ERROR_BAD_USER, Self::BadPassword => ffi::G_URI_ERROR_BAD_PASSWORD, Self::BadAuthParams => ffi::G_URI_ERROR_BAD_AUTH_PARAMS, Self::BadHost => ffi::G_URI_ERROR_BAD_HOST, Self::BadPort => ffi::G_URI_ERROR_BAD_PORT, Self::BadPath => ffi::G_URI_ERROR_BAD_PATH, Self::BadQuery => ffi::G_URI_ERROR_BAD_QUERY, Self::BadFragment => ffi::G_URI_ERROR_BAD_FRAGMENT, Self::__Unknown(value) => value, } } } #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl FromGlib for UriError { unsafe fn from_glib(value: ffi::GUriError) -> Self { match value { ffi::G_URI_ERROR_FAILED => Self::Failed, ffi::G_URI_ERROR_BAD_SCHEME => Self::BadScheme, ffi::G_URI_ERROR_BAD_USER => Self::BadUser, ffi::G_URI_ERROR_BAD_PASSWORD => Self::BadPassword, ffi::G_URI_ERROR_BAD_AUTH_PARAMS => Self::BadAuthParams, ffi::G_URI_ERROR_BAD_HOST => Self::BadHost, ffi::G_URI_ERROR_BAD_PORT => Self::BadPort, ffi::G_URI_ERROR_BAD_PATH => Self::BadPath, ffi::G_URI_ERROR_BAD_QUERY => Self::BadQuery, ffi::G_URI_ERROR_BAD_FRAGMENT => Self::BadFragment, value => Self::__Unknown(value), } } } #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] impl ErrorDomain for UriError { fn domain() -> Quark { unsafe { from_glib(ffi::g_uri_error_quark()) } } fn code(self) -> i32 { self.into_glib() } fn from(code: i32) -> Option { match code { ffi::G_URI_ERROR_FAILED => Some(Self::Failed), ffi::G_URI_ERROR_BAD_SCHEME => Some(Self::BadScheme), ffi::G_URI_ERROR_BAD_USER => Some(Self::BadUser), ffi::G_URI_ERROR_BAD_PASSWORD => Some(Self::BadPassword), ffi::G_URI_ERROR_BAD_AUTH_PARAMS => Some(Self::BadAuthParams), ffi::G_URI_ERROR_BAD_HOST => Some(Self::BadHost), ffi::G_URI_ERROR_BAD_PORT => Some(Self::BadPort), ffi::G_URI_ERROR_BAD_PATH => Some(Self::BadPath), ffi::G_URI_ERROR_BAD_QUERY => Some(Self::BadQuery), ffi::G_URI_ERROR_BAD_FRAGMENT => Some(Self::BadFragment), _ => Some(Self::Failed), } } } glib-0.14.8/src/auto/flags.rs000064400000000000000000000405210072674642500140660ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::translate::*; use crate::value::FromValue; use crate::value::ToValue; use crate::StaticType; use crate::Type; use bitflags::bitflags; use std::fmt; #[cfg(any(feature = "v2_66", feature = "dox"))] bitflags! { #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] #[doc(alias = "GFileSetContentsFlags")] pub struct FileSetContentsFlags: u32 { #[doc(alias = "G_FILE_SET_CONTENTS_NONE")] const NONE = ffi::G_FILE_SET_CONTENTS_NONE as u32; #[doc(alias = "G_FILE_SET_CONTENTS_CONSISTENT")] const CONSISTENT = ffi::G_FILE_SET_CONTENTS_CONSISTENT as u32; #[doc(alias = "G_FILE_SET_CONTENTS_DURABLE")] const DURABLE = ffi::G_FILE_SET_CONTENTS_DURABLE as u32; #[doc(alias = "G_FILE_SET_CONTENTS_ONLY_EXISTING")] const ONLY_EXISTING = ffi::G_FILE_SET_CONTENTS_ONLY_EXISTING as u32; } } #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] impl fmt::Display for FileSetContentsFlags { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, f) } } #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl IntoGlib for FileSetContentsFlags { type GlibType = ffi::GFileSetContentsFlags; fn into_glib(self) -> ffi::GFileSetContentsFlags { self.bits() } } #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl FromGlib for FileSetContentsFlags { unsafe fn from_glib(value: ffi::GFileSetContentsFlags) -> Self { Self::from_bits_truncate(value) } } bitflags! { #[doc(alias = "GFileTest")] pub struct FileTest: u32 { #[doc(alias = "G_FILE_TEST_IS_REGULAR")] const IS_REGULAR = ffi::G_FILE_TEST_IS_REGULAR as u32; #[doc(alias = "G_FILE_TEST_IS_SYMLINK")] const IS_SYMLINK = ffi::G_FILE_TEST_IS_SYMLINK as u32; #[doc(alias = "G_FILE_TEST_IS_DIR")] const IS_DIR = ffi::G_FILE_TEST_IS_DIR as u32; #[doc(alias = "G_FILE_TEST_IS_EXECUTABLE")] const IS_EXECUTABLE = ffi::G_FILE_TEST_IS_EXECUTABLE as u32; #[doc(alias = "G_FILE_TEST_EXISTS")] const EXISTS = ffi::G_FILE_TEST_EXISTS as u32; } } impl fmt::Display for FileTest { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, f) } } #[doc(hidden)] impl IntoGlib for FileTest { type GlibType = ffi::GFileTest; fn into_glib(self) -> ffi::GFileTest { self.bits() } } #[doc(hidden)] impl FromGlib for FileTest { unsafe fn from_glib(value: ffi::GFileTest) -> Self { Self::from_bits_truncate(value) } } bitflags! { #[doc(alias = "GFormatSizeFlags")] pub struct FormatSizeFlags: u32 { #[doc(alias = "G_FORMAT_SIZE_DEFAULT")] const DEFAULT = ffi::G_FORMAT_SIZE_DEFAULT as u32; #[doc(alias = "G_FORMAT_SIZE_LONG_FORMAT")] const LONG_FORMAT = ffi::G_FORMAT_SIZE_LONG_FORMAT as u32; #[doc(alias = "G_FORMAT_SIZE_IEC_UNITS")] const IEC_UNITS = ffi::G_FORMAT_SIZE_IEC_UNITS as u32; #[doc(alias = "G_FORMAT_SIZE_BITS")] const BITS = ffi::G_FORMAT_SIZE_BITS as u32; } } impl fmt::Display for FormatSizeFlags { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, f) } } #[doc(hidden)] impl IntoGlib for FormatSizeFlags { type GlibType = ffi::GFormatSizeFlags; fn into_glib(self) -> ffi::GFormatSizeFlags { self.bits() } } #[doc(hidden)] impl FromGlib for FormatSizeFlags { unsafe fn from_glib(value: ffi::GFormatSizeFlags) -> Self { Self::from_bits_truncate(value) } } bitflags! { #[doc(alias = "GIOCondition")] pub struct IOCondition: u32 { #[doc(alias = "G_IO_IN")] const IN = ffi::G_IO_IN as u32; #[doc(alias = "G_IO_OUT")] const OUT = ffi::G_IO_OUT as u32; #[doc(alias = "G_IO_PRI")] const PRI = ffi::G_IO_PRI as u32; #[doc(alias = "G_IO_ERR")] const ERR = ffi::G_IO_ERR as u32; #[doc(alias = "G_IO_HUP")] const HUP = ffi::G_IO_HUP as u32; #[doc(alias = "G_IO_NVAL")] const NVAL = ffi::G_IO_NVAL as u32; } } impl fmt::Display for IOCondition { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, f) } } #[doc(hidden)] impl IntoGlib for IOCondition { type GlibType = ffi::GIOCondition; fn into_glib(self) -> ffi::GIOCondition { self.bits() } } #[doc(hidden)] impl FromGlib for IOCondition { unsafe fn from_glib(value: ffi::GIOCondition) -> Self { Self::from_bits_truncate(value) } } impl StaticType for IOCondition { fn static_type() -> Type { unsafe { from_glib(ffi::g_io_condition_get_type()) } } } impl crate::value::ValueType for IOCondition { type Type = Self; } unsafe impl<'a> FromValue<'a> for IOCondition { type Checker = crate::value::GenericValueTypeChecker; unsafe fn from_value(value: &'a crate::Value) -> Self { from_glib(crate::gobject_ffi::g_value_get_flags( value.to_glib_none().0, )) } } impl ToValue for IOCondition { fn to_value(&self) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { crate::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } fn value_type(&self) -> crate::Type { Self::static_type() } } bitflags! { #[doc(alias = "GKeyFileFlags")] pub struct KeyFileFlags: u32 { #[doc(alias = "G_KEY_FILE_NONE")] const NONE = ffi::G_KEY_FILE_NONE as u32; #[doc(alias = "G_KEY_FILE_KEEP_COMMENTS")] const KEEP_COMMENTS = ffi::G_KEY_FILE_KEEP_COMMENTS as u32; #[doc(alias = "G_KEY_FILE_KEEP_TRANSLATIONS")] const KEEP_TRANSLATIONS = ffi::G_KEY_FILE_KEEP_TRANSLATIONS as u32; } } impl fmt::Display for KeyFileFlags { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, f) } } #[doc(hidden)] impl IntoGlib for KeyFileFlags { type GlibType = ffi::GKeyFileFlags; fn into_glib(self) -> ffi::GKeyFileFlags { self.bits() } } #[doc(hidden)] impl FromGlib for KeyFileFlags { unsafe fn from_glib(value: ffi::GKeyFileFlags) -> Self { Self::from_bits_truncate(value) } } bitflags! { #[doc(alias = "GLogLevelFlags")] pub struct LogLevelFlags: u32 { #[doc(alias = "G_LOG_FLAG_RECURSION")] const FLAG_RECURSION = ffi::G_LOG_FLAG_RECURSION as u32; #[doc(alias = "G_LOG_FLAG_FATAL")] const FLAG_FATAL = ffi::G_LOG_FLAG_FATAL as u32; #[doc(alias = "G_LOG_LEVEL_ERROR")] const LEVEL_ERROR = ffi::G_LOG_LEVEL_ERROR as u32; #[doc(alias = "G_LOG_LEVEL_CRITICAL")] const LEVEL_CRITICAL = ffi::G_LOG_LEVEL_CRITICAL as u32; #[doc(alias = "G_LOG_LEVEL_WARNING")] const LEVEL_WARNING = ffi::G_LOG_LEVEL_WARNING as u32; #[doc(alias = "G_LOG_LEVEL_MESSAGE")] const LEVEL_MESSAGE = ffi::G_LOG_LEVEL_MESSAGE as u32; #[doc(alias = "G_LOG_LEVEL_INFO")] const LEVEL_INFO = ffi::G_LOG_LEVEL_INFO as u32; #[doc(alias = "G_LOG_LEVEL_DEBUG")] const LEVEL_DEBUG = ffi::G_LOG_LEVEL_DEBUG as u32; #[doc(alias = "G_LOG_LEVEL_MASK")] const LEVEL_MASK = ffi::G_LOG_LEVEL_MASK as u32; } } impl fmt::Display for LogLevelFlags { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, f) } } #[doc(hidden)] impl IntoGlib for LogLevelFlags { type GlibType = ffi::GLogLevelFlags; fn into_glib(self) -> ffi::GLogLevelFlags { self.bits() } } #[doc(hidden)] impl FromGlib for LogLevelFlags { unsafe fn from_glib(value: ffi::GLogLevelFlags) -> Self { Self::from_bits_truncate(value) } } bitflags! { #[doc(alias = "GOptionFlags")] pub struct OptionFlags: u32 { #[doc(alias = "G_OPTION_FLAG_NONE")] const NONE = ffi::G_OPTION_FLAG_NONE as u32; #[doc(alias = "G_OPTION_FLAG_HIDDEN")] const HIDDEN = ffi::G_OPTION_FLAG_HIDDEN as u32; #[doc(alias = "G_OPTION_FLAG_IN_MAIN")] const IN_MAIN = ffi::G_OPTION_FLAG_IN_MAIN as u32; #[doc(alias = "G_OPTION_FLAG_REVERSE")] const REVERSE = ffi::G_OPTION_FLAG_REVERSE as u32; #[doc(alias = "G_OPTION_FLAG_NO_ARG")] const NO_ARG = ffi::G_OPTION_FLAG_NO_ARG as u32; #[doc(alias = "G_OPTION_FLAG_FILENAME")] const FILENAME = ffi::G_OPTION_FLAG_FILENAME as u32; #[doc(alias = "G_OPTION_FLAG_OPTIONAL_ARG")] const OPTIONAL_ARG = ffi::G_OPTION_FLAG_OPTIONAL_ARG as u32; #[doc(alias = "G_OPTION_FLAG_NOALIAS")] const NOALIAS = ffi::G_OPTION_FLAG_NOALIAS as u32; } } impl fmt::Display for OptionFlags { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, f) } } #[doc(hidden)] impl IntoGlib for OptionFlags { type GlibType = ffi::GOptionFlags; fn into_glib(self) -> ffi::GOptionFlags { self.bits() } } #[doc(hidden)] impl FromGlib for OptionFlags { unsafe fn from_glib(value: ffi::GOptionFlags) -> Self { Self::from_bits_truncate(value) } } bitflags! { #[doc(alias = "GSpawnFlags")] pub struct SpawnFlags: u32 { #[doc(alias = "G_SPAWN_DEFAULT")] const DEFAULT = ffi::G_SPAWN_DEFAULT as u32; #[doc(alias = "G_SPAWN_LEAVE_DESCRIPTORS_OPEN")] const LEAVE_DESCRIPTORS_OPEN = ffi::G_SPAWN_LEAVE_DESCRIPTORS_OPEN as u32; #[doc(alias = "G_SPAWN_DO_NOT_REAP_CHILD")] const DO_NOT_REAP_CHILD = ffi::G_SPAWN_DO_NOT_REAP_CHILD as u32; #[doc(alias = "G_SPAWN_SEARCH_PATH")] const SEARCH_PATH = ffi::G_SPAWN_SEARCH_PATH as u32; #[doc(alias = "G_SPAWN_STDOUT_TO_DEV_NULL")] const STDOUT_TO_DEV_NULL = ffi::G_SPAWN_STDOUT_TO_DEV_NULL as u32; #[doc(alias = "G_SPAWN_STDERR_TO_DEV_NULL")] const STDERR_TO_DEV_NULL = ffi::G_SPAWN_STDERR_TO_DEV_NULL as u32; #[doc(alias = "G_SPAWN_CHILD_INHERITS_STDIN")] const CHILD_INHERITS_STDIN = ffi::G_SPAWN_CHILD_INHERITS_STDIN as u32; #[doc(alias = "G_SPAWN_FILE_AND_ARGV_ZERO")] const FILE_AND_ARGV_ZERO = ffi::G_SPAWN_FILE_AND_ARGV_ZERO as u32; #[doc(alias = "G_SPAWN_SEARCH_PATH_FROM_ENVP")] const SEARCH_PATH_FROM_ENVP = ffi::G_SPAWN_SEARCH_PATH_FROM_ENVP as u32; #[doc(alias = "G_SPAWN_CLOEXEC_PIPES")] const CLOEXEC_PIPES = ffi::G_SPAWN_CLOEXEC_PIPES as u32; } } impl fmt::Display for SpawnFlags { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, f) } } #[doc(hidden)] impl IntoGlib for SpawnFlags { type GlibType = ffi::GSpawnFlags; fn into_glib(self) -> ffi::GSpawnFlags { self.bits() } } #[doc(hidden)] impl FromGlib for SpawnFlags { unsafe fn from_glib(value: ffi::GSpawnFlags) -> Self { Self::from_bits_truncate(value) } } #[cfg(any(feature = "v2_66", feature = "dox"))] bitflags! { #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] #[doc(alias = "GUriFlags")] pub struct UriFlags: u32 { #[doc(alias = "G_URI_FLAGS_NONE")] const NONE = ffi::G_URI_FLAGS_NONE as u32; #[doc(alias = "G_URI_FLAGS_PARSE_RELAXED")] const PARSE_RELAXED = ffi::G_URI_FLAGS_PARSE_RELAXED as u32; #[doc(alias = "G_URI_FLAGS_HAS_PASSWORD")] const HAS_PASSWORD = ffi::G_URI_FLAGS_HAS_PASSWORD as u32; #[doc(alias = "G_URI_FLAGS_HAS_AUTH_PARAMS")] const HAS_AUTH_PARAMS = ffi::G_URI_FLAGS_HAS_AUTH_PARAMS as u32; #[doc(alias = "G_URI_FLAGS_ENCODED")] const ENCODED = ffi::G_URI_FLAGS_ENCODED as u32; #[doc(alias = "G_URI_FLAGS_NON_DNS")] const NON_DNS = ffi::G_URI_FLAGS_NON_DNS as u32; #[doc(alias = "G_URI_FLAGS_ENCODED_QUERY")] const ENCODED_QUERY = ffi::G_URI_FLAGS_ENCODED_QUERY as u32; #[doc(alias = "G_URI_FLAGS_ENCODED_PATH")] const ENCODED_PATH = ffi::G_URI_FLAGS_ENCODED_PATH as u32; #[doc(alias = "G_URI_FLAGS_ENCODED_FRAGMENT")] const ENCODED_FRAGMENT = ffi::G_URI_FLAGS_ENCODED_FRAGMENT as u32; } } #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] impl fmt::Display for UriFlags { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, f) } } #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl IntoGlib for UriFlags { type GlibType = ffi::GUriFlags; fn into_glib(self) -> ffi::GUriFlags { self.bits() } } #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl FromGlib for UriFlags { unsafe fn from_glib(value: ffi::GUriFlags) -> Self { Self::from_bits_truncate(value) } } #[cfg(any(feature = "v2_66", feature = "dox"))] bitflags! { #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] #[doc(alias = "GUriHideFlags")] pub struct UriHideFlags: u32 { #[doc(alias = "G_URI_HIDE_NONE")] const NONE = ffi::G_URI_HIDE_NONE as u32; #[doc(alias = "G_URI_HIDE_USERINFO")] const USERINFO = ffi::G_URI_HIDE_USERINFO as u32; #[doc(alias = "G_URI_HIDE_PASSWORD")] const PASSWORD = ffi::G_URI_HIDE_PASSWORD as u32; #[doc(alias = "G_URI_HIDE_AUTH_PARAMS")] const AUTH_PARAMS = ffi::G_URI_HIDE_AUTH_PARAMS as u32; #[doc(alias = "G_URI_HIDE_QUERY")] const QUERY = ffi::G_URI_HIDE_QUERY as u32; #[doc(alias = "G_URI_HIDE_FRAGMENT")] const FRAGMENT = ffi::G_URI_HIDE_FRAGMENT as u32; } } #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] impl fmt::Display for UriHideFlags { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, f) } } #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl IntoGlib for UriHideFlags { type GlibType = ffi::GUriHideFlags; fn into_glib(self) -> ffi::GUriHideFlags { self.bits() } } #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl FromGlib for UriHideFlags { unsafe fn from_glib(value: ffi::GUriHideFlags) -> Self { Self::from_bits_truncate(value) } } #[cfg(any(feature = "v2_66", feature = "dox"))] bitflags! { #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] #[doc(alias = "GUriParamsFlags")] pub struct UriParamsFlags: u32 { #[doc(alias = "G_URI_PARAMS_NONE")] const NONE = ffi::G_URI_PARAMS_NONE as u32; #[doc(alias = "G_URI_PARAMS_CASE_INSENSITIVE")] const CASE_INSENSITIVE = ffi::G_URI_PARAMS_CASE_INSENSITIVE as u32; #[doc(alias = "G_URI_PARAMS_WWW_FORM")] const WWW_FORM = ffi::G_URI_PARAMS_WWW_FORM as u32; #[doc(alias = "G_URI_PARAMS_PARSE_RELAXED")] const PARSE_RELAXED = ffi::G_URI_PARAMS_PARSE_RELAXED as u32; } } #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] impl fmt::Display for UriParamsFlags { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, f) } } #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl IntoGlib for UriParamsFlags { type GlibType = ffi::GUriParamsFlags; fn into_glib(self) -> ffi::GUriParamsFlags { self.bits() } } #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl FromGlib for UriParamsFlags { unsafe fn from_glib(value: ffi::GUriParamsFlags) -> Self { Self::from_bits_truncate(value) } } glib-0.14.8/src/auto/functions.rs000064400000000000000000001475030072674642500150120ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::translate::*; use crate::Bytes; use crate::ChecksumType; use crate::Error; #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] use crate::FileSetContentsFlags; use crate::FileTest; use crate::FormatSizeFlags; use crate::Pid; use crate::Source; use crate::SpawnFlags; use crate::UserDirectory; use std::boxed::Box as Box_; use std::mem; use std::ptr; #[doc(alias = "g_access")] pub fn access>(filename: P, mode: i32) -> i32 { unsafe { ffi::g_access(filename.as_ref().to_glib_none().0, mode) } } #[doc(alias = "g_assert_warning")] pub fn assert_warning( log_domain: &str, file: &str, line: i32, pretty_function: &str, expression: &str, ) { unsafe { ffi::g_assert_warning( log_domain.to_glib_none().0, file.to_glib_none().0, line, pretty_function.to_glib_none().0, expression.to_glib_none().0, ); } } #[doc(alias = "g_assertion_message")] pub fn assertion_message(domain: &str, file: &str, line: i32, func: &str, message: &str) { unsafe { ffi::g_assertion_message( domain.to_glib_none().0, file.to_glib_none().0, line, func.to_glib_none().0, message.to_glib_none().0, ); } } //#[doc(alias = "g_assertion_message_cmpnum")] //pub fn assertion_message_cmpnum(domain: &str, file: &str, line: i32, func: &str, expr: &str, arg1: /*Unknown conversion*//*Unimplemented*/Unsupported, cmp: &str, arg2: /*Unknown conversion*//*Unimplemented*/Unsupported, numtype: crate::Char) { // unsafe { TODO: call ffi:g_assertion_message_cmpnum() } //} #[doc(alias = "g_assertion_message_cmpstr")] pub fn assertion_message_cmpstr( domain: &str, file: &str, line: i32, func: &str, expr: &str, arg1: &str, cmp: &str, arg2: &str, ) { unsafe { ffi::g_assertion_message_cmpstr( domain.to_glib_none().0, file.to_glib_none().0, line, func.to_glib_none().0, expr.to_glib_none().0, arg1.to_glib_none().0, cmp.to_glib_none().0, arg2.to_glib_none().0, ); } } #[doc(alias = "g_base64_decode")] pub fn base64_decode(text: &str) -> Vec { unsafe { let mut out_len = mem::MaybeUninit::uninit(); let ret = FromGlibContainer::from_glib_full_num( ffi::g_base64_decode(text.to_glib_none().0, out_len.as_mut_ptr()), out_len.assume_init() as usize, ); ret } } //#[doc(alias = "g_base64_decode_inplace")] //pub fn base64_decode_inplace(text: /*Unimplemented*/Vec) -> u8 { // unsafe { TODO: call ffi:g_base64_decode_inplace() } //} //#[doc(alias = "g_base64_decode_step")] //pub fn base64_decode_step(in_: &[u8], out: Vec, state: &mut i32, save: &mut u32) -> usize { // unsafe { TODO: call ffi:g_base64_decode_step() } //} #[doc(alias = "g_base64_encode")] pub fn base64_encode(data: &[u8]) -> crate::GString { let len = data.len() as usize; unsafe { from_glib_full(ffi::g_base64_encode(data.to_glib_none().0, len)) } } //#[doc(alias = "g_base64_encode_close")] //pub fn base64_encode_close(break_lines: bool, out: Vec, state: &mut i32, save: &mut i32) -> usize { // unsafe { TODO: call ffi:g_base64_encode_close() } //} //#[doc(alias = "g_base64_encode_step")] //pub fn base64_encode_step(in_: &[u8], break_lines: bool, out: Vec, state: &mut i32, save: &mut i32) -> usize { // unsafe { TODO: call ffi:g_base64_encode_step() } //} #[doc(alias = "g_bit_nth_lsf")] pub fn bit_nth_lsf(mask: libc::c_ulong, nth_bit: i32) -> i32 { unsafe { ffi::g_bit_nth_lsf(mask, nth_bit) } } #[doc(alias = "g_bit_nth_msf")] pub fn bit_nth_msf(mask: libc::c_ulong, nth_bit: i32) -> i32 { unsafe { ffi::g_bit_nth_msf(mask, nth_bit) } } #[doc(alias = "g_bit_storage")] pub fn bit_storage(number: libc::c_ulong) -> u32 { unsafe { ffi::g_bit_storage(number) } } //#[doc(alias = "g_build_filename")] //pub fn build_filename>(first_element: P, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> std::path::PathBuf { // unsafe { TODO: call ffi:g_build_filename() } //} //#[cfg(any(feature = "v2_56", feature = "dox"))] //#[cfg_attr(feature = "dox", doc(cfg(feature = "v2_56")))] //#[doc(alias = "g_build_filename_valist")] //pub fn build_filename_valist>(first_element: P, args: /*Unknown conversion*//*Unimplemented*/Unsupported) -> std::path::PathBuf { // unsafe { TODO: call ffi:g_build_filename_valist() } //} #[doc(alias = "g_build_filenamev")] pub fn build_filenamev(args: &[&std::path::Path]) -> std::path::PathBuf { unsafe { from_glib_full(ffi::g_build_filenamev(args.to_glib_none().0)) } } //#[doc(alias = "g_build_path")] //pub fn build_path, Q: AsRef>(separator: P, first_element: Q, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> std::path::PathBuf { // unsafe { TODO: call ffi:g_build_path() } //} #[doc(alias = "g_build_pathv")] pub fn build_pathv(separator: &str, args: &[&std::path::Path]) -> std::path::PathBuf { unsafe { from_glib_full(ffi::g_build_pathv( separator.to_glib_none().0, args.to_glib_none().0, )) } } #[cfg(any(feature = "v2_58", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_58")))] #[doc(alias = "g_canonicalize_filename")] pub fn canonicalize_filename, Q: AsRef>( filename: P, relative_to: Q, ) -> std::path::PathBuf { unsafe { from_glib_full(ffi::g_canonicalize_filename( filename.as_ref().to_glib_none().0, relative_to.as_ref().to_glib_none().0, )) } } #[doc(alias = "g_chdir")] pub fn chdir>(path: P) -> i32 { unsafe { ffi::g_chdir(path.as_ref().to_glib_none().0) } } #[doc(alias = "glib_check_version")] pub fn check_version( required_major: u32, required_minor: u32, required_micro: u32, ) -> crate::GString { unsafe { from_glib_none(ffi::glib_check_version( required_major, required_minor, required_micro, )) } } #[doc(alias = "g_clear_error")] pub fn clear_error() -> Result<(), crate::Error> { unsafe { let mut error = ptr::null_mut(); let _ = ffi::g_clear_error(&mut error); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } //#[cfg(any(feature = "v2_56", feature = "dox"))] //#[cfg_attr(feature = "dox", doc(cfg(feature = "v2_56")))] //#[doc(alias = "g_clear_handle_id")] //pub fn clear_handle_id(tag_ptr: u32, clear_func: P) { // unsafe { TODO: call ffi:g_clear_handle_id() } //} //#[cfg(any(feature = "v2_64", feature = "dox"))] //#[cfg_attr(feature = "dox", doc(cfg(feature = "v2_64")))] //#[doc(alias = "g_clear_list")] //pub fn clear_list(list_ptr: /*Unimplemented*/&[&Fundamental: Pointer]) { // unsafe { TODO: call ffi:g_clear_list() } //} //#[doc(alias = "g_clear_pointer")] //pub fn clear_pointer(pp: /*Unimplemented*/Fundamental: Pointer) { // unsafe { TODO: call ffi:g_clear_pointer() } //} //#[cfg(any(feature = "v2_64", feature = "dox"))] //#[cfg_attr(feature = "dox", doc(cfg(feature = "v2_64")))] //#[doc(alias = "g_clear_slist")] //pub fn clear_slist(slist_ptr: /*Unimplemented*/&[&Fundamental: Pointer]) { // unsafe { TODO: call ffi:g_clear_slist() } //} #[doc(alias = "g_compute_checksum_for_bytes")] pub fn compute_checksum_for_bytes( checksum_type: ChecksumType, data: &Bytes, ) -> Option { unsafe { from_glib_full(ffi::g_compute_checksum_for_bytes( checksum_type.into_glib(), data.to_glib_none().0, )) } } #[doc(alias = "g_compute_checksum_for_data")] pub fn compute_checksum_for_data( checksum_type: ChecksumType, data: &[u8], ) -> Option { let length = data.len() as usize; unsafe { from_glib_full(ffi::g_compute_checksum_for_data( checksum_type.into_glib(), data.to_glib_none().0, length, )) } } #[doc(alias = "g_compute_checksum_for_string")] pub fn compute_checksum_for_string( checksum_type: ChecksumType, str: &str, ) -> Option { let length = str.len() as isize; unsafe { from_glib_full(ffi::g_compute_checksum_for_string( checksum_type.into_glib(), str.to_glib_none().0, length, )) } } #[cfg(any(feature = "v2_50", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_50")))] #[doc(alias = "g_compute_hmac_for_bytes")] pub fn compute_hmac_for_bytes( digest_type: ChecksumType, key: &Bytes, data: &Bytes, ) -> crate::GString { unsafe { from_glib_full(ffi::g_compute_hmac_for_bytes( digest_type.into_glib(), key.to_glib_none().0, data.to_glib_none().0, )) } } #[doc(alias = "g_compute_hmac_for_data")] pub fn compute_hmac_for_data(digest_type: ChecksumType, key: &[u8], data: &[u8]) -> crate::GString { let key_len = key.len() as usize; let length = data.len() as usize; unsafe { from_glib_full(ffi::g_compute_hmac_for_data( digest_type.into_glib(), key.to_glib_none().0, key_len, data.to_glib_none().0, length, )) } } #[doc(alias = "g_compute_hmac_for_string")] pub fn compute_hmac_for_string(digest_type: ChecksumType, key: &[u8], str: &str) -> crate::GString { let key_len = key.len() as usize; let length = str.len() as isize; unsafe { from_glib_full(ffi::g_compute_hmac_for_string( digest_type.into_glib(), key.to_glib_none().0, key_len, str.to_glib_none().0, length, )) } } //#[doc(alias = "g_convert_with_iconv")] //pub fn convert_with_iconv(str: &[u8], converter: /*Ignored*/&IConv) -> Result<(Vec, usize), crate::Error> { // unsafe { TODO: call ffi:g_convert_with_iconv() } //} //#[doc(alias = "g_datalist_clear")] //pub fn datalist_clear(datalist: /*Ignored*/&mut Data) { // unsafe { TODO: call ffi:g_datalist_clear() } //} //#[doc(alias = "g_datalist_foreach")] //pub fn datalist_foreach(datalist: /*Ignored*/&mut Data, func: /*Unimplemented*/FnMut(Quark, /*Unimplemented*/Option), user_data: /*Unimplemented*/Option) { // unsafe { TODO: call ffi:g_datalist_foreach() } //} //#[doc(alias = "g_datalist_get_data")] //pub fn datalist_get_data(datalist: /*Ignored*/&mut Data, key: &str) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_datalist_get_data() } //} //#[doc(alias = "g_datalist_get_flags")] //pub fn datalist_get_flags(datalist: /*Ignored*/&mut Data) -> u32 { // unsafe { TODO: call ffi:g_datalist_get_flags() } //} //#[doc(alias = "g_datalist_id_dup_data")] //pub fn datalist_id_dup_data(datalist: /*Ignored*/&mut Data, key_id: Quark, dup_func: /*Unimplemented*/FnMut(/*Unimplemented*/Option) -> /*Unimplemented*/Option, user_data: /*Unimplemented*/Option) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_datalist_id_dup_data() } //} //#[doc(alias = "g_datalist_id_get_data")] //pub fn datalist_id_get_data(datalist: /*Ignored*/&mut Data, key_id: Quark) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_datalist_id_get_data() } //} //#[doc(alias = "g_datalist_id_remove_no_notify")] //pub fn datalist_id_remove_no_notify(datalist: /*Ignored*/&mut Data, key_id: Quark) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_datalist_id_remove_no_notify() } //} //#[doc(alias = "g_datalist_id_replace_data")] //pub fn datalist_id_replace_data(datalist: /*Ignored*/&mut Data, key_id: Quark, oldval: /*Unimplemented*/Option, newval: /*Unimplemented*/Option) -> Option { // unsafe { TODO: call ffi:g_datalist_id_replace_data() } //} //#[doc(alias = "g_datalist_id_set_data_full")] //pub fn datalist_id_set_data_full(datalist: /*Ignored*/&mut Data, key_id: Quark, data: /*Unimplemented*/Option) { // unsafe { TODO: call ffi:g_datalist_id_set_data_full() } //} //#[doc(alias = "g_datalist_init")] //pub fn datalist_init(datalist: /*Ignored*/&mut Data) { // unsafe { TODO: call ffi:g_datalist_init() } //} //#[doc(alias = "g_datalist_set_flags")] //pub fn datalist_set_flags(datalist: /*Ignored*/&mut Data, flags: u32) { // unsafe { TODO: call ffi:g_datalist_set_flags() } //} //#[doc(alias = "g_datalist_unset_flags")] //pub fn datalist_unset_flags(datalist: /*Ignored*/&mut Data, flags: u32) { // unsafe { TODO: call ffi:g_datalist_unset_flags() } //} //#[doc(alias = "g_dataset_destroy")] //pub fn dataset_destroy(dataset_location: /*Unimplemented*/Fundamental: Pointer) { // unsafe { TODO: call ffi:g_dataset_destroy() } //} //#[doc(alias = "g_dataset_foreach")] //pub fn dataset_foreach(dataset_location: /*Unimplemented*/Fundamental: Pointer, func: /*Unimplemented*/FnMut(Quark, /*Unimplemented*/Option), user_data: /*Unimplemented*/Option) { // unsafe { TODO: call ffi:g_dataset_foreach() } //} //#[doc(alias = "g_dataset_id_get_data")] //pub fn dataset_id_get_data(dataset_location: /*Unimplemented*/Fundamental: Pointer, key_id: Quark) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_dataset_id_get_data() } //} //#[doc(alias = "g_dataset_id_remove_no_notify")] //pub fn dataset_id_remove_no_notify(dataset_location: /*Unimplemented*/Fundamental: Pointer, key_id: Quark) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_dataset_id_remove_no_notify() } //} //#[doc(alias = "g_dataset_id_set_data_full")] //pub fn dataset_id_set_data_full(dataset_location: /*Unimplemented*/Fundamental: Pointer, key_id: Quark, data: /*Unimplemented*/Option) { // unsafe { TODO: call ffi:g_dataset_id_set_data_full() } //} #[doc(alias = "g_dcgettext")] pub fn dcgettext(domain: Option<&str>, msgid: &str, category: i32) -> crate::GString { unsafe { from_glib_none(ffi::g_dcgettext( domain.to_glib_none().0, msgid.to_glib_none().0, category, )) } } #[doc(alias = "g_dgettext")] pub fn dgettext(domain: Option<&str>, msgid: &str) -> crate::GString { unsafe { from_glib_none(ffi::g_dgettext( domain.to_glib_none().0, msgid.to_glib_none().0, )) } } //#[doc(alias = "g_direct_equal")] //pub fn direct_equal(v1: /*Unimplemented*/Option, v2: /*Unimplemented*/Option) -> bool { // unsafe { TODO: call ffi:g_direct_equal() } //} //#[doc(alias = "g_direct_hash")] //pub fn direct_hash(v: /*Unimplemented*/Option) -> u32 { // unsafe { TODO: call ffi:g_direct_hash() } //} #[doc(alias = "g_dngettext")] pub fn dngettext( domain: Option<&str>, msgid: &str, msgid_plural: &str, n: libc::c_ulong, ) -> crate::GString { unsafe { from_glib_none(ffi::g_dngettext( domain.to_glib_none().0, msgid.to_glib_none().0, msgid_plural.to_glib_none().0, n, )) } } //#[doc(alias = "g_double_equal")] //pub fn double_equal(v1: /*Unimplemented*/Fundamental: Pointer, v2: /*Unimplemented*/Fundamental: Pointer) -> bool { // unsafe { TODO: call ffi:g_double_equal() } //} //#[doc(alias = "g_double_hash")] //pub fn double_hash(v: /*Unimplemented*/Fundamental: Pointer) -> u32 { // unsafe { TODO: call ffi:g_double_hash() } //} #[doc(alias = "g_dpgettext")] pub fn dpgettext(domain: Option<&str>, msgctxtid: &str, msgidoffset: usize) -> crate::GString { unsafe { from_glib_none(ffi::g_dpgettext( domain.to_glib_none().0, msgctxtid.to_glib_none().0, msgidoffset, )) } } #[doc(alias = "g_dpgettext2")] pub fn dpgettext2(domain: Option<&str>, context: &str, msgid: &str) -> crate::GString { unsafe { from_glib_none(ffi::g_dpgettext2( domain.to_glib_none().0, context.to_glib_none().0, msgid.to_glib_none().0, )) } } //#[doc(alias = "g_file_error_from_errno")] //pub fn file_error_from_errno(err_no: i32) -> /*Ignored*/FileError { // unsafe { TODO: call ffi:g_file_error_from_errno() } //} #[doc(alias = "g_file_get_contents")] pub fn file_get_contents>(filename: P) -> Result, crate::Error> { unsafe { let mut contents = ptr::null_mut(); let mut length = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let _ = ffi::g_file_get_contents( filename.as_ref().to_glib_none().0, &mut contents, length.as_mut_ptr(), &mut error, ); if error.is_null() { Ok(FromGlibContainer::from_glib_full_num( contents, length.assume_init() as usize, )) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_file_open_tmp")] pub fn file_open_tmp>( tmpl: P, ) -> Result<(i32, std::path::PathBuf), crate::Error> { unsafe { let mut name_used = ptr::null_mut(); let mut error = ptr::null_mut(); let ret = ffi::g_file_open_tmp(tmpl.as_ref().to_glib_none().0, &mut name_used, &mut error); if error.is_null() { Ok((ret, from_glib_full(name_used))) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_file_read_link")] pub fn file_read_link>( filename: P, ) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_file_read_link(filename.as_ref().to_glib_none().0, &mut error); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_file_set_contents")] pub fn file_set_contents>( filename: P, contents: &[u8], ) -> Result<(), crate::Error> { let length = contents.len() as isize; unsafe { let mut error = ptr::null_mut(); let _ = ffi::g_file_set_contents( filename.as_ref().to_glib_none().0, contents.to_glib_none().0, length, &mut error, ); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] #[doc(alias = "g_file_set_contents_full")] pub fn file_set_contents_full>( filename: P, contents: &[u8], flags: FileSetContentsFlags, mode: i32, ) -> Result<(), crate::Error> { let length = contents.len() as isize; unsafe { let mut error = ptr::null_mut(); let _ = ffi::g_file_set_contents_full( filename.as_ref().to_glib_none().0, contents.to_glib_none().0, length, flags.into_glib(), mode, &mut error, ); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_file_test")] pub fn file_test>(filename: P, test: FileTest) -> bool { unsafe { from_glib(ffi::g_file_test( filename.as_ref().to_glib_none().0, test.into_glib(), )) } } #[doc(alias = "g_filename_display_basename")] pub fn filename_display_basename>(filename: P) -> crate::GString { unsafe { from_glib_full(ffi::g_filename_display_basename( filename.as_ref().to_glib_none().0, )) } } #[doc(alias = "g_filename_display_name")] pub fn filename_display_name>(filename: P) -> crate::GString { unsafe { from_glib_full(ffi::g_filename_display_name( filename.as_ref().to_glib_none().0, )) } } #[doc(alias = "g_format_size")] pub fn format_size(size: u64) -> crate::GString { unsafe { from_glib_full(ffi::g_format_size(size)) } } #[doc(alias = "g_format_size_full")] pub fn format_size_full(size: u64, flags: FormatSizeFlags) -> crate::GString { unsafe { from_glib_full(ffi::g_format_size_full(size, flags.into_glib())) } } //#[doc(alias = "g_fprintf")] //pub fn fprintf(file: /*Unimplemented*/Fundamental: Pointer, format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> i32 { // unsafe { TODO: call ffi:g_fprintf() } //} //#[doc(alias = "g_free")] //pub fn free(mem: /*Unimplemented*/Option) { // unsafe { TODO: call ffi:g_free() } //} #[doc(alias = "g_get_application_name")] #[doc(alias = "get_application_name")] pub fn application_name() -> Option { unsafe { from_glib_none(ffi::g_get_application_name()) } } #[doc(alias = "g_get_codeset")] #[doc(alias = "get_codeset")] pub fn codeset() -> crate::GString { unsafe { from_glib_full(ffi::g_get_codeset()) } } #[cfg(any(feature = "v2_62", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_62")))] #[doc(alias = "g_get_console_charset")] #[doc(alias = "get_console_charset")] pub fn console_charset() -> Option { unsafe { let mut charset = ptr::null(); let ret = from_glib(ffi::g_get_console_charset(&mut charset)); if ret { Some(from_glib_none(charset)) } else { None } } } //#[cfg_attr(feature = "v2_62", deprecated = "Since 2.62")] //#[doc(alias = "g_get_current_time")] //#[doc(alias = "get_current_time")] //pub fn current_time(result: /*Ignored*/&mut TimeVal) { // unsafe { TODO: call ffi:g_get_current_time() } //} #[doc(alias = "g_get_environ")] #[doc(alias = "get_environ")] pub fn environ() -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::g_get_environ()) } } #[doc(alias = "g_get_host_name")] #[doc(alias = "get_host_name")] pub fn host_name() -> crate::GString { unsafe { from_glib_none(ffi::g_get_host_name()) } } #[doc(alias = "g_get_language_names")] #[doc(alias = "get_language_names")] pub fn language_names() -> Vec { unsafe { FromGlibPtrContainer::from_glib_none(ffi::g_get_language_names()) } } #[cfg(any(feature = "v2_58", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_58")))] #[doc(alias = "g_get_language_names_with_category")] #[doc(alias = "get_language_names_with_category")] pub fn language_names_with_category(category_name: &str) -> Vec { unsafe { FromGlibPtrContainer::from_glib_none(ffi::g_get_language_names_with_category( category_name.to_glib_none().0, )) } } #[doc(alias = "g_get_locale_variants")] #[doc(alias = "get_locale_variants")] pub fn locale_variants(locale: &str) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::g_get_locale_variants(locale.to_glib_none().0)) } } #[doc(alias = "g_get_monotonic_time")] #[doc(alias = "get_monotonic_time")] pub fn monotonic_time() -> i64 { unsafe { ffi::g_get_monotonic_time() } } #[doc(alias = "g_get_num_processors")] #[doc(alias = "get_num_processors")] pub fn num_processors() -> u32 { unsafe { ffi::g_get_num_processors() } } #[cfg(any(feature = "v2_64", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_64")))] #[doc(alias = "g_get_os_info")] #[doc(alias = "get_os_info")] pub fn os_info(key_name: &str) -> Option { unsafe { from_glib_full(ffi::g_get_os_info(key_name.to_glib_none().0)) } } #[doc(alias = "g_get_real_time")] #[doc(alias = "get_real_time")] pub fn real_time() -> i64 { unsafe { ffi::g_get_real_time() } } #[doc(alias = "g_get_system_config_dirs")] #[doc(alias = "get_system_config_dirs")] pub fn system_config_dirs() -> Vec { unsafe { FromGlibPtrContainer::from_glib_none(ffi::g_get_system_config_dirs()) } } #[doc(alias = "g_get_system_data_dirs")] #[doc(alias = "get_system_data_dirs")] pub fn system_data_dirs() -> Vec { unsafe { FromGlibPtrContainer::from_glib_none(ffi::g_get_system_data_dirs()) } } #[doc(alias = "g_get_user_cache_dir")] #[doc(alias = "get_user_cache_dir")] pub fn user_cache_dir() -> std::path::PathBuf { unsafe { from_glib_none(ffi::g_get_user_cache_dir()) } } #[doc(alias = "g_get_user_config_dir")] #[doc(alias = "get_user_config_dir")] pub fn user_config_dir() -> std::path::PathBuf { unsafe { from_glib_none(ffi::g_get_user_config_dir()) } } #[doc(alias = "g_get_user_data_dir")] #[doc(alias = "get_user_data_dir")] pub fn user_data_dir() -> std::path::PathBuf { unsafe { from_glib_none(ffi::g_get_user_data_dir()) } } #[doc(alias = "g_get_user_runtime_dir")] #[doc(alias = "get_user_runtime_dir")] pub fn user_runtime_dir() -> std::path::PathBuf { unsafe { from_glib_none(ffi::g_get_user_runtime_dir()) } } #[doc(alias = "g_get_user_special_dir")] #[doc(alias = "get_user_special_dir")] pub fn user_special_dir(directory: UserDirectory) -> std::path::PathBuf { unsafe { from_glib_none(ffi::g_get_user_special_dir(directory.into_glib())) } } #[doc(alias = "g_hostname_is_ascii_encoded")] pub fn hostname_is_ascii_encoded(hostname: &str) -> bool { unsafe { from_glib(ffi::g_hostname_is_ascii_encoded(hostname.to_glib_none().0)) } } #[doc(alias = "g_hostname_is_ip_address")] pub fn hostname_is_ip_address(hostname: &str) -> bool { unsafe { from_glib(ffi::g_hostname_is_ip_address(hostname.to_glib_none().0)) } } #[doc(alias = "g_hostname_is_non_ascii")] pub fn hostname_is_non_ascii(hostname: &str) -> bool { unsafe { from_glib(ffi::g_hostname_is_non_ascii(hostname.to_glib_none().0)) } } #[doc(alias = "g_hostname_to_ascii")] pub fn hostname_to_ascii(hostname: &str) -> Option { unsafe { from_glib_full(ffi::g_hostname_to_ascii(hostname.to_glib_none().0)) } } #[doc(alias = "g_hostname_to_unicode")] pub fn hostname_to_unicode(hostname: &str) -> Option { unsafe { from_glib_full(ffi::g_hostname_to_unicode(hostname.to_glib_none().0)) } } //#[doc(alias = "g_iconv")] //pub fn iconv(converter: /*Ignored*/&IConv, inbuf: &str, inbytes_left: usize, outbuf: &str, outbytes_left: usize) -> usize { // unsafe { TODO: call ffi:g_iconv() } //} //#[doc(alias = "g_idle_remove_by_data")] //pub fn idle_remove_by_data(data: /*Unimplemented*/Option) -> bool { // unsafe { TODO: call ffi:g_idle_remove_by_data() } //} //#[doc(alias = "g_int64_equal")] //pub fn int64_equal(v1: /*Unimplemented*/Fundamental: Pointer, v2: /*Unimplemented*/Fundamental: Pointer) -> bool { // unsafe { TODO: call ffi:g_int64_equal() } //} //#[doc(alias = "g_int64_hash")] //pub fn int64_hash(v: /*Unimplemented*/Fundamental: Pointer) -> u32 { // unsafe { TODO: call ffi:g_int64_hash() } //} //#[doc(alias = "g_int_equal")] //pub fn int_equal(v1: /*Unimplemented*/Fundamental: Pointer, v2: /*Unimplemented*/Fundamental: Pointer) -> bool { // unsafe { TODO: call ffi:g_int_equal() } //} //#[doc(alias = "g_int_hash")] //pub fn int_hash(v: /*Unimplemented*/Fundamental: Pointer) -> u32 { // unsafe { TODO: call ffi:g_int_hash() } //} //#[doc(alias = "g_io_add_watch")] //pub fn io_add_watch(channel: /*Ignored*/&IOChannel, condition: IOCondition, func: /*Unimplemented*/Fn(/*Ignored*/IOChannel, &IOCondition, /*Unimplemented*/Option) -> bool, user_data: /*Unimplemented*/Option) -> u32 { // unsafe { TODO: call ffi:g_io_add_watch() } //} //#[doc(alias = "g_io_add_watch_full")] //pub fn io_add_watch_full(channel: /*Ignored*/&IOChannel, priority: i32, condition: IOCondition, func: /*Unimplemented*/Fn(/*Ignored*/IOChannel, &IOCondition, /*Unimplemented*/Option) -> bool, user_data: /*Unimplemented*/Option) -> u32 { // unsafe { TODO: call ffi:g_io_add_watch_full() } //} //#[doc(alias = "g_io_create_watch")] //pub fn io_create_watch(channel: /*Ignored*/&IOChannel, condition: IOCondition) -> Source { // unsafe { TODO: call ffi:g_io_create_watch() } //} #[doc(alias = "g_listenv")] pub fn listenv() -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::g_listenv()) } } //#[cfg(any(feature = "v2_50", feature = "dox"))] //#[cfg_attr(feature = "dox", doc(cfg(feature = "v2_50")))] //#[doc(alias = "g_log_structured_array")] //pub fn log_structured_array(log_level: LogLevelFlags, fields: /*Ignored*/&[&LogField]) { // unsafe { TODO: call ffi:g_log_structured_array() } //} //#[doc(alias = "g_log_structured_standard")] //pub fn log_structured_standard(log_domain: &str, log_level: LogLevelFlags, file: &str, line: &str, func: &str, message_format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) { // unsafe { TODO: call ffi:g_log_structured_standard() } //} //#[cfg(any(feature = "v2_50", feature = "dox"))] //#[cfg_attr(feature = "dox", doc(cfg(feature = "v2_50")))] //#[doc(alias = "g_log_writer_default")] //pub fn log_writer_default(log_level: LogLevelFlags, fields: /*Ignored*/&[&LogField], user_data: /*Unimplemented*/Option) -> /*Ignored*/LogWriterOutput { // unsafe { TODO: call ffi:g_log_writer_default() } //} //#[cfg(any(feature = "v2_50", feature = "dox"))] //#[cfg_attr(feature = "dox", doc(cfg(feature = "v2_50")))] //#[doc(alias = "g_log_writer_format_fields")] //pub fn log_writer_format_fields(log_level: LogLevelFlags, fields: /*Ignored*/&[&LogField], use_color: bool) -> crate::GString { // unsafe { TODO: call ffi:g_log_writer_format_fields() } //} //#[cfg(any(feature = "v2_50", feature = "dox"))] //#[cfg_attr(feature = "dox", doc(cfg(feature = "v2_50")))] //#[doc(alias = "g_log_writer_journald")] //pub fn log_writer_journald(log_level: LogLevelFlags, fields: /*Ignored*/&[&LogField], user_data: /*Unimplemented*/Option) -> /*Ignored*/LogWriterOutput { // unsafe { TODO: call ffi:g_log_writer_journald() } //} //#[cfg(any(feature = "v2_50", feature = "dox"))] //#[cfg_attr(feature = "dox", doc(cfg(feature = "v2_50")))] //#[doc(alias = "g_log_writer_standard_streams")] //pub fn log_writer_standard_streams(log_level: LogLevelFlags, fields: /*Ignored*/&[&LogField], user_data: /*Unimplemented*/Option) -> /*Ignored*/LogWriterOutput { // unsafe { TODO: call ffi:g_log_writer_standard_streams() } //} //#[doc(alias = "g_logv")] //pub fn logv(log_domain: Option<&str>, log_level: LogLevelFlags, format: &str, args: /*Unknown conversion*//*Unimplemented*/Unsupported) { // unsafe { TODO: call ffi:g_logv() } //} #[doc(alias = "g_main_current_source")] pub fn main_current_source() -> Option { unsafe { from_glib_none(ffi::g_main_current_source()) } } #[doc(alias = "g_main_depth")] pub fn main_depth() -> i32 { unsafe { ffi::g_main_depth() } } //#[doc(alias = "g_malloc")] //pub fn malloc(n_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_malloc() } //} //#[doc(alias = "g_malloc0")] //pub fn malloc0(n_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_malloc0() } //} //#[doc(alias = "g_malloc0_n")] //pub fn malloc0_n(n_blocks: usize, n_block_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_malloc0_n() } //} //#[doc(alias = "g_malloc_n")] //pub fn malloc_n(n_blocks: usize, n_block_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_malloc_n() } //} //#[doc(alias = "g_markup_collect_attributes")] //pub fn markup_collect_attributes(element_name: &str, attribute_names: &str, attribute_values: &str, error: &mut Error, first_type: /*Ignored*/MarkupCollectType, first_attr: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> bool { // unsafe { TODO: call ffi:g_markup_collect_attributes() } //} #[doc(alias = "g_markup_escape_text")] pub fn markup_escape_text(text: &str) -> crate::GString { let length = text.len() as isize; unsafe { from_glib_full(ffi::g_markup_escape_text(text.to_glib_none().0, length)) } } //#[doc(alias = "g_markup_printf_escaped")] //pub fn markup_printf_escaped(format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> crate::GString { // unsafe { TODO: call ffi:g_markup_printf_escaped() } //} //#[doc(alias = "g_markup_vprintf_escaped")] //pub fn markup_vprintf_escaped(format: &str, args: /*Unknown conversion*//*Unimplemented*/Unsupported) -> crate::GString { // unsafe { TODO: call ffi:g_markup_vprintf_escaped() } //} //#[cfg_attr(feature = "v2_68", deprecated = "Since 2.68")] //#[doc(alias = "g_memdup")] //pub fn memdup(mem: /*Unimplemented*/Option, byte_size: u32) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_memdup() } //} #[doc(alias = "g_mkdir_with_parents")] pub fn mkdir_with_parents>(pathname: P, mode: i32) -> i32 { unsafe { ffi::g_mkdir_with_parents(pathname.as_ref().to_glib_none().0, mode) } } #[doc(alias = "g_mkdtemp")] pub fn mkdtemp>(tmpl: P) -> Option { unsafe { from_glib_full(ffi::g_mkdtemp(tmpl.as_ref().to_glib_none().0)) } } #[doc(alias = "g_mkdtemp_full")] pub fn mkdtemp_full>(tmpl: P, mode: i32) -> Option { unsafe { from_glib_full(ffi::g_mkdtemp_full(tmpl.as_ref().to_glib_none().0, mode)) } } #[doc(alias = "g_mkstemp_full")] pub fn mkstemp_full>(tmpl: P, flags: i32, mode: i32) -> i32 { unsafe { ffi::g_mkstemp_full(tmpl.as_ref().to_glib_none().0, flags, mode) } } //#[doc(alias = "g_nullify_pointer")] //pub fn nullify_pointer(nullify_location: /*Unimplemented*/Fundamental: Pointer) { // unsafe { TODO: call ffi:g_nullify_pointer() } //} #[doc(alias = "g_on_error_query")] pub fn on_error_query(prg_name: &str) { unsafe { ffi::g_on_error_query(prg_name.to_glib_none().0); } } #[doc(alias = "g_on_error_stack_trace")] pub fn on_error_stack_trace(prg_name: &str) { unsafe { ffi::g_on_error_stack_trace(prg_name.to_glib_none().0); } } //#[doc(alias = "g_parse_debug_string")] //pub fn parse_debug_string(string: Option<&str>, keys: /*Ignored*/&[&DebugKey]) -> u32 { // unsafe { TODO: call ffi:g_parse_debug_string() } //} #[doc(alias = "g_path_get_basename")] pub fn path_get_basename>(file_name: P) -> std::path::PathBuf { unsafe { from_glib_full(ffi::g_path_get_basename( file_name.as_ref().to_glib_none().0, )) } } #[doc(alias = "g_path_get_dirname")] pub fn path_get_dirname>(file_name: P) -> std::path::PathBuf { unsafe { from_glib_full(ffi::g_path_get_dirname(file_name.as_ref().to_glib_none().0)) } } #[doc(alias = "g_path_is_absolute")] pub fn path_is_absolute>(file_name: P) -> bool { unsafe { from_glib(ffi::g_path_is_absolute(file_name.as_ref().to_glib_none().0)) } } #[doc(alias = "g_path_skip_root")] pub fn path_skip_root>(file_name: P) -> Option { unsafe { from_glib_none(ffi::g_path_skip_root(file_name.as_ref().to_glib_none().0)) } } //#[doc(alias = "g_pattern_match")] //pub fn pattern_match(pspec: /*Ignored*/&mut PatternSpec, string_length: u32, string: &str, string_reversed: Option<&str>) -> bool { // unsafe { TODO: call ffi:g_pattern_match() } //} #[doc(alias = "g_pattern_match_simple")] pub fn pattern_match_simple(pattern: &str, string: &str) -> bool { unsafe { from_glib(ffi::g_pattern_match_simple( pattern.to_glib_none().0, string.to_glib_none().0, )) } } //#[doc(alias = "g_pattern_match_string")] //pub fn pattern_match_string(pspec: /*Ignored*/&mut PatternSpec, string: &str) -> bool { // unsafe { TODO: call ffi:g_pattern_match_string() } //} //#[doc(alias = "g_pointer_bit_lock")] //pub fn pointer_bit_lock(address: /*Unimplemented*/Fundamental: Pointer, lock_bit: i32) { // unsafe { TODO: call ffi:g_pointer_bit_lock() } //} //#[doc(alias = "g_pointer_bit_trylock")] //pub fn pointer_bit_trylock(address: /*Unimplemented*/Fundamental: Pointer, lock_bit: i32) -> bool { // unsafe { TODO: call ffi:g_pointer_bit_trylock() } //} //#[doc(alias = "g_pointer_bit_unlock")] //pub fn pointer_bit_unlock(address: /*Unimplemented*/Fundamental: Pointer, lock_bit: i32) { // unsafe { TODO: call ffi:g_pointer_bit_unlock() } //} //#[doc(alias = "g_poll")] //pub fn poll(fds: /*Ignored*/&mut PollFD, nfds: u32, timeout: i32) -> i32 { // unsafe { TODO: call ffi:g_poll() } //} //#[doc(alias = "g_prefix_error")] //pub fn prefix_error(err: /*Unimplemented*/Option, format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) { // unsafe { TODO: call ffi:g_prefix_error() } //} //#[doc(alias = "g_print")] //pub fn print(format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) { // unsafe { TODO: call ffi:g_print() } //} //#[doc(alias = "g_printerr")] //pub fn printerr(format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) { // unsafe { TODO: call ffi:g_printerr() } //} //#[doc(alias = "g_printf")] //pub fn printf(format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> i32 { // unsafe { TODO: call ffi:g_printf() } //} //#[doc(alias = "g_printf_string_upper_bound")] //pub fn printf_string_upper_bound(format: &str, args: /*Unknown conversion*//*Unimplemented*/Unsupported) -> usize { // unsafe { TODO: call ffi:g_printf_string_upper_bound() } //} //#[doc(alias = "g_propagate_prefixed_error")] //pub fn propagate_prefixed_error(dest: &mut Error, src: &mut Error, format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) { // unsafe { TODO: call ffi:g_propagate_prefixed_error() } //} //#[doc(alias = "g_qsort_with_data")] //pub fn qsort_with_data(pbase: /*Unimplemented*/Fundamental: Pointer, total_elems: i32, size: usize, compare_func: /*Unimplemented*/Fn(/*Unimplemented*/Option, /*Unimplemented*/Option) -> i32, user_data: /*Unimplemented*/Option) { // unsafe { TODO: call ffi:g_qsort_with_data() } //} #[doc(alias = "g_random_double")] pub fn random_double() -> f64 { unsafe { ffi::g_random_double() } } #[doc(alias = "g_random_double_range")] pub fn random_double_range(begin: f64, end: f64) -> f64 { unsafe { ffi::g_random_double_range(begin, end) } } #[doc(alias = "g_random_int")] pub fn random_int() -> u32 { unsafe { ffi::g_random_int() } } #[doc(alias = "g_random_int_range")] pub fn random_int_range(begin: i32, end: i32) -> i32 { unsafe { ffi::g_random_int_range(begin, end) } } #[doc(alias = "g_random_set_seed")] pub fn random_set_seed(seed: u32) { unsafe { ffi::g_random_set_seed(seed); } } //#[doc(alias = "g_realloc")] //pub fn realloc(mem: /*Unimplemented*/Option, n_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_realloc() } //} //#[doc(alias = "g_realloc_n")] //pub fn realloc_n(mem: /*Unimplemented*/Option, n_blocks: usize, n_block_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_realloc_n() } //} #[doc(alias = "g_reload_user_special_dirs_cache")] pub fn reload_user_special_dirs_cache() { unsafe { ffi::g_reload_user_special_dirs_cache(); } } #[doc(alias = "g_return_if_fail_warning")] pub fn return_if_fail_warning( log_domain: Option<&str>, pretty_function: &str, expression: Option<&str>, ) { unsafe { ffi::g_return_if_fail_warning( log_domain.to_glib_none().0, pretty_function.to_glib_none().0, expression.to_glib_none().0, ); } } #[doc(alias = "g_rmdir")] pub fn rmdir>(filename: P) -> i32 { unsafe { ffi::g_rmdir(filename.as_ref().to_glib_none().0) } } #[doc(alias = "g_set_application_name")] pub fn set_application_name(application_name: &str) { unsafe { ffi::g_set_application_name(application_name.to_glib_none().0); } } //#[doc(alias = "g_set_error")] //pub fn set_error(domain: Quark, code: i32, format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> Error { // unsafe { TODO: call ffi:g_set_error() } //} //#[doc(alias = "g_set_print_handler")] //pub fn set_print_handler(func: P) -> Fn(&str) + 'static { // unsafe { TODO: call ffi:g_set_print_handler() } //} //#[doc(alias = "g_set_printerr_handler")] //pub fn set_printerr_handler(func: P) -> Fn(&str) + 'static { // unsafe { TODO: call ffi:g_set_printerr_handler() } //} #[doc(alias = "g_shell_parse_argv")] pub fn shell_parse_argv>( command_line: P, ) -> Result, crate::Error> { unsafe { let mut argcp = mem::MaybeUninit::uninit(); let mut argvp = ptr::null_mut(); let mut error = ptr::null_mut(); let _ = ffi::g_shell_parse_argv( command_line.as_ref().to_glib_none().0, argcp.as_mut_ptr(), &mut argvp, &mut error, ); if error.is_null() { Ok(FromGlibContainer::from_glib_full_num( argvp, argcp.assume_init() as usize, )) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_shell_quote")] pub fn shell_quote>(unquoted_string: P) -> std::ffi::OsString { unsafe { from_glib_full(ffi::g_shell_quote( unquoted_string.as_ref().to_glib_none().0, )) } } #[doc(alias = "g_shell_unquote")] pub fn shell_unquote>( quoted_string: P, ) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_shell_unquote(quoted_string.as_ref().to_glib_none().0, &mut error); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } //#[doc(alias = "g_slice_alloc")] //pub fn slice_alloc(block_size: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_slice_alloc() } //} //#[doc(alias = "g_slice_alloc0")] //pub fn slice_alloc0(block_size: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_slice_alloc0() } //} //#[doc(alias = "g_slice_copy")] //pub fn slice_copy(block_size: usize, mem_block: /*Unimplemented*/Option) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_slice_copy() } //} //#[doc(alias = "g_slice_free1")] //pub fn slice_free1(block_size: usize, mem_block: /*Unimplemented*/Option) { // unsafe { TODO: call ffi:g_slice_free1() } //} //#[doc(alias = "g_slice_free_chain_with_offset")] //pub fn slice_free_chain_with_offset(block_size: usize, mem_chain: /*Unimplemented*/Option, next_offset: usize) { // unsafe { TODO: call ffi:g_slice_free_chain_with_offset() } //} //#[doc(alias = "g_slice_get_config")] //pub fn slice_get_config(ckey: /*Ignored*/SliceConfig) -> i64 { // unsafe { TODO: call ffi:g_slice_get_config() } //} //#[doc(alias = "g_slice_get_config_state")] //pub fn slice_get_config_state(ckey: /*Ignored*/SliceConfig, address: i64, n_values: u32) -> i64 { // unsafe { TODO: call ffi:g_slice_get_config_state() } //} //#[doc(alias = "g_slice_set_config")] //pub fn slice_set_config(ckey: /*Ignored*/SliceConfig, value: i64) { // unsafe { TODO: call ffi:g_slice_set_config() } //} //#[doc(alias = "g_snprintf")] //pub fn snprintf(string: &str, n: libc::c_ulong, format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> i32 { // unsafe { TODO: call ffi:g_snprintf() } //} #[doc(alias = "g_spaced_primes_closest")] pub fn spaced_primes_closest(num: u32) -> u32 { unsafe { ffi::g_spaced_primes_closest(num) } } #[doc(alias = "g_spawn_async")] pub fn spawn_async>( working_directory: P, argv: &[&std::path::Path], envp: &[&std::path::Path], flags: SpawnFlags, child_setup: Option>, ) -> Result { let child_setup_data: Box_>> = Box_::new(child_setup); unsafe extern "C" fn child_setup_func>(user_data: ffi::gpointer) { let callback: Box_>> = Box_::from_raw(user_data as *mut _); let callback = (*callback).expect("cannot get closure..."); callback() } let child_setup = if child_setup_data.is_some() { Some(child_setup_func::

as _) } else { None }; let super_callback0: Box_>> = child_setup_data; unsafe { let mut child_pid = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let _ = ffi::g_spawn_async( working_directory.as_ref().to_glib_none().0, argv.to_glib_none().0, envp.to_glib_none().0, flags.into_glib(), child_setup, Box_::into_raw(super_callback0) as *mut _, child_pid.as_mut_ptr(), &mut error, ); let child_pid = from_glib(child_pid.assume_init()); if error.is_null() { Ok(child_pid) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_spawn_check_exit_status")] pub fn spawn_check_exit_status(exit_status: i32) -> Result<(), crate::Error> { unsafe { let mut error = ptr::null_mut(); let _ = ffi::g_spawn_check_exit_status(exit_status, &mut error); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[cfg(any(unix, feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(unix)))] #[doc(alias = "g_spawn_command_line_async")] pub fn spawn_command_line_async>( command_line: P, ) -> Result<(), crate::Error> { unsafe { let mut error = ptr::null_mut(); let _ = ffi::g_spawn_command_line_async(command_line.as_ref().to_glib_none().0, &mut error); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } //#[doc(alias = "g_spawn_command_line_sync")] //pub fn spawn_command_line_sync>(command_line: P, standard_output: Vec, standard_error: Vec) -> Result { // unsafe { TODO: call ffi:g_spawn_command_line_sync() } //} //#[doc(alias = "g_spawn_sync")] //pub fn spawn_sync>(working_directory: P, argv: &[&std::path::Path], envp: &[&std::path::Path], flags: SpawnFlags, child_setup: Option>, standard_output: Vec, standard_error: Vec) -> Result { // unsafe { TODO: call ffi:g_spawn_sync() } //} //#[doc(alias = "g_sprintf")] //pub fn sprintf(string: &str, format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> i32 { // unsafe { TODO: call ffi:g_sprintf() } //} #[doc(alias = "g_stpcpy")] pub fn stpcpy(dest: &str, src: &str) -> crate::GString { unsafe { from_glib_full(ffi::g_stpcpy(dest.to_glib_none().0, src.to_glib_none().0)) } } //#[doc(alias = "g_try_malloc")] //pub fn try_malloc(n_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_try_malloc() } //} //#[doc(alias = "g_try_malloc0")] //pub fn try_malloc0(n_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_try_malloc0() } //} //#[doc(alias = "g_try_malloc0_n")] //pub fn try_malloc0_n(n_blocks: usize, n_block_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_try_malloc0_n() } //} //#[doc(alias = "g_try_malloc_n")] //pub fn try_malloc_n(n_blocks: usize, n_block_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_try_malloc_n() } //} //#[doc(alias = "g_try_realloc")] //pub fn try_realloc(mem: /*Unimplemented*/Option, n_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_try_realloc() } //} //#[doc(alias = "g_try_realloc_n")] //pub fn try_realloc_n(mem: /*Unimplemented*/Option, n_blocks: usize, n_block_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_try_realloc_n() } //} //#[doc(alias = "g_unicode_script_from_iso15924")] //pub fn unicode_script_from_iso15924(iso15924: u32) -> /*Ignored*/UnicodeScript { // unsafe { TODO: call ffi:g_unicode_script_from_iso15924() } //} //#[doc(alias = "g_unicode_script_to_iso15924")] //pub fn unicode_script_to_iso15924(script: /*Ignored*/UnicodeScript) -> u32 { // unsafe { TODO: call ffi:g_unicode_script_to_iso15924() } //} //#[cfg(any(unix, feature = "dox"))] //#[cfg_attr(feature = "dox", doc(cfg(unix)))] //#[cfg(any(feature = "v2_64", feature = "dox"))] //#[cfg_attr(feature = "dox", doc(cfg(feature = "v2_64")))] //#[doc(alias = "g_unix_get_passwd_entry")] //pub fn unix_get_passwd_entry(user_name: &str) -> Result, crate::Error> { // unsafe { TODO: call ffi:g_unix_get_passwd_entry() } //} #[doc(alias = "g_unlink")] pub fn unlink>(filename: P) -> i32 { unsafe { ffi::g_unlink(filename.as_ref().to_glib_none().0) } } #[doc(alias = "g_usleep")] pub fn usleep(microseconds: libc::c_ulong) { unsafe { ffi::g_usleep(microseconds); } } #[cfg(any(feature = "v2_52", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_52")))] #[doc(alias = "g_uuid_string_is_valid")] pub fn uuid_string_is_valid(str: &str) -> bool { unsafe { from_glib(ffi::g_uuid_string_is_valid(str.to_glib_none().0)) } } #[cfg(any(feature = "v2_52", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_52")))] #[doc(alias = "g_uuid_string_random")] pub fn uuid_string_random() -> crate::GString { unsafe { from_glib_full(ffi::g_uuid_string_random()) } } //#[doc(alias = "g_vasprintf")] //pub fn vasprintf(string: &str, format: &str, args: /*Unknown conversion*//*Unimplemented*/Unsupported) -> i32 { // unsafe { TODO: call ffi:g_vasprintf() } //} //#[doc(alias = "g_vfprintf")] //pub fn vfprintf(file: /*Unimplemented*/Fundamental: Pointer, format: &str, args: /*Unknown conversion*//*Unimplemented*/Unsupported) -> i32 { // unsafe { TODO: call ffi:g_vfprintf() } //} //#[doc(alias = "g_vprintf")] //pub fn vprintf(format: &str, args: /*Unknown conversion*//*Unimplemented*/Unsupported) -> i32 { // unsafe { TODO: call ffi:g_vprintf() } //} //#[doc(alias = "g_vsnprintf")] //pub fn vsnprintf(string: &str, n: libc::c_ulong, format: &str, args: /*Unknown conversion*//*Unimplemented*/Unsupported) -> i32 { // unsafe { TODO: call ffi:g_vsnprintf() } //} //#[doc(alias = "g_vsprintf")] //pub fn vsprintf(string: &str, format: &str, args: /*Unknown conversion*//*Unimplemented*/Unsupported) -> i32 { // unsafe { TODO: call ffi:g_vsprintf() } //} #[doc(alias = "g_warn_message")] pub fn warn_message( domain: Option<&str>, file: &str, line: i32, func: &str, warnexpr: Option<&str>, ) { unsafe { ffi::g_warn_message( domain.to_glib_none().0, file.to_glib_none().0, line, func.to_glib_none().0, warnexpr.to_glib_none().0, ); } } glib-0.14.8/src/auto/key_file.rs000064400000000000000000000377470072674642500146010ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::translate::*; #[cfg(any(feature = "v2_50", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_50")))] use crate::Bytes; use crate::Error; use crate::KeyFileFlags; use std::mem; use std::ptr; crate::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct KeyFile(Shared); match fn { ref => |ptr| ffi::g_key_file_ref(ptr), unref => |ptr| ffi::g_key_file_unref(ptr), type_ => || ffi::g_key_file_get_type(), } } impl KeyFile { #[doc(alias = "g_key_file_new")] pub fn new() -> KeyFile { unsafe { from_glib_full(ffi::g_key_file_new()) } } #[doc(alias = "g_key_file_get_comment")] #[doc(alias = "get_comment")] pub fn comment( &self, group_name: Option<&str>, key: Option<&str>, ) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_comment( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_double")] #[doc(alias = "get_double")] pub fn double(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_double( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(ret) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_double_list")] #[doc(alias = "get_double_list")] pub fn double_list(&self, group_name: &str, key: &str) -> Result, crate::Error> { unsafe { let mut length = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_double_list( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, length.as_mut_ptr(), &mut error, ); if error.is_null() { Ok(FromGlibContainer::from_glib_container_num( ret, length.assume_init() as usize, )) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_groups")] #[doc(alias = "get_groups")] pub fn groups(&self) -> (Vec, usize) { unsafe { let mut length = mem::MaybeUninit::uninit(); let ret = FromGlibPtrContainer::from_glib_full(ffi::g_key_file_get_groups( self.to_glib_none().0, length.as_mut_ptr(), )); let length = length.assume_init(); (ret, length) } } #[doc(alias = "g_key_file_get_int64")] #[doc(alias = "get_int64")] pub fn int64(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_int64( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(ret) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_integer")] #[doc(alias = "get_integer")] pub fn integer(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_integer( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(ret) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_integer_list")] #[doc(alias = "get_integer_list")] pub fn integer_list(&self, group_name: &str, key: &str) -> Result, crate::Error> { unsafe { let mut length = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_integer_list( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, length.as_mut_ptr(), &mut error, ); if error.is_null() { Ok(FromGlibContainer::from_glib_container_num( ret, length.assume_init() as usize, )) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_keys")] #[doc(alias = "get_keys")] pub fn keys(&self, group_name: &str) -> Result<(Vec, usize), crate::Error> { unsafe { let mut length = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_keys( self.to_glib_none().0, group_name.to_glib_none().0, length.as_mut_ptr(), &mut error, ); let length = length.assume_init(); if error.is_null() { Ok((FromGlibPtrContainer::from_glib_full(ret), length)) } else { Err(from_glib_full(error)) } } } #[cfg(any(feature = "v2_56", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_56")))] #[doc(alias = "g_key_file_get_locale_for_key")] #[doc(alias = "get_locale_for_key")] pub fn locale_for_key( &self, group_name: &str, key: &str, locale: Option<&str>, ) -> Option { unsafe { from_glib_full(ffi::g_key_file_get_locale_for_key( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, locale.to_glib_none().0, )) } } #[doc(alias = "g_key_file_get_start_group")] #[doc(alias = "get_start_group")] pub fn start_group(&self) -> Option { unsafe { from_glib_full(ffi::g_key_file_get_start_group(self.to_glib_none().0)) } } #[doc(alias = "g_key_file_get_uint64")] #[doc(alias = "get_uint64")] pub fn uint64(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_uint64( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(ret) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_value")] #[doc(alias = "get_value")] pub fn value(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_value( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_has_group")] pub fn has_group(&self, group_name: &str) -> bool { unsafe { from_glib(ffi::g_key_file_has_group( self.to_glib_none().0, group_name.to_glib_none().0, )) } } #[cfg(any(feature = "v2_50", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_50")))] #[doc(alias = "g_key_file_load_from_bytes")] pub fn load_from_bytes(&self, bytes: &Bytes, flags: KeyFileFlags) -> Result<(), crate::Error> { unsafe { let mut error = ptr::null_mut(); let _ = ffi::g_key_file_load_from_bytes( self.to_glib_none().0, bytes.to_glib_none().0, flags.into_glib(), &mut error, ); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_load_from_data")] pub fn load_from_data(&self, data: &str, flags: KeyFileFlags) -> Result<(), crate::Error> { let length = data.len() as usize; unsafe { let mut error = ptr::null_mut(); let _ = ffi::g_key_file_load_from_data( self.to_glib_none().0, data.to_glib_none().0, length, flags.into_glib(), &mut error, ); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_load_from_file")] pub fn load_from_file>( &self, file: P, flags: KeyFileFlags, ) -> Result<(), crate::Error> { unsafe { let mut error = ptr::null_mut(); let _ = ffi::g_key_file_load_from_file( self.to_glib_none().0, file.as_ref().to_glib_none().0, flags.into_glib(), &mut error, ); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_remove_comment")] pub fn remove_comment( &self, group_name: Option<&str>, key: Option<&str>, ) -> Result<(), crate::Error> { unsafe { let mut error = ptr::null_mut(); let _ = ffi::g_key_file_remove_comment( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_remove_group")] pub fn remove_group(&self, group_name: &str) -> Result<(), crate::Error> { unsafe { let mut error = ptr::null_mut(); let _ = ffi::g_key_file_remove_group( self.to_glib_none().0, group_name.to_glib_none().0, &mut error, ); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_remove_key")] pub fn remove_key(&self, group_name: &str, key: &str) -> Result<(), crate::Error> { unsafe { let mut error = ptr::null_mut(); let _ = ffi::g_key_file_remove_key( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_set_boolean")] pub fn set_boolean(&self, group_name: &str, key: &str, value: bool) { unsafe { ffi::g_key_file_set_boolean( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, value.into_glib(), ); } } //#[doc(alias = "g_key_file_set_boolean_list")] //pub fn set_boolean_list(&self, group_name: &str, key: &str, list: /*Unimplemented*/&CArray TypeId { ns_id: 0, id: 1 }) { // unsafe { TODO: call ffi:g_key_file_set_boolean_list() } //} #[doc(alias = "g_key_file_set_comment")] pub fn set_comment( &self, group_name: Option<&str>, key: Option<&str>, comment: &str, ) -> Result<(), crate::Error> { unsafe { let mut error = ptr::null_mut(); let _ = ffi::g_key_file_set_comment( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, comment.to_glib_none().0, &mut error, ); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_set_double")] pub fn set_double(&self, group_name: &str, key: &str, value: f64) { unsafe { ffi::g_key_file_set_double( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, value, ); } } #[doc(alias = "g_key_file_set_int64")] pub fn set_int64(&self, group_name: &str, key: &str, value: i64) { unsafe { ffi::g_key_file_set_int64( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, value, ); } } #[doc(alias = "g_key_file_set_integer")] pub fn set_integer(&self, group_name: &str, key: &str, value: i32) { unsafe { ffi::g_key_file_set_integer( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, value, ); } } #[doc(alias = "g_key_file_set_list_separator")] pub fn set_list_separator(&self, separator: crate::Char) { unsafe { ffi::g_key_file_set_list_separator(self.to_glib_none().0, separator.into_glib()); } } #[doc(alias = "g_key_file_set_locale_string")] pub fn set_locale_string(&self, group_name: &str, key: &str, locale: &str, string: &str) { unsafe { ffi::g_key_file_set_locale_string( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, locale.to_glib_none().0, string.to_glib_none().0, ); } } #[doc(alias = "g_key_file_set_string")] pub fn set_string(&self, group_name: &str, key: &str, string: &str) { unsafe { ffi::g_key_file_set_string( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, string.to_glib_none().0, ); } } #[doc(alias = "g_key_file_set_uint64")] pub fn set_uint64(&self, group_name: &str, key: &str, value: u64) { unsafe { ffi::g_key_file_set_uint64( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, value, ); } } #[doc(alias = "g_key_file_set_value")] pub fn set_value(&self, group_name: &str, key: &str, value: &str) { unsafe { ffi::g_key_file_set_value( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, value.to_glib_none().0, ); } } } impl Default for KeyFile { fn default() -> Self { Self::new() } } glib-0.14.8/src/auto/main_context.rs000064400000000000000000000114110072674642500154560ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::translate::*; crate::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MainContext(Shared); match fn { ref => |ptr| ffi::g_main_context_ref(ptr), unref => |ptr| ffi::g_main_context_unref(ptr), type_ => || ffi::g_main_context_get_type(), } } impl MainContext { #[doc(alias = "g_main_context_new")] pub fn new() -> MainContext { unsafe { from_glib_full(ffi::g_main_context_new()) } } //#[doc(alias = "g_main_context_add_poll")] //pub fn add_poll(&self, fd: /*Ignored*/&mut PollFD, priority: i32) { // unsafe { TODO: call ffi:g_main_context_add_poll() } //} //#[doc(alias = "g_main_context_check")] //pub fn check(&self, max_priority: i32, fds: /*Ignored*/&[&PollFD]) -> bool { // unsafe { TODO: call ffi:g_main_context_check() } //} #[doc(alias = "g_main_context_dispatch")] pub fn dispatch(&self) { unsafe { ffi::g_main_context_dispatch(self.to_glib_none().0); } } //#[doc(alias = "g_main_context_find_source_by_funcs_user_data")] //pub fn find_source_by_funcs_user_data(&self, funcs: /*Ignored*/&mut SourceFuncs, user_data: /*Unimplemented*/Option) -> Source { // unsafe { TODO: call ffi:g_main_context_find_source_by_funcs_user_data() } //} //#[doc(alias = "g_main_context_find_source_by_user_data")] //pub fn find_source_by_user_data(&self, user_data: /*Unimplemented*/Option) -> Source { // unsafe { TODO: call ffi:g_main_context_find_source_by_user_data() } //} //#[doc(alias = "g_main_context_get_poll_func")] //#[doc(alias = "get_poll_func")] //pub fn poll_func(&self) -> /*Unimplemented*/Fn(/*Ignored*/PollFD, u32, i32) -> i32 { // unsafe { TODO: call ffi:g_main_context_get_poll_func() } //} #[doc(alias = "g_main_context_is_owner")] pub fn is_owner(&self) -> bool { unsafe { from_glib(ffi::g_main_context_is_owner(self.to_glib_none().0)) } } #[doc(alias = "g_main_context_iteration")] pub fn iteration(&self, may_block: bool) -> bool { unsafe { from_glib(ffi::g_main_context_iteration( self.to_glib_none().0, may_block.into_glib(), )) } } #[doc(alias = "g_main_context_pending")] pub fn pending(&self) -> bool { unsafe { from_glib(ffi::g_main_context_pending(self.to_glib_none().0)) } } #[doc(alias = "g_main_context_pop_thread_default")] pub fn pop_thread_default(&self) { unsafe { ffi::g_main_context_pop_thread_default(self.to_glib_none().0); } } #[doc(alias = "g_main_context_push_thread_default")] pub fn push_thread_default(&self) { unsafe { ffi::g_main_context_push_thread_default(self.to_glib_none().0); } } //#[doc(alias = "g_main_context_query")] //pub fn query(&self, max_priority: i32, fds: /*Ignored*/Vec) -> (i32, i32) { // unsafe { TODO: call ffi:g_main_context_query() } //} //#[doc(alias = "g_main_context_remove_poll")] //pub fn remove_poll(&self, fd: /*Ignored*/&mut PollFD) { // unsafe { TODO: call ffi:g_main_context_remove_poll() } //} //#[doc(alias = "g_main_context_set_poll_func")] //pub fn set_poll_func(&self, func: /*Unimplemented*/Fn(/*Ignored*/PollFD, u32, i32) -> i32) { // unsafe { TODO: call ffi:g_main_context_set_poll_func() } //} //#[cfg_attr(feature = "v2_58", deprecated = "Since 2.58")] //#[doc(alias = "g_main_context_wait")] //pub fn wait(&self, cond: /*Ignored*/&mut Cond, mutex: /*Ignored*/&mut Mutex) -> bool { // unsafe { TODO: call ffi:g_main_context_wait() } //} #[doc(alias = "g_main_context_wakeup")] pub fn wakeup(&self) { unsafe { ffi::g_main_context_wakeup(self.to_glib_none().0); } } #[doc(alias = "g_main_context_default")] pub fn default() -> MainContext { unsafe { from_glib_none(ffi::g_main_context_default()) } } #[doc(alias = "g_main_context_get_thread_default")] #[doc(alias = "get_thread_default")] pub fn thread_default() -> Option { unsafe { from_glib_none(ffi::g_main_context_get_thread_default()) } } #[doc(alias = "g_main_context_ref_thread_default")] pub fn ref_thread_default() -> MainContext { unsafe { from_glib_full(ffi::g_main_context_ref_thread_default()) } } } impl Default for MainContext { fn default() -> Self { Self::new() } } unsafe impl Send for MainContext {} unsafe impl Sync for MainContext {} glib-0.14.8/src/auto/main_loop.rs000064400000000000000000000030360072674642500147470ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::translate::*; use crate::MainContext; crate::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MainLoop(Shared); match fn { ref => |ptr| ffi::g_main_loop_ref(ptr), unref => |ptr| ffi::g_main_loop_unref(ptr), type_ => || ffi::g_main_loop_get_type(), } } impl MainLoop { #[doc(alias = "g_main_loop_new")] pub fn new(context: Option<&MainContext>, is_running: bool) -> MainLoop { unsafe { from_glib_full(ffi::g_main_loop_new( context.to_glib_none().0, is_running.into_glib(), )) } } #[doc(alias = "g_main_loop_get_context")] #[doc(alias = "get_context")] pub fn context(&self) -> MainContext { unsafe { from_glib_none(ffi::g_main_loop_get_context(self.to_glib_none().0)) } } #[doc(alias = "g_main_loop_is_running")] pub fn is_running(&self) -> bool { unsafe { from_glib(ffi::g_main_loop_is_running(self.to_glib_none().0)) } } #[doc(alias = "g_main_loop_quit")] pub fn quit(&self) { unsafe { ffi::g_main_loop_quit(self.to_glib_none().0); } } #[doc(alias = "g_main_loop_run")] pub fn run(&self) { unsafe { ffi::g_main_loop_run(self.to_glib_none().0); } } } unsafe impl Send for MainLoop {} unsafe impl Sync for MainLoop {} glib-0.14.8/src/auto/mod.rs000064400000000000000000000076750072674642500135660ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT mod checksum; pub use self::checksum::Checksum; mod date_time; pub use self::date_time::DateTime; mod key_file; pub use self::key_file::KeyFile; mod main_context; pub use self::main_context::MainContext; mod main_loop; pub use self::main_loop::MainLoop; mod source; pub use self::source::Source; mod time_zone; pub use self::time_zone::TimeZone; #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] mod uri; #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] pub use self::uri::Uri; mod enums; pub use self::enums::ChecksumType; pub use self::enums::DateMonth; pub use self::enums::DateWeekday; pub use self::enums::KeyFileError; pub use self::enums::OptionArg; pub use self::enums::SeekType; pub use self::enums::TimeType; #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] pub use self::enums::UriError; mod flags; #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] pub use self::flags::FileSetContentsFlags; pub use self::flags::FileTest; pub use self::flags::FormatSizeFlags; pub use self::flags::IOCondition; pub use self::flags::KeyFileFlags; pub use self::flags::LogLevelFlags; pub use self::flags::OptionFlags; pub use self::flags::SpawnFlags; #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] pub use self::flags::UriFlags; #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] pub use self::flags::UriHideFlags; #[cfg(any(feature = "v2_66", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_66")))] pub use self::flags::UriParamsFlags; mod alias; pub use self::alias::DateDay; pub use self::alias::DateYear; pub use self::alias::Time; pub use self::alias::TimeSpan; pub mod functions; mod constants; pub use self::constants::CSET_a_2_z; pub use self::constants::CSET_A_2_Z; pub use self::constants::CSET_DIGITS; pub use self::constants::KEY_FILE_DESKTOP_GROUP; pub use self::constants::KEY_FILE_DESKTOP_KEY_ACTIONS; pub use self::constants::KEY_FILE_DESKTOP_KEY_CATEGORIES; pub use self::constants::KEY_FILE_DESKTOP_KEY_COMMENT; pub use self::constants::KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE; pub use self::constants::KEY_FILE_DESKTOP_KEY_EXEC; pub use self::constants::KEY_FILE_DESKTOP_KEY_GENERIC_NAME; pub use self::constants::KEY_FILE_DESKTOP_KEY_HIDDEN; pub use self::constants::KEY_FILE_DESKTOP_KEY_ICON; pub use self::constants::KEY_FILE_DESKTOP_KEY_MIME_TYPE; pub use self::constants::KEY_FILE_DESKTOP_KEY_NAME; pub use self::constants::KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN; pub use self::constants::KEY_FILE_DESKTOP_KEY_NO_DISPLAY; pub use self::constants::KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN; pub use self::constants::KEY_FILE_DESKTOP_KEY_PATH; pub use self::constants::KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY; pub use self::constants::KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS; pub use self::constants::KEY_FILE_DESKTOP_KEY_TERMINAL; pub use self::constants::KEY_FILE_DESKTOP_KEY_TRY_EXEC; pub use self::constants::KEY_FILE_DESKTOP_KEY_TYPE; pub use self::constants::KEY_FILE_DESKTOP_KEY_URL; pub use self::constants::KEY_FILE_DESKTOP_KEY_VERSION; pub use self::constants::KEY_FILE_DESKTOP_TYPE_APPLICATION; pub use self::constants::KEY_FILE_DESKTOP_TYPE_DIRECTORY; pub use self::constants::KEY_FILE_DESKTOP_TYPE_LINK; pub use self::constants::OPTION_REMAINING; pub use self::constants::STR_DELIMITERS; #[cfg(any(feature = "v2_60", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_60")))] pub use self::constants::TEST_OPTION_ISOLATE_DIRS; pub use self::constants::URI_RESERVED_CHARS_GENERIC_DELIMITERS; pub use self::constants::URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS; #[doc(hidden)] pub mod traits {} glib-0.14.8/src/auto/source.rs000064400000000000000000000105770072674642500143020ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::translate::*; use crate::MainContext; crate::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Source(Shared); match fn { ref => |ptr| ffi::g_source_ref(ptr), unref => |ptr| ffi::g_source_unref(ptr), type_ => || ffi::g_source_get_type(), } } impl Source { //#[doc(alias = "g_source_new")] //pub fn new(source_funcs: /*Ignored*/&mut SourceFuncs, struct_size: u32) -> Source { // unsafe { TODO: call ffi:g_source_new() } //} #[doc(alias = "g_source_add_child_source")] pub fn add_child_source(&self, child_source: &Source) { unsafe { ffi::g_source_add_child_source(self.to_glib_none().0, child_source.to_glib_none().0); } } //#[doc(alias = "g_source_add_poll")] //pub fn add_poll(&self, fd: /*Ignored*/&mut PollFD) { // unsafe { TODO: call ffi:g_source_add_poll() } //} //#[doc(alias = "g_source_add_unix_fd")] //pub fn add_unix_fd(&self, fd: i32, events: IOCondition) -> /*Unimplemented*/Fundamental: Pointer { // unsafe { TODO: call ffi:g_source_add_unix_fd() } //} #[doc(alias = "g_source_destroy")] pub fn destroy(&self) { unsafe { ffi::g_source_destroy(self.to_glib_none().0); } } #[doc(alias = "g_source_get_can_recurse")] #[doc(alias = "get_can_recurse")] pub fn can_recurse(&self) -> bool { unsafe { from_glib(ffi::g_source_get_can_recurse(self.to_glib_none().0)) } } #[doc(alias = "g_source_get_context")] #[doc(alias = "get_context")] pub fn context(&self) -> Option { unsafe { from_glib_none(ffi::g_source_get_context(self.to_glib_none().0)) } } #[doc(alias = "g_source_get_name")] #[doc(alias = "get_name")] pub fn name(&self) -> Option { unsafe { from_glib_none(ffi::g_source_get_name(self.to_glib_none().0)) } } #[doc(alias = "g_source_get_priority")] #[doc(alias = "get_priority")] pub fn priority(&self) -> i32 { unsafe { ffi::g_source_get_priority(self.to_glib_none().0) } } #[doc(alias = "g_source_get_ready_time")] #[doc(alias = "get_ready_time")] pub fn ready_time(&self) -> i64 { unsafe { ffi::g_source_get_ready_time(self.to_glib_none().0) } } #[doc(alias = "g_source_get_time")] #[doc(alias = "get_time")] pub fn time(&self) -> i64 { unsafe { ffi::g_source_get_time(self.to_glib_none().0) } } #[doc(alias = "g_source_is_destroyed")] pub fn is_destroyed(&self) -> bool { unsafe { from_glib(ffi::g_source_is_destroyed(self.to_glib_none().0)) } } //#[doc(alias = "g_source_modify_unix_fd")] //pub fn modify_unix_fd(&self, tag: /*Unimplemented*/Fundamental: Pointer, new_events: IOCondition) { // unsafe { TODO: call ffi:g_source_modify_unix_fd() } //} //#[doc(alias = "g_source_query_unix_fd")] //pub fn query_unix_fd(&self, tag: /*Unimplemented*/Fundamental: Pointer) -> IOCondition { // unsafe { TODO: call ffi:g_source_query_unix_fd() } //} #[doc(alias = "g_source_remove_child_source")] pub fn remove_child_source(&self, child_source: &Source) { unsafe { ffi::g_source_remove_child_source(self.to_glib_none().0, child_source.to_glib_none().0); } } //#[doc(alias = "g_source_remove_poll")] //pub fn remove_poll(&self, fd: /*Ignored*/&mut PollFD) { // unsafe { TODO: call ffi:g_source_remove_poll() } //} //#[doc(alias = "g_source_remove_unix_fd")] //pub fn remove_unix_fd(&self, tag: /*Unimplemented*/Fundamental: Pointer) { // unsafe { TODO: call ffi:g_source_remove_unix_fd() } //} //#[doc(alias = "g_source_remove_by_funcs_user_data")] //pub fn remove_by_funcs_user_data(funcs: /*Ignored*/&mut SourceFuncs, user_data: /*Unimplemented*/Option) -> bool { // unsafe { TODO: call ffi:g_source_remove_by_funcs_user_data() } //} //#[doc(alias = "g_source_remove_by_user_data")] //pub fn remove_by_user_data(user_data: /*Unimplemented*/Option) -> bool { // unsafe { TODO: call ffi:g_source_remove_by_user_data() } //} } unsafe impl Send for Source {} unsafe impl Sync for Source {} glib-0.14.8/src/auto/time_zone.rs000064400000000000000000000052170072674642500147660ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::translate::*; use crate::TimeType; crate::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct TimeZone(Shared); match fn { ref => |ptr| ffi::g_time_zone_ref(ptr), unref => |ptr| ffi::g_time_zone_unref(ptr), type_ => || ffi::g_time_zone_get_type(), } } impl TimeZone { #[cfg_attr(feature = "v2_68", deprecated = "Since 2.68")] #[doc(alias = "g_time_zone_new")] pub fn new(identifier: Option<&str>) -> TimeZone { unsafe { from_glib_full(ffi::g_time_zone_new(identifier.to_glib_none().0)) } } #[doc(alias = "g_time_zone_new_local")] pub fn new_local() -> TimeZone { unsafe { from_glib_full(ffi::g_time_zone_new_local()) } } #[cfg(any(feature = "v2_58", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_58")))] #[doc(alias = "g_time_zone_new_offset")] pub fn new_offset(seconds: i32) -> TimeZone { unsafe { from_glib_full(ffi::g_time_zone_new_offset(seconds)) } } #[doc(alias = "g_time_zone_new_utc")] pub fn new_utc() -> TimeZone { unsafe { from_glib_full(ffi::g_time_zone_new_utc()) } } #[doc(alias = "g_time_zone_find_interval")] pub fn find_interval(&self, type_: TimeType, time_: i64) -> i32 { unsafe { ffi::g_time_zone_find_interval(self.to_glib_none().0, type_.into_glib(), time_) } } #[doc(alias = "g_time_zone_get_abbreviation")] #[doc(alias = "get_abbreviation")] pub fn abbreviation(&self, interval: i32) -> crate::GString { unsafe { from_glib_none(ffi::g_time_zone_get_abbreviation( self.to_glib_none().0, interval, )) } } #[cfg(any(feature = "v2_58", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_58")))] #[doc(alias = "g_time_zone_get_identifier")] #[doc(alias = "get_identifier")] pub fn identifier(&self) -> crate::GString { unsafe { from_glib_none(ffi::g_time_zone_get_identifier(self.to_glib_none().0)) } } #[doc(alias = "g_time_zone_get_offset")] #[doc(alias = "get_offset")] pub fn offset(&self, interval: i32) -> i32 { unsafe { ffi::g_time_zone_get_offset(self.to_glib_none().0, interval) } } #[doc(alias = "g_time_zone_is_dst")] pub fn is_dst(&self, interval: i32) -> bool { unsafe { from_glib(ffi::g_time_zone_is_dst(self.to_glib_none().0, interval)) } } } unsafe impl Send for TimeZone {} unsafe impl Sync for TimeZone {} glib-0.14.8/src/auto/uri.rs000064400000000000000000000404660072674642500136010ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::translate::*; use crate::Bytes; use crate::Error; use crate::UriFlags; use crate::UriHideFlags; use std::fmt; use std::mem; use std::ptr; crate::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Uri(Shared); match fn { ref => |ptr| ffi::g_uri_ref(ptr), unref => |ptr| ffi::g_uri_unref(ptr), type_ => || ffi::g_uri_get_type(), } } impl Uri { #[doc(alias = "g_uri_get_auth_params")] #[doc(alias = "get_auth_params")] pub fn auth_params(&self) -> Option { unsafe { from_glib_none(ffi::g_uri_get_auth_params(self.to_glib_none().0)) } } #[doc(alias = "g_uri_get_flags")] #[doc(alias = "get_flags")] pub fn flags(&self) -> UriFlags { unsafe { from_glib(ffi::g_uri_get_flags(self.to_glib_none().0)) } } #[doc(alias = "g_uri_get_fragment")] #[doc(alias = "get_fragment")] pub fn fragment(&self) -> Option { unsafe { from_glib_none(ffi::g_uri_get_fragment(self.to_glib_none().0)) } } #[doc(alias = "g_uri_get_host")] #[doc(alias = "get_host")] pub fn host(&self) -> Option { unsafe { from_glib_none(ffi::g_uri_get_host(self.to_glib_none().0)) } } #[doc(alias = "g_uri_get_password")] #[doc(alias = "get_password")] pub fn password(&self) -> Option { unsafe { from_glib_none(ffi::g_uri_get_password(self.to_glib_none().0)) } } #[doc(alias = "g_uri_get_path")] #[doc(alias = "get_path")] pub fn path(&self) -> crate::GString { unsafe { from_glib_none(ffi::g_uri_get_path(self.to_glib_none().0)) } } #[doc(alias = "g_uri_get_port")] #[doc(alias = "get_port")] pub fn port(&self) -> i32 { unsafe { ffi::g_uri_get_port(self.to_glib_none().0) } } #[doc(alias = "g_uri_get_query")] #[doc(alias = "get_query")] pub fn query(&self) -> Option { unsafe { from_glib_none(ffi::g_uri_get_query(self.to_glib_none().0)) } } #[doc(alias = "g_uri_get_scheme")] #[doc(alias = "get_scheme")] pub fn scheme(&self) -> crate::GString { unsafe { from_glib_none(ffi::g_uri_get_scheme(self.to_glib_none().0)) } } #[doc(alias = "g_uri_get_user")] #[doc(alias = "get_user")] pub fn user(&self) -> Option { unsafe { from_glib_none(ffi::g_uri_get_user(self.to_glib_none().0)) } } #[doc(alias = "g_uri_get_userinfo")] #[doc(alias = "get_userinfo")] pub fn userinfo(&self) -> Option { unsafe { from_glib_none(ffi::g_uri_get_userinfo(self.to_glib_none().0)) } } #[doc(alias = "g_uri_parse_relative")] pub fn parse_relative(&self, uri_ref: &str, flags: UriFlags) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_uri_parse_relative( self.to_glib_none().0, uri_ref.to_glib_none().0, flags.into_glib(), &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_uri_to_string")] #[doc(alias = "to_string")] pub fn to_str(&self) -> crate::GString { unsafe { from_glib_full(ffi::g_uri_to_string(self.to_glib_none().0)) } } #[doc(alias = "g_uri_to_string_partial")] pub fn to_string_partial(&self, flags: UriHideFlags) -> crate::GString { unsafe { from_glib_full(ffi::g_uri_to_string_partial( self.to_glib_none().0, flags.into_glib(), )) } } #[doc(alias = "g_uri_build")] pub fn build( flags: UriFlags, scheme: &str, userinfo: Option<&str>, host: Option<&str>, port: i32, path: &str, query: Option<&str>, fragment: Option<&str>, ) -> Uri { unsafe { from_glib_full(ffi::g_uri_build( flags.into_glib(), scheme.to_glib_none().0, userinfo.to_glib_none().0, host.to_glib_none().0, port, path.to_glib_none().0, query.to_glib_none().0, fragment.to_glib_none().0, )) } } #[doc(alias = "g_uri_build_with_user")] pub fn build_with_user( flags: UriFlags, scheme: &str, user: Option<&str>, password: Option<&str>, auth_params: Option<&str>, host: Option<&str>, port: i32, path: &str, query: Option<&str>, fragment: Option<&str>, ) -> Uri { unsafe { from_glib_full(ffi::g_uri_build_with_user( flags.into_glib(), scheme.to_glib_none().0, user.to_glib_none().0, password.to_glib_none().0, auth_params.to_glib_none().0, host.to_glib_none().0, port, path.to_glib_none().0, query.to_glib_none().0, fragment.to_glib_none().0, )) } } #[doc(alias = "g_uri_escape_bytes")] pub fn escape_bytes(unescaped: &[u8], reserved_chars_allowed: Option<&str>) -> crate::GString { let length = unescaped.len() as usize; unsafe { from_glib_full(ffi::g_uri_escape_bytes( unescaped.to_glib_none().0, length, reserved_chars_allowed.to_glib_none().0, )) } } #[doc(alias = "g_uri_escape_string")] pub fn escape_string( unescaped: &str, reserved_chars_allowed: Option<&str>, allow_utf8: bool, ) -> crate::GString { unsafe { from_glib_full(ffi::g_uri_escape_string( unescaped.to_glib_none().0, reserved_chars_allowed.to_glib_none().0, allow_utf8.into_glib(), )) } } #[doc(alias = "g_uri_is_valid")] pub fn is_valid(uri_string: &str, flags: UriFlags) -> Result<(), crate::Error> { unsafe { let mut error = ptr::null_mut(); let _ = ffi::g_uri_is_valid(uri_string.to_glib_none().0, flags.into_glib(), &mut error); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_uri_join")] pub fn join( flags: UriFlags, scheme: Option<&str>, userinfo: Option<&str>, host: Option<&str>, port: i32, path: &str, query: Option<&str>, fragment: Option<&str>, ) -> crate::GString { unsafe { from_glib_full(ffi::g_uri_join( flags.into_glib(), scheme.to_glib_none().0, userinfo.to_glib_none().0, host.to_glib_none().0, port, path.to_glib_none().0, query.to_glib_none().0, fragment.to_glib_none().0, )) } } #[doc(alias = "g_uri_join_with_user")] pub fn join_with_user( flags: UriFlags, scheme: Option<&str>, user: Option<&str>, password: Option<&str>, auth_params: Option<&str>, host: Option<&str>, port: i32, path: &str, query: Option<&str>, fragment: Option<&str>, ) -> crate::GString { unsafe { from_glib_full(ffi::g_uri_join_with_user( flags.into_glib(), scheme.to_glib_none().0, user.to_glib_none().0, password.to_glib_none().0, auth_params.to_glib_none().0, host.to_glib_none().0, port, path.to_glib_none().0, query.to_glib_none().0, fragment.to_glib_none().0, )) } } #[doc(alias = "g_uri_list_extract_uris")] pub fn list_extract_uris(uri_list: &str) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::g_uri_list_extract_uris( uri_list.to_glib_none().0, )) } } #[doc(alias = "g_uri_parse")] pub fn parse(uri_string: &str, flags: UriFlags) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_uri_parse(uri_string.to_glib_none().0, flags.into_glib(), &mut error); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } //#[doc(alias = "g_uri_parse_params")] //pub fn parse_params(params: &str, separators: &str, flags: UriParamsFlags) -> Result { // unsafe { TODO: call ffi:g_uri_parse_params() } //} #[doc(alias = "g_uri_parse_scheme")] pub fn parse_scheme(uri: &str) -> Option { unsafe { from_glib_full(ffi::g_uri_parse_scheme(uri.to_glib_none().0)) } } #[doc(alias = "g_uri_peek_scheme")] pub fn peek_scheme(uri: &str) -> Option { unsafe { from_glib_none(ffi::g_uri_peek_scheme(uri.to_glib_none().0)) } } #[doc(alias = "g_uri_resolve_relative")] pub fn resolve_relative( base_uri_string: Option<&str>, uri_ref: &str, flags: UriFlags, ) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_uri_resolve_relative( base_uri_string.to_glib_none().0, uri_ref.to_glib_none().0, flags.into_glib(), &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_uri_split")] pub fn split( uri_ref: &str, flags: UriFlags, ) -> Result< ( Option, Option, Option, i32, crate::GString, Option, Option, ), crate::Error, > { unsafe { let mut scheme = ptr::null_mut(); let mut userinfo = ptr::null_mut(); let mut host = ptr::null_mut(); let mut port = mem::MaybeUninit::uninit(); let mut path = ptr::null_mut(); let mut query = ptr::null_mut(); let mut fragment = ptr::null_mut(); let mut error = ptr::null_mut(); let _ = ffi::g_uri_split( uri_ref.to_glib_none().0, flags.into_glib(), &mut scheme, &mut userinfo, &mut host, port.as_mut_ptr(), &mut path, &mut query, &mut fragment, &mut error, ); let port = port.assume_init(); if error.is_null() { Ok(( from_glib_full(scheme), from_glib_full(userinfo), from_glib_full(host), port, from_glib_full(path), from_glib_full(query), from_glib_full(fragment), )) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_uri_split_network")] pub fn split_network( uri_string: &str, flags: UriFlags, ) -> Result<(Option, Option, i32), crate::Error> { unsafe { let mut scheme = ptr::null_mut(); let mut host = ptr::null_mut(); let mut port = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let _ = ffi::g_uri_split_network( uri_string.to_glib_none().0, flags.into_glib(), &mut scheme, &mut host, port.as_mut_ptr(), &mut error, ); let port = port.assume_init(); if error.is_null() { Ok((from_glib_full(scheme), from_glib_full(host), port)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_uri_split_with_user")] pub fn split_with_user( uri_ref: &str, flags: UriFlags, ) -> Result< ( Option, Option, Option, Option, Option, i32, crate::GString, Option, Option, ), crate::Error, > { unsafe { let mut scheme = ptr::null_mut(); let mut user = ptr::null_mut(); let mut password = ptr::null_mut(); let mut auth_params = ptr::null_mut(); let mut host = ptr::null_mut(); let mut port = mem::MaybeUninit::uninit(); let mut path = ptr::null_mut(); let mut query = ptr::null_mut(); let mut fragment = ptr::null_mut(); let mut error = ptr::null_mut(); let _ = ffi::g_uri_split_with_user( uri_ref.to_glib_none().0, flags.into_glib(), &mut scheme, &mut user, &mut password, &mut auth_params, &mut host, port.as_mut_ptr(), &mut path, &mut query, &mut fragment, &mut error, ); let port = port.assume_init(); if error.is_null() { Ok(( from_glib_full(scheme), from_glib_full(user), from_glib_full(password), from_glib_full(auth_params), from_glib_full(host), port, from_glib_full(path), from_glib_full(query), from_glib_full(fragment), )) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_uri_unescape_bytes")] pub fn unescape_bytes( escaped_string: &str, illegal_characters: Option<&str>, ) -> Result { let length = escaped_string.len() as isize; unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_uri_unescape_bytes( escaped_string.to_glib_none().0, length, illegal_characters.to_glib_none().0, &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_uri_unescape_segment")] pub fn unescape_segment( escaped_string: Option<&str>, escaped_string_end: Option<&str>, illegal_characters: Option<&str>, ) -> Option { unsafe { from_glib_full(ffi::g_uri_unescape_segment( escaped_string.to_glib_none().0, escaped_string_end.to_glib_none().0, illegal_characters.to_glib_none().0, )) } } #[doc(alias = "g_uri_unescape_string")] pub fn unescape_string( escaped_string: &str, illegal_characters: Option<&str>, ) -> Option { unsafe { from_glib_full(ffi::g_uri_unescape_string( escaped_string.to_glib_none().0, illegal_characters.to_glib_none().0, )) } } } impl fmt::Display for Uri { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(&self.to_str()) } } unsafe impl Send for Uri {} unsafe impl Sync for Uri {} glib-0.14.8/src/auto/versions.txt000064400000000000000000000002040072674642500150270ustar 00000000000000Generated by gir (https://github.com/gtk-rs/gir @ 8891a2f2c34b) from gir-files (https://github.com/gtk-rs/gir-files @ 7d95377690e9) glib-0.14.8/src/boxed.rs000064400000000000000000000514140072674642500131260ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! `IMPL` Boxed wrapper implementation. use crate::translate::*; use std::cmp; use std::fmt; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut}; use std::ptr; /// Wrapper implementations for Boxed types. See `wrapper!`. #[macro_export] macro_rules! glib_boxed_wrapper { ([$($attr:meta)*] $name:ident, $ffi_name:ty, @copy $copy_arg:ident $copy_expr:expr, @free $free_arg:ident $free_expr:expr, @init $init_arg:ident $init_expr:expr, @clear $clear_arg:ident $clear_expr:expr, @type_ $get_type_expr:expr) => { $crate::glib_boxed_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name); $crate::glib_boxed_wrapper!(@memory_manager_impl $name, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr, @init $init_arg $init_expr, @clear $clear_arg $clear_expr); $crate::glib_boxed_wrapper!(@value_impl $name, $ffi_name, @type_ $get_type_expr); }; ([$($attr:meta)*] $name:ident, $ffi_name:ty, @copy $copy_arg:ident $copy_expr:expr, @free $free_arg:ident $free_expr:expr, @init $init_arg:ident $init_expr:expr, @clear $clear_arg:ident $clear_expr:expr) => { $crate::glib_boxed_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name); $crate::glib_boxed_wrapper!(@memory_manager_impl $name, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr, @init $init_arg $init_expr, @clear $clear_arg $clear_expr); }; ([$($attr:meta)*] $name:ident, $ffi_name:ty, @copy $copy_arg:ident $copy_expr:expr, @free $free_arg:ident $free_expr:expr) => { $crate::glib_boxed_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name); $crate::glib_boxed_wrapper!(@memory_manager_impl $name, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr); }; ([$($attr:meta)*] $name:ident, $ffi_name:ty, @copy $copy_arg:ident $copy_expr:expr, @free $free_arg:ident $free_expr:expr, @type_ $get_type_expr:expr) => { $crate::glib_boxed_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name); $crate::glib_boxed_wrapper!(@memory_manager_impl $name, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr); $crate::glib_boxed_wrapper!(@value_impl $name, $ffi_name, @type_ $get_type_expr); }; (@generic_impl [$($attr:meta)*] $name:ident, $ffi_name:ty) => { $(#[$attr])* #[derive(Clone)] pub struct $name($crate::boxed::Boxed<$ffi_name, $name>); #[doc(hidden)] impl $crate::translate::GlibPtrDefault for $name { type GlibType = *mut $ffi_name; } #[doc(hidden)] impl<'a> $crate::translate::ToGlibPtr<'a, *const $ffi_name> for $name { type Storage = &'a $crate::boxed::Boxed<$ffi_name, $name>; #[inline] fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *const $ffi_name, Self> { let stash = $crate::translate::ToGlibPtr::to_glib_none(&self.0); $crate::translate::Stash(stash.0, stash.1) } #[inline] fn to_glib_full(&self) -> *const $ffi_name { $crate::translate::ToGlibPtr::to_glib_full(&self.0) } } #[doc(hidden)] impl<'a> $crate::translate::ToGlibPtrMut<'a, *mut $ffi_name> for $name { type Storage = &'a mut $crate::boxed::Boxed<$ffi_name, $name>; #[inline] fn to_glib_none_mut(&'a mut self) -> $crate::translate::StashMut<'a, *mut $ffi_name, Self> { let stash = $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut self.0); $crate::translate::StashMut(stash.0, stash.1) } } #[doc(hidden)] impl<'a> $crate::translate::ToGlibContainerFromSlice<'a, *mut *const $ffi_name> for $name { type Storage = (Vec<$crate::translate::Stash<'a, *const $ffi_name, $name>>, Option>); fn to_glib_none_from_slice(t: &'a [$name]) -> (*mut *const $ffi_name, Self::Storage) { let v: Vec<_> = t.iter().map(|s| $crate::translate::ToGlibPtr::to_glib_none(s)).collect(); let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect(); v_ptr.push(std::ptr::null_mut() as *const $ffi_name); (v_ptr.as_ptr() as *mut *const $ffi_name, (v, Some(v_ptr))) } fn to_glib_container_from_slice(t: &'a [$name]) -> (*mut *const $ffi_name, Self::Storage) { let v: Vec<_> = t.iter().map(|s| $crate::translate::ToGlibPtr::to_glib_none(s)).collect(); let v_ptr = unsafe { let v_ptr = $crate::ffi::g_malloc0(std::mem::size_of::<*const $ffi_name>() * (t.len() + 1)) as *mut *const $ffi_name; for (i, s) in v.iter().enumerate() { std::ptr::write(v_ptr.add(i), s.0); } v_ptr }; (v_ptr, (v, None)) } fn to_glib_full_from_slice(t: &[$name]) -> *mut *const $ffi_name { unsafe { let v_ptr = $crate::ffi::g_malloc0(std::mem::size_of::<*const $ffi_name>() * (t.len() + 1)) as *mut *const $ffi_name; for (i, s) in t.iter().enumerate() { std::ptr::write(v_ptr.add(i), $crate::translate::ToGlibPtr::to_glib_full(s)); } v_ptr } } } #[doc(hidden)] impl<'a> $crate::translate::ToGlibContainerFromSlice<'a, *const *const $ffi_name> for $name { type Storage = (Vec<$crate::translate::Stash<'a, *const $ffi_name, $name>>, Option>); fn to_glib_none_from_slice(t: &'a [$name]) -> (*const *const $ffi_name, Self::Storage) { let (ptr, stash) = $crate::translate::ToGlibContainerFromSlice::<'a, *mut *const $ffi_name>::to_glib_none_from_slice(t); (ptr as *const *const $ffi_name, stash) } fn to_glib_container_from_slice(_: &'a [$name]) -> (*const *const $ffi_name, Self::Storage) { // Can't have consumer free a *const pointer unimplemented!() } fn to_glib_full_from_slice(_: &[$name]) -> *const *const $ffi_name { // Can't have consumer free a *const pointer unimplemented!() } } #[doc(hidden)] impl $crate::translate::FromGlibPtrNone<*mut $ffi_name> for $name { #[inline] unsafe fn from_glib_none(ptr: *mut $ffi_name) -> Self { $name($crate::translate::from_glib_none(ptr)) } } #[doc(hidden)] impl $crate::translate::FromGlibPtrNone<*const $ffi_name> for $name { #[inline] unsafe fn from_glib_none(ptr: *const $ffi_name) -> Self { $name($crate::translate::from_glib_none(ptr)) } } #[doc(hidden)] impl $crate::translate::FromGlibPtrFull<*mut $ffi_name> for $name { #[inline] unsafe fn from_glib_full(ptr: *mut $ffi_name) -> Self { $name($crate::translate::from_glib_full(ptr)) } } #[doc(hidden)] impl $crate::translate::FromGlibPtrFull<*const $ffi_name> for $name { #[inline] unsafe fn from_glib_full(ptr: *const $ffi_name) -> Self { $name($crate::translate::from_glib_full(ptr)) } } #[doc(hidden)] impl $crate::translate::FromGlibPtrBorrow<*mut $ffi_name> for $name { #[inline] unsafe fn from_glib_borrow(ptr: *mut $ffi_name) -> $crate::translate::Borrowed { $crate::translate::Borrowed::new( $name( $crate::translate::from_glib_borrow::<_, $crate::boxed::Boxed<_, _>>(ptr).into_inner() ) ) } } #[doc(hidden)] impl $crate::translate::FromGlibPtrBorrow<*const $ffi_name> for $name { #[inline] unsafe fn from_glib_borrow(ptr: *const $ffi_name) -> $crate::translate::Borrowed { $crate::translate::from_glib_borrow::<_, $name>(ptr as *mut $ffi_name) } } #[doc(hidden)] impl $crate::translate::FromGlibContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name { unsafe fn from_glib_none_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for i in 0..num { res.push($crate::translate::from_glib_none(std::ptr::read(ptr.add(i)))); } res } unsafe fn from_glib_container_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { let res = $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); $crate::ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for i in 0..num { res.push($crate::translate::from_glib_full(std::ptr::read(ptr.add(i)))); } $crate::ffi::g_free(ptr as *mut _); res } } #[doc(hidden)] impl $crate::translate::FromGlibPtrArrayContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name { unsafe fn from_glib_none_as_vec(ptr: *mut *mut $ffi_name) -> Vec { $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr)) } unsafe fn from_glib_container_as_vec(ptr: *mut *mut $ffi_name) -> Vec { $crate::translate::FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr)) } unsafe fn from_glib_full_as_vec(ptr: *mut *mut $ffi_name) -> Vec { $crate::translate::FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr)) } } }; (@value_impl $name:ident, $ffi_name:ty, @type_ $get_type_expr:expr) => { impl $crate::types::StaticType for $name { fn static_type() -> $crate::types::Type { #[allow(unused_unsafe)] unsafe { $crate::translate::from_glib($get_type_expr) } } } #[doc(hidden)] impl $crate::value::ValueType for $name { type Type = $name; } #[doc(hidden)] unsafe impl<'a> $crate::value::FromValue<'a> for $name { type Checker = $crate::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a $crate::Value) -> Self { let ptr = $crate::gobject_ffi::g_value_dup_boxed($crate::translate::ToGlibPtr::to_glib_none(value).0); assert!(!ptr.is_null()); <$name as $crate::translate::FromGlibPtrFull<*mut $ffi_name>>::from_glib_full(ptr as *mut $ffi_name) } } #[doc(hidden)] impl $crate::value::ToValue for $name { fn to_value(&self) -> $crate::Value { unsafe { let mut value = $crate::Value::from_type(<$name as $crate::StaticType>::static_type()); $crate::gobject_ffi::g_value_take_boxed( $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_full(self) as *mut _, ); value } } fn value_type(&self) -> $crate::Type { <$name as $crate::StaticType>::static_type() } } #[doc(hidden)] impl $crate::value::ToValueOptional for $name { fn to_value_optional(s: Option<&Self>) -> $crate::Value { let mut value = $crate::Value::for_value_type::(); unsafe { $crate::gobject_ffi::g_value_take_boxed( $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_full(&s) as *mut _, ); } value } } }; (@memory_manager_impl $name:ident, $ffi_name:ty, @copy $copy_arg:ident $copy_expr:expr, @free $free_arg:ident $free_expr:expr) => { #[doc(hidden)] impl $crate::boxed::BoxedMemoryManager<$ffi_name> for $name { #[inline] unsafe fn copy($copy_arg: *const $ffi_name) -> *mut $ffi_name { $copy_expr } #[inline] #[allow(clippy::no_effect)] unsafe fn free($free_arg: *mut $ffi_name) { $free_expr; } #[inline] unsafe fn init(_: *mut $ffi_name) { unimplemented!() } #[inline] unsafe fn clear(_: *mut $ffi_name) { unimplemented!() } } }; (@memory_manager_impl $name:ident, $ffi_name:ty, @copy $copy_arg:ident $copy_expr:expr, @free $free_arg:ident $free_expr:expr, @init $init_arg:ident $init_expr:expr, @clear $clear_arg:ident $clear_expr:expr) => { #[doc(hidden)] impl $crate::boxed::BoxedMemoryManager<$ffi_name> for $name { #[inline] unsafe fn copy($copy_arg: *const $ffi_name) -> *mut $ffi_name { $copy_expr } #[inline] #[allow(clippy::no_effect)] unsafe fn free($free_arg: *mut $ffi_name) { $free_expr; } #[inline] #[allow(clippy::no_effect)] unsafe fn init($init_arg: *mut $ffi_name) { $init_expr; } #[inline] #[allow(clippy::no_effect)] unsafe fn clear($clear_arg: *mut $ffi_name) { $clear_expr; } } #[doc(hidden)] impl $crate::translate::Uninitialized for $name { #[inline] unsafe fn uninitialized() -> Self { $name($crate::boxed::Boxed::uninitialized()) } } }; } enum AnyBox { Native(Box), Foreign(ptr::NonNull), } impl fmt::Debug for AnyBox { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::AnyBox::*; match *self { Native(ref b) => f.debug_tuple("Native").field(&(&**b as *const T)).finish(), Foreign(ptr) => f.debug_tuple("Foreign").field(&ptr).finish(), } } } // The safety docs really belong in the wrapper!() macro for Boxed /// Memory management functions for a boxed type. pub trait BoxedMemoryManager: 'static { /// Makes a copy. unsafe fn copy(ptr: *const T) -> *mut T; /// Frees the object. unsafe fn free(ptr: *mut T); /// Initializes an already allocated object. unsafe fn init(ptr: *mut T); /// Clears and frees all memory of the object, but not the object itself. unsafe fn clear(ptr: *mut T); } /// Encapsulates memory management logic for boxed types. pub struct Boxed> { inner: AnyBox, _dummy: PhantomData<*mut MM>, } impl> Uninitialized for Boxed { #[inline] unsafe fn uninitialized() -> Self { Self { inner: { let mut inner = mem::MaybeUninit::zeroed(); MM::init(inner.as_mut_ptr()); AnyBox::Native(Box::new(inner.assume_init())) }, _dummy: PhantomData, } } } impl<'a, T: 'static, MM: BoxedMemoryManager> ToGlibPtr<'a, *const T> for Boxed { type Storage = &'a Self; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const T, Self> { use self::AnyBox::*; let ptr = match self.inner { Native(ref b) => &**b as *const T, Foreign(p) => p.as_ptr(), }; Stash(ptr, self) } #[inline] fn to_glib_full(&self) -> *const T { use self::AnyBox::*; let ptr = match self.inner { Native(ref b) => &**b as *const T, Foreign(p) => p.as_ptr(), }; unsafe { MM::copy(ptr) } } } impl<'a, T: 'static, MM: BoxedMemoryManager> ToGlibPtrMut<'a, *mut T> for Boxed { type Storage = &'a mut Self; #[inline] fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut T, Self> { use self::AnyBox::*; let ptr = match self.inner { Native(ref mut b) => &mut **b as *mut T, Foreign(p) => p.as_ptr(), }; StashMut(ptr, self) } } impl> FromGlibPtrNone<*mut T> for Boxed { #[inline] unsafe fn from_glib_none(ptr: *mut T) -> Self { assert!(!ptr.is_null()); let ptr = MM::copy(ptr); from_glib_full(ptr) } } impl> FromGlibPtrNone<*const T> for Boxed { #[inline] unsafe fn from_glib_none(ptr: *const T) -> Self { assert!(!ptr.is_null()); let ptr = MM::copy(ptr); from_glib_full(ptr) } } impl> FromGlibPtrFull<*mut T> for Boxed { #[inline] unsafe fn from_glib_full(ptr: *mut T) -> Self { assert!(!ptr.is_null()); Self { inner: AnyBox::Foreign(ptr::NonNull::new_unchecked(ptr)), _dummy: PhantomData, } } } impl> FromGlibPtrFull<*const T> for Boxed { #[inline] unsafe fn from_glib_full(ptr: *const T) -> Self { assert!(!ptr.is_null()); Self { inner: AnyBox::Foreign(ptr::NonNull::new_unchecked(ptr as *mut T)), _dummy: PhantomData, } } } impl> FromGlibPtrBorrow<*mut T> for Boxed { #[inline] unsafe fn from_glib_borrow(ptr: *mut T) -> Borrowed { assert!(!ptr.is_null()); Borrowed::new(Self { inner: AnyBox::Foreign(ptr::NonNull::new_unchecked(ptr)), _dummy: PhantomData, }) } } impl> Drop for Boxed { #[inline] fn drop(&mut self) { unsafe { match self.inner { AnyBox::Foreign(ptr) => { MM::free(ptr.as_ptr()); } AnyBox::Native(ref mut box_) => { MM::clear(&mut **box_); } } } } } impl> fmt::Debug for Boxed { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Boxed").field("inner", &self.inner).finish() } } impl> PartialOrd for Boxed { fn partial_cmp(&self, other: &Self) -> Option { self.to_glib_none().0.partial_cmp(&other.to_glib_none().0) } } impl> Ord for Boxed { fn cmp(&self, other: &Self) -> cmp::Ordering { self.to_glib_none().0.cmp(&other.to_glib_none().0) } } impl> PartialEq for Boxed { fn eq(&self, other: &Self) -> bool { self.to_glib_none().0 == other.to_glib_none().0 } } impl> Eq for Boxed {} impl> Hash for Boxed { fn hash(&self, state: &mut H) where H: Hasher, { self.to_glib_none().0.hash(state) } } impl> Clone for Boxed { #[inline] fn clone(&self) -> Self { unsafe { from_glib_none(self.to_glib_none().0 as *mut T) } } } impl> Deref for Boxed { type Target = T; fn deref(&self) -> &T { unsafe { // This is safe because the pointer will remain valid while self is borrowed &*self.to_glib_none().0 } } } impl> DerefMut for Boxed { fn deref_mut(&mut self) -> &mut T { unsafe { // This is safe because the pointer will remain valid while self is borrowed &mut *self.to_glib_none_mut().0 } } } glib-0.14.8/src/bridged_logging.rs000064400000000000000000000304670072674642500151400ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::log as glib_log; use crate::translate::*; /// Enumeration of the possible formatting behaviours for a /// [`GlibLogger`](struct.GlibLogger.html). /// /// In order to use this type, `glib` must be built with the `log` feature /// enabled. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum GlibLoggerFormat { /// A simple format, writing only the message on output. Plain, /// A simple format, writing file, line and message on output. LineAndFile, /// A logger using glib structured logging. Structured logging is available /// only on features `v2_56` and later. #[cfg(any(feature = "v2_56", feature = "dox"))] Structured, } /// Enumeration of the possible domain handling behaviours for a /// [`GlibLogger`](struct.GlibLogger.html). /// /// In order to use this type, `glib` must be built with the `log` feature /// enabled. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum GlibLoggerDomain { /// Logs will have no domain specified. None, /// Logs will use the `target` of the log crate as a domain; this allows /// Rust code, like `warn!(target: "my-domain", "...");` to log to the glib /// logger using the specified domain. CrateTarget, /// Logs will use the crate path as the log domain. CratePath, } /// An implementation of a [`log`](https://crates.io/crates/log) compatible /// logger which logs over glib logging facilities. /// /// In order to use this type, `glib` must be built with the `log` feature /// enabled. /// /// Use this if you want to use glib as the main logging output in your application, /// and want to route all logging happening through the log crate to glib logging. /// If you want the opposite, see /// [`rust_log_handler`](fn.rust_log_handler.html). /// /// NOTE: This should never be used when /// [`rust_log_handler`](fn.rust_log_handler.html) has /// been registered as a default glib log handler, otherwise a stack overflow /// will occur. /// /// Example: /// /// ```no_compile /// static glib_logger: glib::GlibLogger = glib::GlibLogger::new( /// glib::GlibLoggerFormat::Plain, /// glib::GlibLoggerDomain::CrateTarget, /// ); /// /// log::set_logger(&glib_logger); /// log::set_max_level(log::LevelFilter::Debug); /// /// log::info!("This line will get logged by glib"); /// ``` #[derive(Debug)] pub struct GlibLogger { format: GlibLoggerFormat, domain: GlibLoggerDomain, } impl GlibLogger { /// Creates a new instance of [`GlibLogger`](struct.GlibLogger.html). /// See documentation of [`GlibLogger`](struct.GlibLogger.html) for more /// information. /// /// Example: /// /// ```no_compile /// static glib_logger: glib::GlibLogger = glib::GlibLogger::new( /// glib::GlibLoggerFormat::Plain, /// glib::GlibLoggerDomain::CrateTarget, /// ); /// /// log::set_logger(&glib_logger); /// log::set_max_level(log::LevelFilter::Debug); /// /// log::info!("This line will get logged by glib"); /// ``` pub const fn new(format: GlibLoggerFormat, domain: GlibLoggerDomain) -> Self { Self { format, domain } } fn level_to_glib(level: rs_log::Level) -> crate::ffi::GLogLevelFlags { match level { // Errors are mapped to critical to avoid automatic termination rs_log::Level::Error => crate::ffi::G_LOG_LEVEL_CRITICAL, rs_log::Level::Warn => crate::ffi::G_LOG_LEVEL_WARNING, rs_log::Level::Info => crate::ffi::G_LOG_LEVEL_INFO, rs_log::Level::Debug => crate::ffi::G_LOG_LEVEL_DEBUG, // There is no equivalent to trace level in glib rs_log::Level::Trace => crate::ffi::G_LOG_LEVEL_DEBUG, } } #[doc(alias = "g_log")] fn write_log(domain: Option<&str>, level: rs_log::Level, message: &str) { unsafe { crate::ffi::g_log( domain.to_glib_none().0, GlibLogger::level_to_glib(level), message.replace("%", "%%").to_glib_none().0, ); } } #[cfg(any(feature = "v2_56", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_56")))] #[doc(alias = "g_log_structured_standard")] fn write_log_structured( domain: Option<&str>, level: rs_log::Level, file: Option<&str>, line: Option, func: Option<&str>, message: &str, ) { let line_str = line.map(|l| l.to_string()); unsafe { crate::ffi::g_log_structured_standard( domain.to_glib_none().0, GlibLogger::level_to_glib(level), file.to_glib_none().0, line_str.to_glib_none().0, func.to_glib_none().0, message.replace("%", "%%").to_glib_none().0, ); } } } impl rs_log::Log for GlibLogger { fn enabled(&self, _: &rs_log::Metadata) -> bool { true } fn log(&self, record: &rs_log::Record) { if !self.enabled(record.metadata()) { return; } let domain = match &self.domain { GlibLoggerDomain::None => None, GlibLoggerDomain::CrateTarget => Some(record.metadata().target()), GlibLoggerDomain::CratePath => record.module_path(), }; match self.format { GlibLoggerFormat::Plain => { let s = format!("{}", record.args()); GlibLogger::write_log(domain, record.level(), &s) } GlibLoggerFormat::LineAndFile => { let s = match (record.file(), record.line()) { (Some(file), Some(line)) => format!("{}:{}: {}", file, line, record.args()), (Some(file), None) => format!("{}: {}", file, record.args()), _ => format!("{}", record.args()), }; GlibLogger::write_log(domain, record.level(), &s); } #[cfg(any(feature = "v2_56", feature = "dox"))] GlibLoggerFormat::Structured => { GlibLogger::write_log_structured( domain, record.level(), record.file(), record.line(), None, &format!("{}", record.args()), ); } }; } fn flush(&self) {} } /// Provides a glib log handler which routes all logging messages to the /// [`log crate`](https://crates.io/crates/log). /// /// In order to use this function, `glib` must be built with the `log` feature /// enabled. /// /// Use this function if you want to use the log crate as the main logging /// output in your application, and want to route all logging happening in /// glib to the log crate. If you want the opposite, use [`GlibLogger`](struct.GlibLogger.html). /// /// NOTE: This should never be used when [`GlibLogger`](struct.GlibLogger.html) is /// registered as a logger, otherwise a stack overflow will occur. /// /// ```no_run /// glib::log_set_default_handler(glib::rust_log_handler); /// ``` pub fn rust_log_handler(domain: Option<&str>, level: glib_log::LogLevel, message: &str) { let level = match level { glib_log::LogLevel::Error | glib_log::LogLevel::Critical => rs_log::Level::Error, glib_log::LogLevel::Warning => rs_log::Level::Warn, glib_log::LogLevel::Message | glib_log::LogLevel::Info => rs_log::Level::Info, glib_log::LogLevel::Debug => rs_log::Level::Debug, }; rs_log::log!(target: domain.unwrap_or(""), level, "{}", message); } /// A macro which behaves exactly as `log::error!` except that it sets the /// current log target to the contents of a `G_LOG_DOMAIN` constant (and fails /// to build if not defined). /// /// In order to use this macro, `glib` must be built with the `log_macros` /// feature enabled and the [`GlibLogger`](struct.GlibLogger.html) must have been /// initialized using [`GlibLoggerDomain::CrateTarget`](enum.GlibLoggerDomain.html). /// /// ```no_run /// static G_LOG_DOMAIN: &str = "my-domain"; /// /// glib::error!("This will be logged under 'my-domain'"); /// ``` #[macro_export] #[cfg(any(feature = "dox", feature = "log_macros"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "log_macros")))] macro_rules! error { (target: $target:expr, $($arg:tt)+) => ( $crate::rs_log::log!(target: $target, $crate::rs_log::Level::Error, $($arg)+); ); ($($arg:tt)+) => ( $crate::rs_log::log!(target: G_LOG_DOMAIN, $crate::rs_log::Level::Error, $($arg)+); ) } /// A macro which behaves exactly as `log::warn!` except that it sets the /// current log target to the contents of a `G_LOG_DOMAIN` constant (and fails /// to build if not defined). /// /// In order to use this macro, `glib` must be built with the `log_macros` /// feature enabled and the [`GlibLogger`](struct.GlibLogger.html) must have been /// initialized using [`GlibLoggerDomain::CrateTarget`](enum.GlibLoggerDomain.html). /// /// ```no_run /// static G_LOG_DOMAIN: &str = "my-domain"; /// /// glib::warn!("This will be logged under 'my-domain'"); /// ``` #[macro_export] #[cfg(any(feature = "dox", feature = "log_macros"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "log_macros")))] macro_rules! warn { (target: $target:expr, $($arg:tt)+) => ( $crate::rs_log::log!(target: $target, $crate::rs_log::Level::Warn, $($arg)+); ); ($($arg:tt)+) => ( $crate::rs_log::log!(target: G_LOG_DOMAIN, $crate::rs_log::Level::Warn, $($arg)+); ) } /// A macro which behaves exactly as `log::info!` except that it sets the /// current log target to the contents of a `G_LOG_DOMAIN` constant (and fails /// to build if not defined). /// /// In order to use this macro, `glib` must be built with the `log_macros` /// feature enabled and the [`GlibLogger`](struct.GlibLogger.html) must have been /// initialized using [`GlibLoggerDomain::CrateTarget`](enum.GlibLoggerDomain.html). /// /// ```no_run /// static G_LOG_DOMAIN: &str = "my-domain"; /// /// glib::info!("This will be logged under 'my-domain'"); /// ``` #[macro_export] #[cfg(any(feature = "dox", feature = "log_macros"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "log_macros")))] macro_rules! info { (target: $target:expr, $($arg:tt)+) => ( $crate::rs_log::log!(target: $target, $crate::rs_log::Level::Info, $($arg)+); ); ($($arg:tt)+) => ( $crate::rs_log::log!(target: G_LOG_DOMAIN, $crate::rs_log::Level::Info, $($arg)+); ) } /// A macro which behaves exactly as `log::debug!` except that it sets the /// current log target to the contents of a `G_LOG_DOMAIN` constant (and fails /// to build if not defined). /// /// In order to use this macro, `glib` must be built with the `log_macros` /// feature enabled and the [`GlibLogger`](struct.GlibLogger.html) must have been /// initialized using [`GlibLoggerDomain::CrateTarget`](enum.GlibLoggerDomain.html). /// /// ```no_run /// static G_LOG_DOMAIN: &str = "my-domain"; /// /// glib::debug!("This will be logged under 'my-domain'"); /// ``` #[macro_export] #[cfg(any(feature = "dox", feature = "log_macros"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "log_macros")))] macro_rules! debug { (target: $target:expr, $($arg:tt)+) => ( $crate::rs_log::log!(target: $target, $crate::rs_log::Level::Debug, $($arg)+); ); ($($arg:tt)+) => ( $crate::rs_log::log!(target: G_LOG_DOMAIN, $crate::rs_log::Level::Debug, $($arg)+); ) } /// A macro which behaves exactly as `log::trace!` except that it sets the /// current log target to the contents of a `G_LOG_DOMAIN` constant (and fails /// to build if not defined). /// /// In order to use this macro, `glib` must be built with the `log_macros` /// feature enabled and the [`GlibLogger`](struct.GlibLogger.html) must have been /// initialized using [`GlibLoggerDomain::CrateTarget`](enum.GlibLoggerDomain.html). /// /// ```no_run /// static G_LOG_DOMAIN: &str = "my-domain"; /// /// glib::trace!("This will be logged under 'my-domain'"); /// ``` #[macro_export] #[cfg(any(feature = "dox", feature = "log_macros"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "log_macros")))] macro_rules! trace { (target: $target:expr, $($arg:tt)+) => ( $crate::rs_log::log!(target: $target, $crate::rs_log::Level::Trace, $($arg)+); ); ($($arg:tt)+) => ( $crate::rs_log::log!(target: G_LOG_DOMAIN, $crate::rs_log::Level::Trace, $($arg)+); ) } glib-0.14.8/src/byte_array.rs000064400000000000000000000165230072674642500141700ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! # Examples //! //! ``` //! use glib::prelude::*; // or `use gtk::prelude::*;` //! use glib::ByteArray; //! //! let ba = ByteArray::from(b"def"); //! ba.append(b"ghi").prepend(b"abc"); //! ba.remove_range(3, 3); //! assert_eq!(ba, "abcghi".as_bytes()); //! ``` use crate::translate::*; use std::borrow::Borrow; use std::cmp::Ordering; use std::fmt; use std::hash::{Hash, Hasher}; use std::mem; use std::ops::Deref; use std::ptr::NonNull; use std::slice; use crate::Bytes; wrapper! { #[doc(alias = "GByteArray")] pub struct ByteArray(Shared); match fn { ref => |ptr| ffi::g_byte_array_ref(ptr), unref => |ptr| ffi::g_byte_array_unref(ptr), type_ => || ffi::g_byte_array_get_type(), } } impl ByteArray { #[doc(alias = "g_byte_array_new")] pub fn new() -> Self { unsafe { from_glib_full(ffi::g_byte_array_new()) } } #[doc(alias = "g_byte_array_sized_new")] pub fn with_capacity(size: usize) -> Self { unsafe { from_glib_full(ffi::g_byte_array_sized_new(size as u32)) } } #[doc(alias = "g_byte_array_free_to_bytes")] pub fn into_gbytes(self) -> Bytes { unsafe { let s = mem::ManuallyDrop::new(self); from_glib_full(ffi::g_byte_array_free_to_bytes(mut_override( s.to_glib_none().0, ))) } } #[doc(alias = "g_byte_array_append")] pub fn append>(&self, data: &T) -> &Self { let bytes = data.as_ref(); unsafe { ffi::g_byte_array_append( self.to_glib_none().0, bytes.as_ptr() as *const _, bytes.len() as u32, ); } self } #[doc(alias = "g_byte_array_prepend")] pub fn prepend>(&self, data: &T) -> &Self { let bytes = data.as_ref(); unsafe { ffi::g_byte_array_prepend( self.to_glib_none().0, bytes.as_ptr() as *const _, bytes.len() as u32, ); } self } #[doc(alias = "g_byte_array_remove_index")] pub fn remove_index(&self, index: usize) { unsafe { ffi::g_byte_array_remove_index(self.to_glib_none().0, index as u32); } } #[doc(alias = "g_byte_array_remove_index_fast")] pub fn remove_index_fast(&self, index: usize) { unsafe { ffi::g_byte_array_remove_index_fast(self.to_glib_none().0, index as u32); } } #[doc(alias = "g_byte_array_remove_range")] pub fn remove_range(&self, index: usize, length: usize) { unsafe { ffi::g_byte_array_remove_range(self.to_glib_none().0, index as u32, length as u32); } } #[doc(alias = "g_byte_array_set_size")] pub unsafe fn set_size(&self, size: usize) { ffi::g_byte_array_set_size(self.to_glib_none().0, size as u32); } #[doc(alias = "g_byte_array_sort_with_data")] pub fn sort Ordering>(&self, compare_func: F) { unsafe extern "C" fn compare_func_trampoline( a: ffi::gconstpointer, b: ffi::gconstpointer, func: ffi::gpointer, ) -> i32 { let func = func as *mut &mut (dyn FnMut(&u8, &u8) -> Ordering); let a = &*(a as *const u8); let b = &*(b as *const u8); match (*func)(a, b) { Ordering::Less => -1, Ordering::Equal => 0, Ordering::Greater => 1, } } unsafe { let mut func = compare_func; let func_obj: &mut (dyn FnMut(&u8, &u8) -> Ordering) = &mut func; let func_ptr = &func_obj as *const &mut (dyn FnMut(&u8, &u8) -> Ordering) as ffi::gpointer; ffi::g_byte_array_sort_with_data( self.to_glib_none().0, Some(compare_func_trampoline), func_ptr, ); } } } impl AsRef<[u8]> for ByteArray { fn as_ref(&self) -> &[u8] { &*self } } impl<'a, T: ?Sized + Borrow<[u8]> + 'a> From<&'a T> for ByteArray { fn from(value: &'a T) -> ByteArray { let ba = ByteArray::new(); ba.append(value.borrow()); ba } } impl Deref for ByteArray { type Target = [u8]; fn deref(&self) -> &[u8] { unsafe { let mut ptr = (*self.to_glib_none().0).data; let len = (*self.to_glib_none().0).len as usize; debug_assert!(!ptr.is_null() || len == 0); if ptr.is_null() { ptr = NonNull::dangling().as_ptr(); } slice::from_raw_parts(ptr as *const u8, len) } } } impl Default for ByteArray { fn default() -> Self { Self::new() } } impl fmt::Debug for ByteArray { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("ByteArray") .field("ptr", &self.to_glib_none().0) .field("data", &&self[..]) .finish() } } macro_rules! impl_cmp { ($lhs:ty, $rhs: ty) => { #[allow(clippy::redundant_slicing)] impl<'a, 'b> PartialEq<$rhs> for $lhs { #[inline] fn eq(&self, other: &$rhs) -> bool { self[..].eq(&other[..]) } } #[allow(clippy::redundant_slicing)] impl<'a, 'b> PartialEq<$lhs> for $rhs { #[inline] fn eq(&self, other: &$lhs) -> bool { self[..].eq(&other[..]) } } #[allow(clippy::redundant_slicing)] impl<'a, 'b> PartialOrd<$rhs> for $lhs { #[inline] fn partial_cmp(&self, other: &$rhs) -> Option { self[..].partial_cmp(&other[..]) } } #[allow(clippy::redundant_slicing)] impl<'a, 'b> PartialOrd<$lhs> for $rhs { #[inline] fn partial_cmp(&self, other: &$lhs) -> Option { self[..].partial_cmp(&other[..]) } } }; } impl_cmp!(ByteArray, [u8]); impl_cmp!(ByteArray, &'a [u8]); impl_cmp!(&'a ByteArray, [u8]); impl_cmp!(ByteArray, Vec); impl_cmp!(&'a ByteArray, Vec); impl PartialEq for ByteArray { fn eq(&self, other: &Self) -> bool { self[..] == other[..] } } impl Eq for ByteArray {} impl Hash for ByteArray { fn hash(&self, state: &mut H) { self.len().hash(state); Hash::hash_slice(&self[..], state) } } #[cfg(test)] mod tests { use super::*; use std::collections::HashSet; #[test] fn various() { let ba: ByteArray = Default::default(); ba.append("foo").append("bar").prepend("baz"); ba.remove_index(0); ba.remove_index_fast(1); ba.remove_range(1, 2); ba.sort(|a, b| a.cmp(b)); unsafe { ba.set_size(3) }; assert_eq!(ba, b"aab" as &[u8]); let abc: &[u8] = b"abc"; assert_eq!(ByteArray::from(abc), b"abc" as &[u8]); } #[test] fn hash() { let b1 = ByteArray::from(b"this is a test"); let b2 = ByteArray::from(b"this is a test"); let b3 = ByteArray::from(b"test"); let mut set = HashSet::new(); set.insert(b1); assert!(set.contains(&b2)); assert!(!set.contains(&b3)); } } glib-0.14.8/src/bytes.rs000064400000000000000000000152050072674642500131510ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::*; use std::borrow::Borrow; use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; use std::fmt; use std::hash::{Hash, Hasher}; use std::ops::Deref; use std::slice; wrapper! { /// A shared immutable byte slice (the equivalent of `Rc<[u8]>`). /// /// `From` implementations that take references (e.g. `&[u8]`) copy the /// data. The `from_static` constructor avoids copying static data. /// /// ``` /// use glib::Bytes; /// /// let v = vec![1, 2, 3]; /// let b = Bytes::from(&v); /// assert_eq!(v, b); /// /// let s = b"xyz"; /// let b = Bytes::from_static(s); /// assert_eq!(&s[..], b); /// ``` #[doc(alias = "GBytes")] pub struct Bytes(Shared); match fn { ref => |ptr| ffi::g_bytes_ref(ptr), unref => |ptr| ffi::g_bytes_unref(ptr), type_ => || ffi::g_bytes_get_type(), } } impl Bytes { /// Copies `data` into a new shared slice. #[doc(alias = "g_bytes_new")] fn new>(data: T) -> Bytes { let data = data.as_ref(); unsafe { from_glib_full(ffi::g_bytes_new(data.as_ptr() as *const _, data.len())) } } /// Creates a view into static `data` without copying. #[doc(alias = "g_bytes_new_static")] pub fn from_static(data: &'static [u8]) -> Bytes { unsafe { from_glib_full(ffi::g_bytes_new_static( data.as_ptr() as *const _, data.len(), )) } } /// Takes ownership of `data` and creates a new `Bytes` without copying. pub fn from_owned + Send + 'static>(data: T) -> Bytes { let data: Box = Box::new(data); let (size, data_ptr) = { let data = (*data).as_ref(); (data.len(), data.as_ptr()) }; unsafe extern "C" fn drop_box + Send + 'static>(b: ffi::gpointer) { let _: Box = Box::from_raw(b as *mut _); } unsafe { from_glib_full(ffi::g_bytes_new_with_free_func( data_ptr as *const _, size, Some(drop_box::), Box::into_raw(data) as *mut _, )) } } } unsafe impl Send for Bytes {} unsafe impl Sync for Bytes {} impl<'a, T: ?Sized + Borrow<[u8]> + 'a> From<&'a T> for Bytes { fn from(value: &'a T) -> Bytes { Bytes::new(value.borrow()) } } impl fmt::Debug for Bytes { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Bytes") .field("ptr", &self.to_glib_none().0) .field("data", &&self[..]) .finish() } } impl AsRef<[u8]> for Bytes { fn as_ref(&self) -> &[u8] { &*self } } impl Deref for Bytes { type Target = [u8]; fn deref(&self) -> &[u8] { unsafe { let mut len = 0; let ptr = ffi::g_bytes_get_data(self.to_glib_none().0, &mut len); debug_assert!(!ptr.is_null() || len == 0); slice::from_raw_parts(ptr as *const u8, len) } } } impl PartialEq for Bytes { #[doc(alias = "g_bytes_equal")] fn eq(&self, other: &Self) -> bool { unsafe { from_glib(ffi::g_bytes_equal( self.to_glib_none().0 as *const _, other.to_glib_none().0 as *const _, )) } } } impl Eq for Bytes {} impl PartialOrd for Bytes { fn partial_cmp(&self, other: &Self) -> Option { unsafe { let ret = ffi::g_bytes_compare( self.to_glib_none().0 as *const _, other.to_glib_none().0 as *const _, ); ret.partial_cmp(&0) } } } impl Ord for Bytes { fn cmp(&self, other: &Self) -> Ordering { unsafe { let ret = ffi::g_bytes_compare( self.to_glib_none().0 as *const _, other.to_glib_none().0 as *const _, ); ret.cmp(&0) } } } macro_rules! impl_cmp { ($lhs:ty, $rhs: ty) => { #[allow(clippy::redundant_slicing)] impl<'a, 'b> PartialEq<$rhs> for $lhs { #[inline] fn eq(&self, other: &$rhs) -> bool { self[..].eq(&other[..]) } } #[allow(clippy::redundant_slicing)] impl<'a, 'b> PartialEq<$lhs> for $rhs { #[inline] fn eq(&self, other: &$lhs) -> bool { self[..].eq(&other[..]) } } #[allow(clippy::redundant_slicing)] impl<'a, 'b> PartialOrd<$rhs> for $lhs { #[inline] fn partial_cmp(&self, other: &$rhs) -> Option { self[..].partial_cmp(&other[..]) } } #[allow(clippy::redundant_slicing)] impl<'a, 'b> PartialOrd<$lhs> for $rhs { #[inline] fn partial_cmp(&self, other: &$lhs) -> Option { self[..].partial_cmp(&other[..]) } } }; } impl_cmp!(Bytes, [u8]); impl_cmp!(Bytes, &'a [u8]); impl_cmp!(&'a Bytes, [u8]); impl_cmp!(Bytes, Vec); impl_cmp!(&'a Bytes, Vec); impl Hash for Bytes { fn hash(&self, state: &mut H) { self.len().hash(state); Hash::hash_slice(self, state) } } #[cfg(test)] mod tests { use super::*; use std::collections::HashSet; #[test] fn eq() { let abc: &[u8] = b"abc"; let def: &[u8] = b"def"; let a1 = Bytes::from(abc); let a2 = Bytes::from(abc); let d = Bytes::from(def); assert_eq!(a1, a2); assert_eq!(def, d); assert_ne!(a1, d); assert_ne!(a1, def); } #[test] fn ord() { let abc: &[u8] = b"abc"; let def: &[u8] = b"def"; let a = Bytes::from(abc); let d = Bytes::from(def); assert!(a < d); assert!(a < def); assert!(abc < d); assert!(d > a); assert!(d > abc); assert!(def > a); } #[test] fn hash() { let b1 = Bytes::from(b"this is a test"); let b2 = Bytes::from(b"this is a test"); let b3 = Bytes::from(b"test"); let mut set = HashSet::new(); set.insert(b1); assert!(set.contains(&b2)); assert!(!set.contains(&b3)); } #[test] fn from_static() { let b1 = Bytes::from_static(b"this is a test"); let b2 = Bytes::from(b"this is a test"); assert_eq!(b1, b2); } #[test] fn from_owned() { let b = Bytes::from_owned(vec![1, 2, 3]); assert_eq!(b, [1u8, 2u8, 3u8].as_ref()); } } glib-0.14.8/src/char.rs000064400000000000000000000127330072674642500127430ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::FromGlib; use crate::translate::IntoGlib; use libc::{c_char, c_uchar}; use std::convert::TryFrom; use std::num::TryFromIntError; /// Wrapper for values where C functions expect a plain C `char` /// /// Consider the following C function prototype from glib: /// /// ```C /// void g_key_file_set_list_separator (GKeyFile *key_file, gchar separator); /// ``` /// /// This function plainly expects a byte as the `separator` argument. However, /// having this function exposed to Rust as the following would be inconvenient: /// /// ```ignore /// impl KeyFile { /// pub fn set_list_separator(&self, separator: libc:c_char) { } /// } /// ``` /// /// This would be inconvenient because users would have to do the conversion from a Rust `char` to an `libc::c_char` by hand, which is just a type alias /// for `i8` on most system. /// /// This `Char` type is a wrapper over an `libc::c_char`, so that we can pass it to Glib or C functions. /// The check for whether a Rust `char` (a Unicode scalar value) actually fits in a `libc::c_char` is /// done in the `new` function; see its documentation for details. /// /// The inner `libc::c_char` (which is equivalent to `i8`) can be extracted with `.0`, or /// by calling `my_char.into_glib()`. /// /// # Examples /// ``` /// use glib::Char; /// use std::convert::TryFrom; /// /// Char::from(b'a'); /// Char::try_from('a').unwrap(); /// assert!(Char::try_from('☔').is_err()); /// ``` /// /// ```ignore /// extern "C" fn have_a_byte(b: libc::c_char); /// /// have_a_byte(Char::from(b'a').into_glib()); /// ``` #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct Char(pub c_char); impl TryFrom for Char { type Error = TryFromIntError; #[allow(clippy::unnecessary_cast)] fn try_from(c: char) -> Result { Ok(Self(u8::try_from(u32::from(c))? as c_char)) } } impl From for char { fn from(c: Char) -> char { c.0 as u8 as char } } impl From for Char { #[allow(clippy::unnecessary_cast)] fn from(c: u8) -> Char { Char(c as c_char) } } impl From for u8 { #[allow(clippy::unnecessary_cast)] fn from(c: Char) -> u8 { c.0 as u8 } } #[doc(hidden)] impl FromGlib for Char { unsafe fn from_glib(value: c_char) -> Self { Self(value) } } #[doc(hidden)] impl IntoGlib for Char { type GlibType = c_char; fn into_glib(self) -> c_char { self.0 } } /// Wrapper for values where C functions expect a plain C `unsigned char` /// /// This `UChar` type is a wrapper over an `libc::c_uchar`, so that we can pass it to Glib or C functions. /// The check for whether a Rust `char` (a Unicode scalar value) actually fits in a `libc::c_uchar` is /// done in the `new` function; see its documentation for details. /// /// The inner `libc::c_uchar` (which is equivalent to `u8`) can be extracted with `.0`, or /// by calling `my_char.into_glib()`. /// /// # Examples /// ``` /// use glib::UChar; /// use std::convert::TryFrom; /// /// UChar::from(b'a'); /// UChar::try_from('a').unwrap(); /// assert!(UChar::try_from('☔').is_err()); /// ``` /// /// ```ignore /// extern "C" fn have_a_byte(b: libc::c_uchar); /// /// have_a_byte(UChar::from(b'a').into_glib()); /// ``` #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct UChar(pub c_uchar); impl TryFrom for UChar { type Error = TryFromIntError; #[allow(clippy::unnecessary_cast)] fn try_from(c: char) -> Result { Ok(Self(u8::try_from(u32::from(c))? as c_uchar)) } } impl From for char { fn from(c: UChar) -> char { c.0 as char } } impl From for UChar { #[allow(clippy::unnecessary_cast)] fn from(c: u8) -> UChar { UChar(c as c_uchar) } } impl From for u8 { fn from(c: UChar) -> u8 { c.0 as u8 } } #[doc(hidden)] impl FromGlib for UChar { unsafe fn from_glib(value: c_uchar) -> Self { Self(value) } } #[doc(hidden)] impl IntoGlib for UChar { type GlibType = c_uchar; fn into_glib(self) -> c_uchar { self.0 } } #[cfg(test)] mod tests { use super::*; use crate::translate::from_glib; #[test] #[allow(clippy::unnecessary_cast)] fn converts_single_byte_chars() { assert_eq!(Char::try_from(0 as char), Ok(Char(0 as c_char))); assert_eq!(UChar::try_from(0 as char), Ok(UChar(0 as c_uchar))); assert_eq!(UChar::try_from(255 as char), Ok(UChar(255 as c_uchar))); assert_eq!(UChar::try_from('ñ'), Ok(UChar(241 as c_uchar))); } #[test] fn refuses_multibyte_chars() { assert!(Char::try_from('☔').is_err()); // no umbrella for you assert!(UChar::try_from('☔').is_err()); } #[test] #[allow(clippy::unnecessary_cast)] fn into_i8() { assert_eq!(Char::from(b'A').into_glib(), 65 as c_char); } #[test] #[allow(clippy::unnecessary_cast)] fn into_u8() { assert_eq!(UChar::from(b'A').into_glib(), 65 as c_uchar); } #[test] #[allow(clippy::unnecessary_cast)] fn into_char() { assert_eq!(char::from(Char(65 as c_char)), 'A'); assert_eq!('ñ', UChar(241 as c_uchar).into()); } #[test] #[allow(clippy::unnecessary_cast)] fn convert_from_glib() { assert_eq!(Char(65 as c_char), unsafe { from_glib(65 as c_char) }); assert_eq!(UChar(241 as c_uchar), unsafe { from_glib(241 as c_uchar) }); } } glib-0.14.8/src/checksum.rs000064400000000000000000000037160072674642500136310ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::*; use crate::Checksum; use libc::size_t; use std::vec::Vec; impl Checksum { #[doc(alias = "g_checksum_get_digest")] #[doc(alias = "get_digest")] pub fn digest(self) -> Vec { unsafe { //Don't forget update when `ChecksumType` contains type bigger that Sha512. let mut digest_len: size_t = 512 / 8; let mut vec = Vec::with_capacity(digest_len as usize); ffi::g_checksum_get_digest( mut_override(self.to_glib_none().0), vec.as_mut_ptr(), &mut digest_len, ); vec.set_len(digest_len); vec } } #[doc(alias = "g_checksum_get_string")] #[doc(alias = "get_string")] pub fn string(self) -> Option { unsafe { from_glib_none(ffi::g_checksum_get_string(mut_override( self.to_glib_none().0, ))) } } } #[cfg(test)] mod tests { use crate::{Checksum, ChecksumType}; const CS_TYPE: ChecksumType = ChecksumType::Md5; const CS_VALUE: &str = "fc3ff98e8c6a0d3087d515c0473f8677"; const CS_SLICE: &[u8] = &[ 0xfc, 0x3f, 0xf9, 0x8e, 0x8c, 0x6a, 0x0d, 0x30, 0x87, 0xd5, 0x15, 0xc0, 0x47, 0x3f, 0x86, 0x77, ]; #[test] fn update() { let mut cs = Checksum::new(CS_TYPE).unwrap(); cs.update(b"hello world!"); assert_eq!(cs.string().unwrap(), CS_VALUE); } #[test] fn update_multi_call() { let mut cs = Checksum::new(CS_TYPE).unwrap(); cs.update(b"hello "); cs.update(b"world!"); assert_eq!(cs.string().unwrap(), CS_VALUE); } #[test] #[doc(alias = "get_digest")] fn digest() { let mut cs = Checksum::new(CS_TYPE).unwrap(); cs.update(b"hello world!"); let vec = cs.digest(); assert_eq!(vec, CS_SLICE); } } glib-0.14.8/src/clone.rs000064400000000000000000000035120072674642500131210ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::marker::PhantomData; use std::rc::{self, Rc}; use std::sync::{self, Arc}; /// Trait for generalizing downgrading a strong reference to a weak reference. pub trait Downgrade where Self: Sized, { /// Weak reference type. type Weak; /// Downgrade to a weak reference. fn downgrade(&self) -> Self::Weak; } /// Trait for generalizing upgrading a weak reference to a strong reference. pub trait Upgrade where Self: Sized, { /// Strong reference type. type Strong; /// Try upgrading a weak reference to a strong reference. fn upgrade(&self) -> Option; } impl Upgrade for crate::WeakRef { type Strong = T; fn upgrade(&self) -> Option { self.upgrade() } } impl Downgrade for PhantomData { type Weak = PhantomData; fn downgrade(&self) -> Self::Weak { PhantomData } } impl Downgrade for &T { type Weak = T::Weak; fn downgrade(&self) -> Self::Weak { T::downgrade(*self) } } impl Downgrade for Arc { type Weak = sync::Weak; fn downgrade(&self) -> Self::Weak { Arc::downgrade(self) } } impl Upgrade for PhantomData { type Strong = PhantomData; fn upgrade(&self) -> Option { Some(PhantomData) } } impl Upgrade for sync::Weak { type Strong = Arc; fn upgrade(&self) -> Option { self.upgrade() } } impl Downgrade for Rc { type Weak = rc::Weak; fn downgrade(&self) -> Self::Weak { Rc::downgrade(self) } } impl Upgrade for rc::Weak { type Strong = Rc; fn upgrade(&self) -> Option { self.upgrade() } } glib-0.14.8/src/closure.rs000064400000000000000000000133370072674642500135030ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // TODO: support marshaller. use std::mem; use std::ptr; use std::slice; use libc::{c_uint, c_void}; use crate::translate::{from_glib_none, mut_override, ToGlibPtr, ToGlibPtrMut, Uninitialized}; use crate::ToValue; use crate::Value; wrapper! { #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] #[doc(alias = "GClosure")] pub struct Closure(Shared); match fn { ref => |ptr| { gobject_ffi::g_closure_ref(ptr); gobject_ffi::g_closure_sink(ptr); }, unref => |ptr| gobject_ffi::g_closure_unref(ptr), type_ => || gobject_ffi::g_closure_get_type(), } } impl Closure { pub fn new Option + Send + Sync + 'static>(callback: F) -> Self { unsafe { Self::new_unsafe(callback) } } pub fn new_local Option + 'static>(callback: F) -> Self { let callback = crate::ThreadGuard::new(callback); unsafe { Self::new_unsafe(move |values| (callback.get_ref())(values)) } } pub unsafe fn new_unsafe Option>(callback: F) -> Self { unsafe extern "C" fn marshal( _closure: *mut gobject_ffi::GClosure, return_value: *mut gobject_ffi::GValue, n_param_values: c_uint, param_values: *const gobject_ffi::GValue, _invocation_hint: *mut c_void, marshal_data: *mut c_void, ) where F: Fn(&[Value]) -> Option, { let values = slice::from_raw_parts(param_values as *const _, n_param_values as usize); let callback: &F = &*(marshal_data as *mut _); let result = callback(values); if !return_value.is_null() { match result { Some(result) => *return_value = result.into_raw(), None => { let result = Value::uninitialized(); *return_value = result.into_raw(); } } } } unsafe extern "C" fn finalize( notify_data: *mut c_void, _closure: *mut gobject_ffi::GClosure, ) where F: Fn(&[Value]) -> Option, { let _callback: Box = Box::from_raw(notify_data as *mut _); // callback is dropped here. } // Due to bitfields we have to do our own calculations here for the size of the GClosure: // - 4: 32 bits in guint bitfields at the beginning // - padding due to alignment needed for the following pointer // - 3 * size_of<*mut c_void>: 3 pointers // We don't store any custom data ourselves in the GClosure let size = u32::max(4, mem::align_of::<*mut c_void>() as u32) + 3 * mem::size_of::<*mut c_void>() as u32; let closure = gobject_ffi::g_closure_new_simple(size, ptr::null_mut()); assert_ne!(closure, ptr::null_mut()); let callback = Box::new(callback); let ptr: *mut F = Box::into_raw(callback); let ptr: *mut c_void = ptr as *mut _; gobject_ffi::g_closure_set_meta_marshal(closure, ptr, Some(marshal::)); gobject_ffi::g_closure_add_finalize_notifier(closure, ptr, Some(finalize::)); from_glib_none(closure) } pub fn invoke(&self, values: &[&dyn ToValue]) -> Option { let values = values .iter() .copied() .map(ToValue::to_value) .collect::>(); self.invoke_with_values(&values) } pub fn invoke_with_values(&self, values: &[Value]) -> Option { let result = unsafe { let mut result = Value::uninitialized(); gobject_ffi::g_closure_invoke( self.to_glib_none().0 as *mut _, result.to_glib_none_mut().0, values.len() as u32, mut_override(values.as_ptr()) as *mut gobject_ffi::GValue, ptr::null_mut(), ); result }; Some(result).filter(|r| r.type_().is_valid()) } } unsafe impl Send for Closure {} unsafe impl Sync for Closure {} #[cfg(test)] mod tests { use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use super::Closure; use crate::{ToValue, Value}; #[allow(clippy::unnecessary_wraps)] fn closure_fn(values: &[Value]) -> Option { assert_eq!(values.len(), 2); let string_arg = values[0].get::<&str>(); assert_eq!(string_arg, Ok("test")); let int_arg = values[1].get::(); assert_eq!(int_arg, Ok(42)); Some(24.to_value()) } #[test] fn test_closure() { let call_count = Arc::new(AtomicUsize::new(0)); let count = call_count.clone(); let closure = Closure::new(move |values| { count.fetch_add(1, Ordering::Relaxed); assert_eq!(values.len(), 2); let string_arg = values[0].get::<&str>(); assert_eq!(string_arg, Ok("test")); let int_arg = values[1].get::(); assert_eq!(int_arg, Ok(42)); None }); let result = closure.invoke(&[&"test", &42]); assert!(result.is_none()); assert_eq!(call_count.load(Ordering::Relaxed), 1); let result = closure.invoke(&[&"test", &42]); assert!(result.is_none()); assert_eq!(call_count.load(Ordering::Relaxed), 2); let closure = Closure::new(closure_fn); let result = closure.invoke(&[&"test", &42]); let int_res = result.map(|result| result.get::()); assert_eq!(int_res, Some(Ok(24))); } } glib-0.14.8/src/date.rs000064400000000000000000000324600072674642500127420ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::*; use crate::BoolError; use crate::DateDay; use crate::DateMonth; use crate::DateWeekday; use crate::DateYear; use std::cmp; use std::fmt; use std::hash; wrapper! { #[doc(alias = "GDate")] pub struct Date(Boxed); match fn { copy => |ptr| gobject_ffi::g_boxed_copy(ffi::g_date_get_type(), ptr as *const _) as *mut _, free => |ptr| ffi::g_date_free(ptr), init => |_ptr| (), clear => |ptr| ffi::g_date_clear(ptr, 1), type_ => || ffi::g_date_get_type(), } } unsafe impl Send for Date {} unsafe impl Sync for Date {} impl Date { #[doc(alias = "g_date_new_dmy")] pub fn new_dmy(day: DateDay, month: DateMonth, year: DateYear) -> Result { let month = month.into_glib(); unsafe { let check: bool = from_glib(ffi::g_date_valid_dmy(day, month, year)); if !check { Err(bool_error!("Invalid date")) } else { Ok(from_glib_full(ffi::g_date_new_dmy(day, month, year))) } } } #[doc(alias = "g_date_new_julian")] pub fn new_julian(julian_day: u32) -> Result { if !Self::valid_julian(julian_day) { Err(bool_error!("Invalid date")) } else { unsafe { Ok(from_glib_full(ffi::g_date_new_julian(julian_day))) } } } #[doc(alias = "g_date_add_days")] pub fn add_days(&mut self, n_days: u32) -> Result<(), BoolError> { let julian_days = self.julian(); if julian_days == 0 || n_days > u32::MAX - julian_days { Err(bool_error!("Invalid date")) } else { unsafe { ffi::g_date_add_days(self.to_glib_none_mut().0, n_days); } Ok(()) } } #[doc(alias = "g_date_add_months")] pub fn add_months(&mut self, n_months: u32) -> Result<(), BoolError> { // The checks for this function are just a mess in the C code, allowing intermediate // unknown state. So for now, nothing can be done... unsafe { ffi::g_date_add_months(self.to_glib_none_mut().0, n_months); } Ok(()) } #[doc(alias = "g_date_add_years")] pub fn add_years(&mut self, n_years: u16) -> Result<(), BoolError> { let year = self.year(); if n_years > u16::MAX - year { Err(bool_error!("Invalid date")) } else { unsafe { ffi::g_date_add_years(self.to_glib_none_mut().0, n_years as _); } Ok(()) } } #[doc(alias = "g_date_clamp")] pub fn clamp(&mut self, min_date: &Date, max_date: &Date) -> Result<(), BoolError> { if min_date >= max_date { Err(bool_error!("`min_date` must be before `max_date`")) } else { unsafe { ffi::g_date_clamp( self.to_glib_none_mut().0, min_date.to_glib_none().0, max_date.to_glib_none().0, ); } Ok(()) } } #[doc(alias = "g_date_compare")] fn compare(&self, rhs: &Date) -> i32 { unsafe { ffi::g_date_compare(self.to_glib_none().0, rhs.to_glib_none().0) } } #[doc(alias = "g_date_days_between")] pub fn days_between(&self, date2: &Date) -> i32 { unsafe { ffi::g_date_days_between(self.to_glib_none().0, date2.to_glib_none().0) } } #[doc(alias = "g_date_get_day")] #[doc(alias = "get_day")] pub fn day(&self) -> DateDay { unsafe { ffi::g_date_get_day(self.to_glib_none().0) } } #[doc(alias = "g_date_get_day_of_year")] #[doc(alias = "get_day_of_year")] pub fn day_of_year(&self) -> u32 { unsafe { ffi::g_date_get_day_of_year(self.to_glib_none().0) } } #[doc(alias = "g_date_get_iso8601_week_of_year")] #[doc(alias = "get_iso8601_week_of_year")] pub fn iso8601_week_of_year(&self) -> u32 { unsafe { ffi::g_date_get_iso8601_week_of_year(self.to_glib_none().0) } } #[doc(alias = "g_date_get_julian")] #[doc(alias = "get_julian")] pub fn julian(&self) -> u32 { unsafe { ffi::g_date_get_julian(self.to_glib_none().0) } } #[doc(alias = "g_date_get_monday_week_of_year")] #[doc(alias = "get_monday_week_of_year")] pub fn monday_week_of_year(&self) -> u32 { unsafe { ffi::g_date_get_monday_week_of_year(self.to_glib_none().0) } } #[doc(alias = "g_date_get_month")] #[doc(alias = "get_month")] pub fn month(&self) -> DateMonth { unsafe { from_glib(ffi::g_date_get_month(self.to_glib_none().0)) } } #[doc(alias = "g_date_get_sunday_week_of_year")] #[doc(alias = "get_sunday_week_of_year")] pub fn sunday_week_of_year(&self) -> u32 { unsafe { ffi::g_date_get_sunday_week_of_year(self.to_glib_none().0) } } #[doc(alias = "g_date_get_weekday")] #[doc(alias = "get_weekday")] pub fn weekday(&self) -> DateWeekday { unsafe { from_glib(ffi::g_date_get_weekday(self.to_glib_none().0)) } } #[doc(alias = "g_date_get_year")] #[doc(alias = "get_year")] pub fn year(&self) -> DateYear { unsafe { ffi::g_date_get_year(self.to_glib_none().0) } } #[doc(alias = "g_date_is_first_of_month")] pub fn is_first_of_month(&self) -> bool { unsafe { from_glib(ffi::g_date_is_first_of_month(self.to_glib_none().0)) } } #[doc(alias = "g_date_is_last_of_month")] pub fn is_last_of_month(&self) -> bool { unsafe { from_glib(ffi::g_date_is_last_of_month(self.to_glib_none().0)) } } #[doc(alias = "g_date_order")] pub fn order(&mut self, date2: &mut Date) { unsafe { ffi::g_date_order(self.to_glib_none_mut().0, date2.to_glib_none_mut().0); } } #[doc(alias = "g_date_set_day")] pub fn set_day(&mut self, day: DateDay) -> Result<(), BoolError> { if !Self::valid_dmy(day, self.month(), self.year()) { Err(bool_error!("invalid day")) } else { unsafe { ffi::g_date_set_day(self.to_glib_none_mut().0, day); } Ok(()) } } #[doc(alias = "g_date_set_dmy")] pub fn set_dmy( &mut self, day: DateDay, month: DateMonth, y: DateYear, ) -> Result<(), BoolError> { if !Self::valid_dmy(day, month, y) { Err(bool_error!("invalid date")) } else { unsafe { ffi::g_date_set_dmy(self.to_glib_none_mut().0, day, month.into_glib(), y); } Ok(()) } } #[doc(alias = "g_date_set_julian")] pub fn set_julian(&mut self, julian_date: u32) -> Result<(), BoolError> { if !Self::valid_julian(julian_date) { Err(bool_error!("invalid date")) } else { unsafe { ffi::g_date_set_julian(self.to_glib_none_mut().0, julian_date); } Ok(()) } } #[doc(alias = "g_date_set_month")] pub fn set_month(&mut self, month: DateMonth) -> Result<(), BoolError> { if !Self::valid_dmy(self.day(), month, self.year()) { Err(bool_error!("invalid month")) } else { unsafe { ffi::g_date_set_month(self.to_glib_none_mut().0, month.into_glib()); } Ok(()) } } #[doc(alias = "g_date_set_parse")] pub fn set_parse(&mut self, str: &str) -> Result<(), BoolError> { let mut c = self.clone(); if !unsafe { ffi::g_date_set_parse(c.to_glib_none_mut().0, str.to_glib_none().0); ffi::g_date_valid(c.to_glib_none().0) == 0 } { Err(bool_error!("invalid parse string")) } else { *self = c; Ok(()) } } #[doc(alias = "g_date_set_time_t")] pub fn set_time(&mut self, time_: u32) -> Result<(), BoolError> { let mut c = self.clone(); unsafe { ffi::g_date_set_time_t(c.to_glib_none_mut().0, time_ as _); } if !Self::valid_dmy(c.day(), c.month(), c.year()) { Err(bool_error!("invalid time")) } else { *self = c; Ok(()) } } //pub fn set_time_val(&mut self, timeval: /*Ignored*/&mut TimeVal) { // unsafe { TODO: call ffi::g_date_set_time_val() } //} #[doc(alias = "g_date_set_year")] pub fn set_year(&mut self, year: DateYear) -> Result<(), BoolError> { if !Self::valid_dmy(self.day(), self.month(), year) { Err(bool_error!("invalid year")) } else { unsafe { ffi::g_date_set_year(self.to_glib_none_mut().0, year); } Ok(()) } } #[doc(alias = "g_date_subtract_days")] pub fn subtract_days(&mut self, n_days: u32) -> Result<(), BoolError> { let julian = self.julian(); if julian > n_days { Err(bool_error!("invalid number of days")) } else { unsafe { ffi::g_date_subtract_days(self.to_glib_none_mut().0, n_days); } Ok(()) } } #[doc(alias = "g_date_subtract_months")] pub fn subtract_months(&mut self, n_months: u32) -> Result<(), BoolError> { // The checks for this function are just a mess in the C code, allowing intermediate // unknown state. So for now, nothing can be done... unsafe { ffi::g_date_subtract_months(self.to_glib_none_mut().0, n_months); } Ok(()) } #[doc(alias = "g_date_subtract_years")] pub fn subtract_years(&mut self, n_years: u16) -> Result<(), BoolError> { if self.year() < n_years { Err(bool_error!("invalid number of years")) } else { unsafe { ffi::g_date_subtract_years(self.to_glib_none_mut().0, n_years as _); } Ok(()) } } //#[doc(alias="g_date_to_struct_tm")] //pub fn to_struct_tm(&self, tm: /*Unimplemented*/Fundamental: Pointer) { // unsafe { TODO: call ffi::g_date_to_struct_tm() } //} #[doc(alias = "g_date_valid")] pub fn valid(&self) -> bool { unsafe { from_glib(ffi::g_date_valid(self.to_glib_none().0)) } } #[doc(alias = "g_date_get_days_in_month")] #[doc(alias = "get_days_in_month")] pub fn days_in_month(month: DateMonth, year: DateYear) -> u8 { unsafe { ffi::g_date_get_days_in_month(month.into_glib(), year) } } #[doc(alias = "g_date_get_monday_weeks_in_year")] #[doc(alias = "get_monday_weeks_in_year")] pub fn monday_weeks_in_year(year: DateYear) -> u8 { unsafe { ffi::g_date_get_monday_weeks_in_year(year) } } #[doc(alias = "g_date_get_sunday_weeks_in_year")] #[doc(alias = "get_sunday_weeks_in_year")] pub fn sunday_weeks_in_year(year: DateYear) -> u8 { unsafe { ffi::g_date_get_sunday_weeks_in_year(year) } } #[doc(alias = "g_date_is_leap_year")] pub fn is_leap_year(year: DateYear) -> bool { unsafe { from_glib(ffi::g_date_is_leap_year(year)) } } #[doc(alias = "g_date_strftime")] pub fn strftime(s: &str, format: &str, date: &Date) -> usize { let slen = s.len() as usize; unsafe { ffi::g_date_strftime( s.to_glib_none().0, slen, format.to_glib_none().0, date.to_glib_none().0, ) } } #[doc(alias = "g_date_valid_day")] pub fn valid_day(day: DateDay) -> bool { unsafe { from_glib(ffi::g_date_valid_day(day)) } } #[doc(alias = "g_date_valid_dmy")] pub fn valid_dmy(day: DateDay, month: DateMonth, year: DateYear) -> bool { unsafe { from_glib(ffi::g_date_valid_dmy(day, month.into_glib(), year)) } } #[doc(alias = "g_date_valid_julian")] pub fn valid_julian(julian_date: u32) -> bool { unsafe { from_glib(ffi::g_date_valid_julian(julian_date)) } } #[doc(alias = "g_date_valid_month")] pub fn valid_month(month: DateMonth) -> bool { unsafe { from_glib(ffi::g_date_valid_month(month.into_glib())) } } #[doc(alias = "g_date_valid_weekday")] pub fn valid_weekday(weekday: DateWeekday) -> bool { unsafe { from_glib(ffi::g_date_valid_weekday(weekday.into_glib())) } } #[doc(alias = "g_date_valid_year")] pub fn valid_year(year: DateYear) -> bool { unsafe { from_glib(ffi::g_date_valid_year(year)) } } } impl PartialEq for Date { #[inline] fn eq(&self, other: &Self) -> bool { self.compare(other) == 0 } } impl Eq for Date {} impl PartialOrd for Date { #[inline] fn partial_cmp(&self, other: &Self) -> Option { self.compare(other).partial_cmp(&0) } } impl Ord for Date { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { self.compare(other).cmp(&0) } } impl fmt::Debug for Date { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Date") .field("year", &self.year()) .field("month", &self.month()) .field("day", &self.day()) .finish() } } impl hash::Hash for Date { fn hash(&self, state: &mut H) where H: hash::Hasher, { self.year().hash(state); self.month().hash(state); self.day().hash(state); } } glib-0.14.8/src/enums.rs000064400000000000000000000550070072674642500131560ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::*; use crate::value::Value; use crate::CStr; use crate::Type; use std::cmp; #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub enum UserDirectory { #[doc(alias = "G_USER_DIRECTORY_DESKTOP")] Desktop, #[doc(alias = "G_USER_DIRECTORY_DOCUMENTS")] Documents, #[doc(alias = "G_USER_DIRECTORY_DOWNLOAD")] Downloads, #[doc(alias = "G_USER_DIRECTORY_MUSIC")] Music, #[doc(alias = "G_USER_DIRECTORY_PICTURES")] Pictures, #[doc(alias = "G_USER_DIRECTORY_PUBLIC_SHARE")] PublicShare, #[doc(alias = "G_USER_DIRECTORY_TEMPLATES")] Templates, #[doc(alias = "G_USER_DIRECTORY_VIDEOS")] Videos, #[doc(hidden)] #[doc(alias = "G_USER_N_DIRECTORIES")] NDirectories, } #[doc(hidden)] impl IntoGlib for UserDirectory { type GlibType = ffi::GUserDirectory; fn into_glib(self) -> ffi::GUserDirectory { match self { Self::Desktop => ffi::G_USER_DIRECTORY_DESKTOP, Self::Documents => ffi::G_USER_DIRECTORY_DOCUMENTS, Self::Downloads => ffi::G_USER_DIRECTORY_DOWNLOAD, Self::Music => ffi::G_USER_DIRECTORY_MUSIC, Self::Pictures => ffi::G_USER_DIRECTORY_PICTURES, Self::PublicShare => ffi::G_USER_DIRECTORY_PUBLIC_SHARE, Self::Templates => ffi::G_USER_DIRECTORY_TEMPLATES, Self::Videos => ffi::G_USER_DIRECTORY_VIDEOS, Self::NDirectories => ffi::G_USER_N_DIRECTORIES, } } } /// Representation of an `enum` for dynamically, at runtime, querying the values of the enum and /// using them. #[derive(Debug)] #[doc(alias = "GEnumClass")] pub struct EnumClass(*mut gobject_ffi::GEnumClass); unsafe impl Send for EnumClass {} unsafe impl Sync for EnumClass {} impl EnumClass { /// Create a new `EnumClass` from a `Type`. /// /// Returns `None` if `type_` is not representing an enum. pub fn new(type_: Type) -> Option { unsafe { let is_enum: bool = from_glib(gobject_ffi::g_type_is_a( type_.into_glib(), gobject_ffi::G_TYPE_ENUM, )); if !is_enum { return None; } Some(EnumClass( gobject_ffi::g_type_class_ref(type_.into_glib()) as *mut _ )) } } /// `Type` of the enum. pub fn type_(&self) -> Type { unsafe { from_glib((*self.0).g_type_class.g_type) } } /// Gets `EnumValue` by integer `value`, if existing. /// /// Returns `None` if the enum does not contain any value /// with `value`. #[doc(alias = "g_enum_get_value")] #[doc(alias = "get_value")] pub fn value(&self, value: i32) -> Option { unsafe { let v = gobject_ffi::g_enum_get_value(self.0, value); if v.is_null() { None } else { Some(EnumValue(v, self.clone())) } } } /// Gets `EnumValue` by string name `name`, if existing. /// /// Returns `None` if the enum does not contain any value /// with name `name`. #[doc(alias = "g_enum_get_value_by_name")] #[doc(alias = "get_value_by_name")] pub fn value_by_name(&self, name: &str) -> Option { unsafe { let v = gobject_ffi::g_enum_get_value_by_name(self.0, name.to_glib_none().0); if v.is_null() { None } else { Some(EnumValue(v, self.clone())) } } } /// Gets `EnumValue` by string nick `nick`, if existing. /// /// Returns `None` if the enum does not contain any value /// with nick `nick`. #[doc(alias = "g_enum_get_value_by_nick")] #[doc(alias = "get_value_by_nick")] pub fn value_by_nick(&self, nick: &str) -> Option { unsafe { let v = gobject_ffi::g_enum_get_value_by_nick(self.0, nick.to_glib_none().0); if v.is_null() { None } else { Some(EnumValue(v, self.clone())) } } } /// Gets all `EnumValue` of this `EnumClass`. #[doc(alias = "get_values")] pub fn values(&self) -> Vec { unsafe { let n = (*self.0).n_values; let mut res = Vec::with_capacity(n as usize); for i in 0..(n as usize) { res.push(EnumValue((*self.0).values.add(i), self.clone())) } res } } /// Converts integer `value` to a `Value`, if part of the enum. pub fn to_value(&self, value: i32) -> Option { self.value(value).map(|v| v.to_value()) } /// Converts string name `name` to a `Value`, if part of the enum. pub fn to_value_by_name(&self, name: &str) -> Option { self.value_by_name(name).map(|v| v.to_value()) } /// Converts string nick `nick` to a `Value`, if part of the enum. pub fn to_value_by_nick(&self, nick: &str) -> Option { self.value_by_nick(nick).map(|v| v.to_value()) } } impl Drop for EnumClass { fn drop(&mut self) { unsafe { gobject_ffi::g_type_class_unref(self.0 as *mut _); } } } impl Clone for EnumClass { fn clone(&self) -> Self { unsafe { Self(gobject_ffi::g_type_class_ref(self.type_().into_glib()) as *mut _) } } } /// Representation of a single enum value of an `EnumClass`. #[derive(Debug, Clone)] #[doc(alias = "GEnumValue")] pub struct EnumValue(*const gobject_ffi::GEnumValue, EnumClass); unsafe impl Send for EnumValue {} unsafe impl Sync for EnumValue {} impl EnumValue { /// Get integer value corresponding to the value. #[doc(alias = "get_value")] pub fn value(&self) -> i32 { unsafe { (*self.0).value } } /// Get name corresponding to the value. #[doc(alias = "get_name")] pub fn name(&self) -> &str { unsafe { CStr::from_ptr((*self.0).value_name).to_str().unwrap() } } /// Get nick corresponding to the value. #[doc(alias = "get_nick")] pub fn nick(&self) -> &str { unsafe { CStr::from_ptr((*self.0).value_nick).to_str().unwrap() } } /// Convert enum value to a `Value`. pub fn to_value(&self) -> Value { unsafe { let mut v = Value::from_type(self.1.type_()); gobject_ffi::g_value_set_enum(v.to_glib_none_mut().0, (*self.0).value); v } } /// Convert enum value from a `Value`. pub fn from_value(value: &Value) -> Option { unsafe { let enum_class = EnumClass::new(value.type_()); enum_class.and_then(|e| e.value(gobject_ffi::g_value_get_enum(value.to_glib_none().0))) } } /// Get `EnumClass` to which the enum value belongs. #[doc(alias = "get_class")] pub fn class(&self) -> &EnumClass { &self.1 } } impl PartialEq for EnumValue { fn eq(&self, other: &Self) -> bool { self.value().eq(&other.value()) } } impl Eq for EnumValue {} impl PartialOrd for EnumValue { fn partial_cmp(&self, other: &Self) -> Option { self.value().partial_cmp(&other.value()) } } impl Ord for EnumValue { fn cmp(&self, other: &Self) -> cmp::Ordering { self.value().cmp(&other.value()) } } /// Representation of a `flags` for dynamically, at runtime, querying the values of the enum and /// using them #[derive(Debug)] #[doc(alias = "GFlagsClass")] pub struct FlagsClass(*mut gobject_ffi::GFlagsClass); unsafe impl Send for FlagsClass {} unsafe impl Sync for FlagsClass {} impl FlagsClass { /// Create a new `FlagsClass` from a `Type` /// /// Returns `None` if `type_` is not representing a flags type. pub fn new(type_: Type) -> Option { unsafe { let is_flags: bool = from_glib(gobject_ffi::g_type_is_a( type_.into_glib(), gobject_ffi::G_TYPE_FLAGS, )); if !is_flags { return None; } Some(FlagsClass( gobject_ffi::g_type_class_ref(type_.into_glib()) as *mut _ )) } } /// `Type` of the flags. pub fn type_(&self) -> Type { unsafe { from_glib((*self.0).g_type_class.g_type) } } /// Gets `FlagsValue` by integer `value`, if existing. /// /// Returns `None` if the flags do not contain any value /// with `value`. #[doc(alias = "g_flags_get_first_value")] #[doc(alias = "get_value")] pub fn value(&self, value: u32) -> Option { unsafe { let v = gobject_ffi::g_flags_get_first_value(self.0, value); if v.is_null() { None } else { Some(FlagsValue(v, self.clone())) } } } /// Gets `FlagsValue` by string name `name`, if existing. /// /// Returns `None` if the flags do not contain any value /// with name `name`. #[doc(alias = "g_flags_get_value_by_name")] #[doc(alias = "get_value_by_name")] pub fn value_by_name(&self, name: &str) -> Option { unsafe { let v = gobject_ffi::g_flags_get_value_by_name(self.0, name.to_glib_none().0); if v.is_null() { None } else { Some(FlagsValue(v, self.clone())) } } } /// Gets `FlagsValue` by string nick `nick`, if existing. /// /// Returns `None` if the flags do not contain any value /// with nick `nick`. #[doc(alias = "g_flags_get_value_by_nick")] #[doc(alias = "get_value_by_nick")] pub fn value_by_nick(&self, nick: &str) -> Option { unsafe { let v = gobject_ffi::g_flags_get_value_by_nick(self.0, nick.to_glib_none().0); if v.is_null() { None } else { Some(FlagsValue(v, self.clone())) } } } /// Gets all `FlagsValue` of this `FlagsClass`. #[doc(alias = "get_values")] pub fn values(&self) -> Vec { unsafe { let n = (*self.0).n_values; let mut res = Vec::with_capacity(n as usize); for i in 0..(n as usize) { res.push(FlagsValue((*self.0).values.add(i), self.clone())) } res } } /// Converts integer `value` to a `Value`, if part of the flags. pub fn to_value(&self, value: u32) -> Option { self.value(value).map(|v| v.to_value()) } /// Converts string name `name` to a `Value`, if part of the flags. pub fn to_value_by_name(&self, name: &str) -> Option { self.value_by_name(name).map(|v| v.to_value()) } /// Converts string nick `nick` to a `Value`, if part of the flags. pub fn to_value_by_nick(&self, nick: &str) -> Option { self.value_by_nick(nick).map(|v| v.to_value()) } /// Checks if the flags corresponding to integer `f` is set in `value`. pub fn is_set(&self, value: &Value, f: u32) -> bool { unsafe { if self.type_() != value.type_() { return false; } let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0); flags & f != 0 } } /// Checks if the flags corresponding to string name `name` is set in `value`. pub fn is_set_by_name(&self, value: &Value, name: &str) -> bool { unsafe { if self.type_() != value.type_() { return false; } if let Some(f) = self.value_by_name(name) { let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0); flags & f.value() != 0 } else { false } } } /// Checks if the flags corresponding to string nick `nick` is set in `value`. pub fn is_set_by_nick(&self, value: &Value, nick: &str) -> bool { unsafe { if self.type_() != value.type_() { return false; } if let Some(f) = self.value_by_nick(nick) { let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0); flags & f.value() != 0 } else { false } } } /// Set flags value corresponding to integer `f` in `value`, if part of that flags. If the /// flag is already set, it will succeed without doing any changes. /// /// Returns `Ok(value)` with the flag set if successful, or `Err(value)` with the original /// value otherwise. #[doc(alias = "g_value_set_flags")] pub fn set(&self, mut value: Value, f: u32) -> Result { unsafe { if self.type_() != value.type_() { return Err(value); } if let Some(f) = self.value(f) { let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0); gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags | f.value()); Ok(value) } else { Err(value) } } } /// Set flags value corresponding to string name `name` in `value`, if part of that flags. /// If the flag is already set, it will succeed without doing any changes. /// /// Returns `Ok(value)` with the flag set if successful, or `Err(value)` with the original /// value otherwise. pub fn set_by_name(&self, mut value: Value, name: &str) -> Result { unsafe { if self.type_() != value.type_() { return Err(value); } if let Some(f) = self.value_by_name(name) { let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0); gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags | f.value()); Ok(value) } else { Err(value) } } } /// Set flags value corresponding to string nick `nick` in `value`, if part of that flags. /// If the flag is already set, it will succeed without doing any changes. /// /// Returns `Ok(value)` with the flag set if successful, or `Err(value)` with the original /// value otherwise. pub fn set_by_nick(&self, mut value: Value, nick: &str) -> Result { unsafe { if self.type_() != value.type_() { return Err(value); } if let Some(f) = self.value_by_nick(nick) { let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0); gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags | f.value()); Ok(value) } else { Err(value) } } } /// Unset flags value corresponding to integer `f` in `value`, if part of that flags. /// If the flag is already unset, it will succeed without doing any changes. /// /// Returns `Ok(value)` with the flag unset if successful, or `Err(value)` with the original /// value otherwise. pub fn unset(&self, mut value: Value, f: u32) -> Result { unsafe { if self.type_() != value.type_() { return Err(value); } if let Some(f) = self.value(f) { let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0); gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags & !f.value()); Ok(value) } else { Err(value) } } } /// Unset flags value corresponding to string name `name` in `value`, if part of that flags. /// If the flag is already unset, it will succeed without doing any changes. /// /// Returns `Ok(value)` with the flag unset if successful, or `Err(value)` with the original /// value otherwise. pub fn unset_by_name(&self, mut value: Value, name: &str) -> Result { unsafe { if self.type_() != value.type_() { return Err(value); } if let Some(f) = self.value_by_name(name) { let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0); gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags & !f.value()); Ok(value) } else { Err(value) } } } /// Unset flags value corresponding to string nick `nick` in `value`, if part of that flags. /// If the flag is already unset, it will succeed without doing any changes. /// /// Returns `Ok(value)` with the flag unset if successful, or `Err(value)` with the original /// value otherwise. pub fn unset_by_nick(&self, mut value: Value, nick: &str) -> Result { unsafe { if self.type_() != value.type_() { return Err(value); } if let Some(f) = self.value_by_nick(nick) { let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0); gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags & !f.value()); Ok(value) } else { Err(value) } } } /// Returns a new `FlagsBuilder` for conveniently setting/unsetting flags /// and building a `Value`. pub fn builder(&self) -> FlagsBuilder { FlagsBuilder::new(self) } /// Returns a new `FlagsBuilder` for conveniently setting/unsetting flags /// and building a `Value`. The `Value` is initialized with `value`. pub fn builder_with_value(&self, value: Value) -> Option { if self.type_() != value.type_() { return None; } Some(FlagsBuilder::with_value(self, value)) } } impl Drop for FlagsClass { fn drop(&mut self) { unsafe { gobject_ffi::g_type_class_unref(self.0 as *mut _); } } } impl Clone for FlagsClass { fn clone(&self) -> Self { unsafe { Self(gobject_ffi::g_type_class_ref(self.type_().into_glib()) as *mut _) } } } /// Representation of a single flags value of a `FlagsClass`. #[derive(Debug, Clone)] #[doc(alias = "GFlagsValue")] pub struct FlagsValue(*const gobject_ffi::GFlagsValue, FlagsClass); unsafe impl Send for FlagsValue {} unsafe impl Sync for FlagsValue {} impl FlagsValue { /// Get integer value corresponding to the value. #[doc(alias = "get_value")] pub fn value(&self) -> u32 { unsafe { (*self.0).value } } /// Get name corresponding to the value. #[doc(alias = "get_name")] pub fn name(&self) -> &str { unsafe { CStr::from_ptr((*self.0).value_name).to_str().unwrap() } } /// Get nick corresponding to the value. #[doc(alias = "get_nick")] pub fn nick(&self) -> &str { unsafe { CStr::from_ptr((*self.0).value_nick).to_str().unwrap() } } /// Convert flags value to a `Value`. pub fn to_value(&self) -> Value { unsafe { let mut v = Value::from_type(self.1.type_()); gobject_ffi::g_value_set_flags(v.to_glib_none_mut().0, (*self.0).value); v } } /// Convert flags values from a `Value`. This returns all flags that are set. pub fn from_value(value: &Value) -> Vec { unsafe { let flags_class = FlagsClass::new(value.type_()); let mut res = Vec::new(); if let Some(flags_class) = flags_class { let f = gobject_ffi::g_value_get_flags(value.to_glib_none().0); for v in flags_class.values() { if v.value() & f != 0 { res.push(v); } } } res } } /// Get `FlagsClass` to which the flags value belongs. #[doc(alias = "get_class")] pub fn class(&self) -> &FlagsClass { &self.1 } } impl PartialEq for FlagsValue { fn eq(&self, other: &Self) -> bool { self.value().eq(&other.value()) } } impl Eq for FlagsValue {} /// Builder for conveniently setting/unsetting flags and returning a `Value`. /// /// Example for getting a flags property, unsetting some flags and setting the updated flags on the /// object again: /// /// ```ignore /// let flags = obj.property("flags").unwrap(); /// let flags_class = FlagsClass::new(flags.type_()).unwrap(); /// let flags = flags_class.builder_with_value(flags).unwrap() /// .unset_by_nick("some-flag") /// .unset_by_nick("some-other-flag") /// .build() /// .unwrap(); /// obj.set_property("flags", &flags).unwrap(); /// ``` /// /// If setting/unsetting any value fails, `build()` returns `None`. pub struct FlagsBuilder<'a>(&'a FlagsClass, Option); impl<'a> FlagsBuilder<'a> { fn new(flags_class: &FlagsClass) -> FlagsBuilder { let value = Value::from_type(flags_class.type_()); FlagsBuilder(flags_class, Some(value)) } fn with_value(flags_class: &FlagsClass, value: Value) -> FlagsBuilder { FlagsBuilder(flags_class, Some(value)) } /// Set flags corresponding to integer value `f`. pub fn set(mut self, f: u32) -> Self { if let Some(value) = self.1.take() { self.1 = self.0.set(value, f).ok(); } self } /// Set flags corresponding to string name `name`. pub fn set_by_name(mut self, name: &str) -> Self { if let Some(value) = self.1.take() { self.1 = self.0.set_by_name(value, name).ok(); } self } /// Set flags corresponding to string nick `nick`. pub fn set_by_nick(mut self, nick: &str) -> Self { if let Some(value) = self.1.take() { self.1 = self.0.set_by_nick(value, nick).ok(); } self } /// Unsets flags corresponding to integer value `f`. pub fn unset(mut self, f: u32) -> Self { if let Some(value) = self.1.take() { self.1 = self.0.unset(value, f).ok(); } self } /// Unset flags corresponding to string name `name`. pub fn unset_by_name(mut self, name: &str) -> Self { if let Some(value) = self.1.take() { self.1 = self.0.unset_by_name(value, name).ok(); } self } /// Unset flags corresponding to string nick `nick`. pub fn unset_by_nick(mut self, nick: &str) -> Self { if let Some(value) = self.1.take() { self.1 = self.0.unset_by_nick(value, nick).ok(); } self } /// Converts to the final `Value`, unless any previous setting/unsetting of flags failed. pub fn build(self) -> Option { self.1 } } glib-0.14.8/src/error.rs000064400000000000000000000160450072674642500131570ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! `Error` binding and helper trait. use crate::translate::*; use crate::Quark; use std::borrow::Cow; use std::error; use std::ffi::CStr; use std::fmt; use std::mem; use std::str; wrapper! { /// A generic error capable of representing various error domains (types). #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GError")] pub struct Error(Boxed); match fn { copy => |ptr| ffi::g_error_copy(ptr), free => |ptr| ffi::g_error_free(ptr), type_ => || ffi::g_error_get_type(), } } unsafe impl Send for Error {} unsafe impl Sync for Error {} impl Error { /// Creates an error with supplied error enum variant and message. #[doc(alias = "g_error_new_literal")] pub fn new(error: T, message: &str) -> Error { unsafe { from_glib_full(ffi::g_error_new_literal( T::domain().into_glib(), error.code(), message.to_glib_none().0, )) } } /// Checks if the error domain matches `T`. pub fn is(&self) -> bool { self.0.domain == T::domain().into_glib() } /// Tries to convert to a specific error enum. /// /// Returns `Some` if the error belongs to the enum's error domain and /// `None` otherwise. /// /// # Examples /// /// ```ignore /// if let Some(file_error) = error.kind::() { /// match file_error { /// FileError::Exist => ... /// FileError::Isdir => ... /// ... /// } /// } /// ``` pub fn kind(&self) -> Option { if self.is::() { T::from(self.0.code) } else { None } } fn message(&self) -> &str { unsafe { let bytes = CStr::from_ptr(self.0.message).to_bytes(); str::from_utf8(bytes) .unwrap_or_else(|err| str::from_utf8(&bytes[..err.valid_up_to()]).unwrap()) } } /// Consumes the `Error` and returns the corresponding `GError` pointer. pub fn into_raw(self) -> *mut ffi::GError { let mut e = mem::ManuallyDrop::new(self); e.to_glib_none_mut().0 } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.message()) } } impl fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Error") .field("domain", unsafe { &crate::Quark::from_glib(self.0.domain) }) .field("code", &self.0.code) .field("message", &self.message()) .finish() } } impl error::Error for Error {} /// `GLib` error domain. /// /// This trait is implemented by error enums that represent error domains (types). pub trait ErrorDomain: Copy { /// Returns the quark identifying the error domain. /// /// As returned from `g_some_error_quark`. fn domain() -> Quark; /// Gets the integer representation of the variant. fn code(self) -> i32; /// Tries to convert an integer code to an enum variant. /// /// By convention, the `Failed` variant, if present, is a catch-all, /// i.e. any unrecognized codes map to it. fn from(code: i32) -> Option where Self: Sized; } /// Generic error used for functions that fail without any further information #[macro_export] macro_rules! bool_error( // Plain strings ($msg:expr) => { $crate::BoolError::new($msg, file!(), module_path!(), line!()) }; // Format strings ($($msg:tt)*) => { { $crate::BoolError::new(format!($($msg)*), file!(), module_path!(), line!()) }}; ); #[macro_export] macro_rules! result_from_gboolean( // Plain strings ($ffi_bool:expr, $msg:expr) => { $crate::BoolError::from_glib($ffi_bool, $msg, file!(), module_path!(), line!()) }; // Format strings ($ffi_bool:expr, $($msg:tt)*) => { { $crate::BoolError::from_glib( $ffi_bool, format!($($msg)*), file!(), module_path!(), line!(), ) }}; ); #[derive(Debug, Clone)] pub struct BoolError { pub message: Cow<'static, str>, #[doc(hidden)] pub filename: &'static str, #[doc(hidden)] pub function: &'static str, #[doc(hidden)] pub line: u32, } impl BoolError { pub fn new>>( message: Msg, filename: &'static str, function: &'static str, line: u32, ) -> Self { Self { message: message.into(), filename, function, line, } } pub fn from_glib>>( b: ffi::gboolean, message: Msg, filename: &'static str, function: &'static str, line: u32, ) -> Result<(), Self> { match b { ffi::GFALSE => Err(BoolError::new(message, filename, function, line)), _ => Ok(()), } } } impl fmt::Display for BoolError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(&self.message) } } impl error::Error for BoolError {} #[cfg(test)] mod tests { use super::*; use std::ffi::CString; #[test] fn test_error_kind() { let e = Error::new(crate::FileError::Failed, "Failed"); assert_eq!(e.kind::(), Some(crate::FileError::Failed)); assert_eq!(e.kind::(), None); } #[test] fn test_into_raw() { let e = Error::new(crate::FileError::Failed, "Failed").into_raw(); unsafe { assert_eq!((*e).domain, ffi::g_file_error_quark()); assert_eq!((*e).code, ffi::G_FILE_ERROR_FAILED); assert_eq!( CStr::from_ptr((*e).message), CString::new("Failed").unwrap().as_c_str() ); ffi::g_error_free(e); } } #[test] fn test_bool_error() { let from_static_msg = bool_error!("Static message"); assert_eq!(from_static_msg.to_string(), "Static message"); let from_dynamic_msg = bool_error!("{} message", "Dynamic"); assert_eq!(from_dynamic_msg.to_string(), "Dynamic message"); let false_static_res = result_from_gboolean!(ffi::GFALSE, "Static message"); assert!(false_static_res.is_err()); let static_err = false_static_res.err().unwrap(); assert_eq!(static_err.to_string(), "Static message"); let true_static_res = result_from_gboolean!(ffi::GTRUE, "Static message"); assert!(true_static_res.is_ok()); let false_dynamic_res = result_from_gboolean!(ffi::GFALSE, "{} message", "Dynamic"); assert!(false_dynamic_res.is_err()); let dynamic_err = false_dynamic_res.err().unwrap(); assert_eq!(dynamic_err.to_string(), "Dynamic message"); let true_dynamic_res = result_from_gboolean!(ffi::GTRUE, "{} message", "Dynamic"); assert!(true_dynamic_res.is_ok()); } } glib-0.14.8/src/file_error.rs000064400000000000000000000075670072674642500141670ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::error::ErrorDomain; use crate::translate::from_glib; use crate::Quark; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum FileError { Exist, Isdir, Acces, Nametoolong, Noent, Notdir, Nxio, Nodev, Rofs, Txtbsy, Fault, Loop, Nospc, Nomem, Mfile, Nfile, Badf, Inval, Pipe, Again, Intr, Io, Perm, Nosys, Failed, } impl ErrorDomain for FileError { fn domain() -> Quark { unsafe { from_glib(ffi::g_file_error_quark()) } } fn code(self) -> i32 { use self::FileError::*; match self { Exist => ffi::G_FILE_ERROR_EXIST as i32, Isdir => ffi::G_FILE_ERROR_ISDIR as i32, Acces => ffi::G_FILE_ERROR_ACCES as i32, Nametoolong => ffi::G_FILE_ERROR_NAMETOOLONG as i32, Noent => ffi::G_FILE_ERROR_NOENT as i32, Notdir => ffi::G_FILE_ERROR_NOTDIR as i32, Nxio => ffi::G_FILE_ERROR_NXIO as i32, Nodev => ffi::G_FILE_ERROR_NODEV as i32, Rofs => ffi::G_FILE_ERROR_ROFS as i32, Txtbsy => ffi::G_FILE_ERROR_TXTBSY as i32, Fault => ffi::G_FILE_ERROR_FAULT as i32, Loop => ffi::G_FILE_ERROR_LOOP as i32, Nospc => ffi::G_FILE_ERROR_NOSPC as i32, Nomem => ffi::G_FILE_ERROR_NOMEM as i32, Mfile => ffi::G_FILE_ERROR_MFILE as i32, Nfile => ffi::G_FILE_ERROR_NFILE as i32, Badf => ffi::G_FILE_ERROR_BADF as i32, Inval => ffi::G_FILE_ERROR_INVAL as i32, Pipe => ffi::G_FILE_ERROR_PIPE as i32, Again => ffi::G_FILE_ERROR_AGAIN as i32, Intr => ffi::G_FILE_ERROR_INTR as i32, Io => ffi::G_FILE_ERROR_IO as i32, Perm => ffi::G_FILE_ERROR_PERM as i32, Nosys => ffi::G_FILE_ERROR_NOSYS as i32, Failed => ffi::G_FILE_ERROR_FAILED as i32, } } #[allow(clippy::cognitive_complexity)] fn from(code: i32) -> Option { use self::FileError::*; match code { x if x == ffi::G_FILE_ERROR_EXIST as i32 => Some(Exist), x if x == ffi::G_FILE_ERROR_ISDIR as i32 => Some(Isdir), x if x == ffi::G_FILE_ERROR_ACCES as i32 => Some(Acces), x if x == ffi::G_FILE_ERROR_NAMETOOLONG as i32 => Some(Nametoolong), x if x == ffi::G_FILE_ERROR_NOENT as i32 => Some(Noent), x if x == ffi::G_FILE_ERROR_NOTDIR as i32 => Some(Notdir), x if x == ffi::G_FILE_ERROR_NXIO as i32 => Some(Nxio), x if x == ffi::G_FILE_ERROR_NODEV as i32 => Some(Nodev), x if x == ffi::G_FILE_ERROR_ROFS as i32 => Some(Rofs), x if x == ffi::G_FILE_ERROR_TXTBSY as i32 => Some(Txtbsy), x if x == ffi::G_FILE_ERROR_FAULT as i32 => Some(Fault), x if x == ffi::G_FILE_ERROR_LOOP as i32 => Some(Loop), x if x == ffi::G_FILE_ERROR_NOSPC as i32 => Some(Nospc), x if x == ffi::G_FILE_ERROR_NOMEM as i32 => Some(Nomem), x if x == ffi::G_FILE_ERROR_MFILE as i32 => Some(Mfile), x if x == ffi::G_FILE_ERROR_NFILE as i32 => Some(Nfile), x if x == ffi::G_FILE_ERROR_BADF as i32 => Some(Badf), x if x == ffi::G_FILE_ERROR_INVAL as i32 => Some(Inval), x if x == ffi::G_FILE_ERROR_PIPE as i32 => Some(Pipe), x if x == ffi::G_FILE_ERROR_AGAIN as i32 => Some(Again), x if x == ffi::G_FILE_ERROR_INTR as i32 => Some(Intr), x if x == ffi::G_FILE_ERROR_IO as i32 => Some(Io), x if x == ffi::G_FILE_ERROR_PERM as i32 => Some(Perm), x if x == ffi::G_FILE_ERROR_NOSYS as i32 => Some(Nosys), x if x == ffi::G_FILE_ERROR_FAILED as i32 => Some(Failed), _ => Some(Failed), } } } glib-0.14.8/src/functions.rs000064400000000000000000000204120072674642500140270ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #[cfg(not(windows))] use std::boxed::Box as Box_; #[cfg(not(windows))] use std::mem; #[cfg(not(windows))] #[cfg(any(feature = "v2_58", feature = "dox"))] use std::os::unix::io::AsRawFd; #[cfg(not(windows))] use std::os::unix::io::{FromRawFd, RawFd}; // #[cfg(windows)] // #[cfg(any(feature = "v2_58", feature = "dox"))] // use std::os::windows::io::AsRawHandle; use crate::translate::*; #[cfg(not(windows))] use crate::Error; use crate::GString; #[cfg(not(windows))] use crate::Pid; #[cfg(not(windows))] use crate::SpawnFlags; use std::ptr; #[cfg(any(feature = "v2_58", feature = "dox"))] #[cfg(not(windows))] #[cfg_attr(feature = "dox", doc(cfg(all(feature = "v2_58", not(windows)))))] #[allow(clippy::too_many_arguments)] #[doc(alias = "g_spawn_async_with_fds")] pub fn spawn_async_with_fds, T: AsRawFd, U: AsRawFd, V: AsRawFd>( working_directory: P, argv: &[&str], envp: &[&str], flags: SpawnFlags, child_setup: Option>, stdin_fd: T, stdout_fd: U, stderr_fd: V, ) -> Result { let child_setup_data: Box_>> = Box_::new(child_setup); unsafe extern "C" fn child_setup_func>(user_data: ffi::gpointer) { let callback: Box_>> = Box_::from_raw(user_data as *mut _); let callback = (*callback).expect("cannot get closure..."); callback() } let child_setup = if child_setup_data.is_some() { Some(child_setup_func::

as _) } else { None }; let super_callback0: Box_>> = child_setup_data; unsafe { let mut child_pid = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let _ = ffi::g_spawn_async_with_fds( working_directory.as_ref().to_glib_none().0, argv.to_glib_none().0, envp.to_glib_none().0, flags.into_glib(), child_setup, Box_::into_raw(super_callback0) as *mut _, child_pid.as_mut_ptr(), stdin_fd.as_raw_fd(), stdout_fd.as_raw_fd(), stderr_fd.as_raw_fd(), &mut error, ); let child_pid = from_glib(child_pid.assume_init()); if error.is_null() { Ok(child_pid) } else { Err(from_glib_full(error)) } } } // #[cfg(any(feature = "v2_58", feature = "dox"))] // #[cfg(windows)] // pub fn spawn_async_with_fds< // P: AsRef, // T: AsRawHandle, // U: AsRawHandle, // V: AsRawHandle, // >( // working_directory: P, // argv: &[&str], // envp: &[&str], // flags: SpawnFlags, // child_setup: Option>, // stdin_fd: T, // stdout_fd: U, // stderr_fd: V, // ) -> Result { // let child_setup_data: Box_>> = Box_::new(child_setup); // unsafe extern "C" fn child_setup_func>( // user_data: ffi::gpointer, // ) { // let callback: Box_>> = // Box_::from_raw(user_data as *mut _); // let callback = (*callback).expect("cannot get closure..."); // callback() // } // let child_setup = if child_setup_data.is_some() { // Some(child_setup_func::

as _) // } else { // None // }; // let super_callback0: Box_>> = child_setup_data; // unsafe { // let mut child_pid = mem::MaybeUninit::uninit(); // let mut error = ptr::null_mut(); // let _ = ffi::g_spawn_async_with_fds( // working_directory.as_ref().to_glib_none().0, // argv.to_glib_none().0, // envp.to_glib_none().0, // flags.into_glib(), // child_setup, // Box_::into_raw(super_callback0) as *mut _, // child_pid.as_mut_ptr(), // stdin_fd.as_raw_handle() as usize as _, // stdout_fd.as_raw_handle() as usize as _, // stderr_fd.as_raw_handle() as usize as _, // &mut error, // ); // let child_pid = from_glib(child_pid.assume_init()); // if error.is_null() { // Ok(child_pid) // } else { // Err(from_glib_full(error)) // } // } // } #[cfg(not(windows))] #[cfg_attr(feature = "dox", doc(cfg(not(windows))))] #[doc(alias = "g_spawn_async_with_pipes")] pub fn spawn_async_with_pipes< P: AsRef, T: FromRawFd, U: FromRawFd, V: FromRawFd, >( working_directory: P, argv: &[&std::path::Path], envp: &[&std::path::Path], flags: SpawnFlags, child_setup: Option>, ) -> Result<(Pid, T, U, V), Error> { let child_setup_data: Box_>> = Box_::new(child_setup); unsafe extern "C" fn child_setup_func>(user_data: ffi::gpointer) { let callback: Box_>> = Box_::from_raw(user_data as *mut _); let callback = (*callback).expect("cannot get closure..."); callback() } let child_setup = if child_setup_data.is_some() { Some(child_setup_func::

as _) } else { None }; let super_callback0: Box_>> = child_setup_data; unsafe { let mut child_pid = mem::MaybeUninit::uninit(); let mut standard_input = mem::MaybeUninit::uninit(); let mut standard_output = mem::MaybeUninit::uninit(); let mut standard_error = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let _ = ffi::g_spawn_async_with_pipes( working_directory.as_ref().to_glib_none().0, argv.to_glib_none().0, envp.to_glib_none().0, flags.into_glib(), child_setup, Box_::into_raw(super_callback0) as *mut _, child_pid.as_mut_ptr(), standard_input.as_mut_ptr(), standard_output.as_mut_ptr(), standard_error.as_mut_ptr(), &mut error, ); let child_pid = from_glib(child_pid.assume_init()); let standard_input = standard_input.assume_init(); let standard_output = standard_output.assume_init(); let standard_error = standard_error.assume_init(); if error.is_null() { #[cfg(not(windows))] { Ok(( child_pid, FromRawFd::from_raw_fd(standard_input), FromRawFd::from_raw_fd(standard_output), FromRawFd::from_raw_fd(standard_error), )) } // #[cfg(windows)] // { // use std::os::windows::io::{FromRawHandle, RawHandle}; // Ok(( // child_pid, // File::from_raw_handle(standard_input as usize as RawHandle), // File::from_raw_handle(standard_output as usize as RawHandle), // File::from_raw_handle(standard_error as usize as RawHandle), // )) // } } else { Err(from_glib_full(error)) } } } /// Obtain the character set for the current locale. /// /// This returns whether the locale's encoding is UTF-8, and the current /// charset if available. #[doc(alias = "g_get_charset")] #[doc(alias = "get_charset")] pub fn charset() -> (bool, Option) { unsafe { let mut out_charset = ptr::null(); let is_utf8 = from_glib(ffi::g_get_charset(&mut out_charset)); let charset = from_glib_none(out_charset); (is_utf8, charset) } } #[cfg(unix)] #[doc(alias = "g_unix_open_pipe")] pub fn unix_open_pipe(flags: i32) -> Result<(RawFd, RawFd), Error> { unsafe { let mut fds = [0, 2]; let mut error = ptr::null_mut(); let _ = ffi::g_unix_open_pipe(fds.as_mut_ptr(), flags, &mut error); if error.is_null() { Ok(( FromRawFd::from_raw_fd(fds[0]), FromRawFd::from_raw_fd(fds[1]), )) } else { Err(from_glib_full(error)) } } } glib-0.14.8/src/gobject/auto/binding.rs000064400000000000000000000030640072674642500160220ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::translate::*; use crate::BindingFlags; use std::fmt; crate::wrapper! { #[doc(alias = "GBinding")] pub struct Binding(Object); match fn { type_ => || gobject_ffi::g_binding_get_type(), } } impl Binding { #[doc(alias = "g_binding_get_flags")] #[doc(alias = "get_flags")] pub fn flags(&self) -> BindingFlags { unsafe { from_glib(gobject_ffi::g_binding_get_flags(self.to_glib_none().0)) } } #[doc(alias = "g_binding_get_source_property")] #[doc(alias = "get_source_property")] pub fn source_property(&self) -> crate::GString { unsafe { from_glib_none(gobject_ffi::g_binding_get_source_property( self.to_glib_none().0, )) } } #[doc(alias = "g_binding_get_target_property")] #[doc(alias = "get_target_property")] pub fn target_property(&self) -> crate::GString { unsafe { from_glib_none(gobject_ffi::g_binding_get_target_property( self.to_glib_none().0, )) } } #[doc(alias = "g_binding_unbind")] pub fn unbind(&self) { unsafe { gobject_ffi::g_binding_unbind(self.to_glib_none().0); } } } unsafe impl Send for Binding {} unsafe impl Sync for Binding {} impl fmt::Display for Binding { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("Binding") } } glib-0.14.8/src/gobject/auto/flags.rs000064400000000000000000000074310072674642500155060ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::translate::*; use crate::value::FromValue; use crate::value::ToValue; use crate::StaticType; use crate::Type; use bitflags::bitflags; use std::fmt; bitflags! { #[doc(alias = "GBindingFlags")] pub struct BindingFlags: u32 { #[doc(alias = "G_BINDING_DEFAULT")] const DEFAULT = gobject_ffi::G_BINDING_DEFAULT as u32; #[doc(alias = "G_BINDING_BIDIRECTIONAL")] const BIDIRECTIONAL = gobject_ffi::G_BINDING_BIDIRECTIONAL as u32; #[doc(alias = "G_BINDING_SYNC_CREATE")] const SYNC_CREATE = gobject_ffi::G_BINDING_SYNC_CREATE as u32; #[doc(alias = "G_BINDING_INVERT_BOOLEAN")] const INVERT_BOOLEAN = gobject_ffi::G_BINDING_INVERT_BOOLEAN as u32; } } impl fmt::Display for BindingFlags { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, f) } } #[doc(hidden)] impl IntoGlib for BindingFlags { type GlibType = gobject_ffi::GBindingFlags; fn into_glib(self) -> gobject_ffi::GBindingFlags { self.bits() } } #[doc(hidden)] impl FromGlib for BindingFlags { unsafe fn from_glib(value: gobject_ffi::GBindingFlags) -> Self { Self::from_bits_truncate(value) } } impl StaticType for BindingFlags { fn static_type() -> Type { unsafe { from_glib(gobject_ffi::g_binding_flags_get_type()) } } } impl crate::value::ValueType for BindingFlags { type Type = Self; } unsafe impl<'a> FromValue<'a> for BindingFlags { type Checker = crate::value::GenericValueTypeChecker; unsafe fn from_value(value: &'a crate::Value) -> Self { from_glib(crate::gobject_ffi::g_value_get_flags( value.to_glib_none().0, )) } } impl ToValue for BindingFlags { fn to_value(&self) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { crate::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } fn value_type(&self) -> crate::Type { Self::static_type() } } bitflags! { #[doc(alias = "GSignalFlags")] pub struct SignalFlags: u32 { #[doc(alias = "G_SIGNAL_RUN_FIRST")] const RUN_FIRST = gobject_ffi::G_SIGNAL_RUN_FIRST as u32; #[doc(alias = "G_SIGNAL_RUN_LAST")] const RUN_LAST = gobject_ffi::G_SIGNAL_RUN_LAST as u32; #[doc(alias = "G_SIGNAL_RUN_CLEANUP")] const RUN_CLEANUP = gobject_ffi::G_SIGNAL_RUN_CLEANUP as u32; #[doc(alias = "G_SIGNAL_NO_RECURSE")] const NO_RECURSE = gobject_ffi::G_SIGNAL_NO_RECURSE as u32; #[doc(alias = "G_SIGNAL_DETAILED")] const DETAILED = gobject_ffi::G_SIGNAL_DETAILED as u32; #[doc(alias = "G_SIGNAL_ACTION")] const ACTION = gobject_ffi::G_SIGNAL_ACTION as u32; #[doc(alias = "G_SIGNAL_NO_HOOKS")] const NO_HOOKS = gobject_ffi::G_SIGNAL_NO_HOOKS as u32; #[doc(alias = "G_SIGNAL_MUST_COLLECT")] const MUST_COLLECT = gobject_ffi::G_SIGNAL_MUST_COLLECT as u32; #[doc(alias = "G_SIGNAL_DEPRECATED")] const DEPRECATED = gobject_ffi::G_SIGNAL_DEPRECATED as u32; } } impl fmt::Display for SignalFlags { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, f) } } #[doc(hidden)] impl IntoGlib for SignalFlags { type GlibType = gobject_ffi::GSignalFlags; fn into_glib(self) -> gobject_ffi::GSignalFlags { self.bits() } } #[doc(hidden)] impl FromGlib for SignalFlags { unsafe fn from_glib(value: gobject_ffi::GSignalFlags) -> Self { Self::from_bits_truncate(value) } } glib-0.14.8/src/gobject/auto/mod.rs000064400000000000000000000004520072674642500151650ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT mod binding; pub use self::binding::Binding; mod flags; pub use self::flags::BindingFlags; pub use self::flags::SignalFlags; #[doc(hidden)] pub mod traits {} glib-0.14.8/src/gobject/binding.rs000064400000000000000000000024220072674642500150470ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::*; use crate::Binding; use crate::Object; use crate::ObjectType; use crate::StaticType; impl Binding { #[doc(alias = "get_source")] pub fn source(&self) -> Option { unsafe { let mut value = crate::Value::from_type(::static_type()); crate::gobject_ffi::g_object_get_property( self.as_ptr() as *mut crate::gobject_ffi::GObject, b"source\0".as_ptr() as *const _, value.to_glib_none_mut().0, ); value .get() .expect("Return Value for property `source` getter") } } #[doc(alias = "get_target")] pub fn target(&self) -> Option { unsafe { let mut value = crate::Value::from_type(::static_type()); crate::gobject_ffi::g_object_get_property( self.as_ptr() as *mut crate::gobject_ffi::GObject, b"target\0".as_ptr() as *const _, value.to_glib_none_mut().0, ); value .get() .expect("Return Value for property `target` getter") } } } glib-0.14.8/src/gobject/flags.rs000064400000000000000000000032660072674642500145400ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::*; bitflags::bitflags! { #[doc(alias = "GParamFlags")] pub struct ParamFlags: u32 { #[doc(alias = "G_PARAM_READABLE")] const READABLE = gobject_ffi::G_PARAM_READABLE as u32; #[doc(alias = "G_PARAM_WRITABLE")] const WRITABLE = gobject_ffi::G_PARAM_WRITABLE as u32; #[doc(alias = "G_PARAM_READWRITE")] const READWRITE = gobject_ffi::G_PARAM_READWRITE as u32; #[doc(alias = "G_PARAM_CONSTRUCT")] const CONSTRUCT = gobject_ffi::G_PARAM_CONSTRUCT as u32; #[doc(alias = "G_PARAM_CONSTRUCT_ONLY")] const CONSTRUCT_ONLY = gobject_ffi::G_PARAM_CONSTRUCT_ONLY as u32; #[doc(alias = "G_PARAM_LAX_VALIDATION")] const LAX_VALIDATION = gobject_ffi::G_PARAM_LAX_VALIDATION as u32; const USER_1 = 256; const USER_2 = 1024; const USER_3 = 2048; const USER_4 = 4096; const USER_5 = 8192; const USER_6 = 16384; const USER_7 = 32768; const USER_8 = 65536; #[doc(alias = "G_PARAM_EXPLICIT_NOTIFY")] const EXPLICIT_NOTIFY = gobject_ffi::G_PARAM_EXPLICIT_NOTIFY as u32; #[doc(alias = "G_PARAM_DEPRECATED")] const DEPRECATED = gobject_ffi::G_PARAM_DEPRECATED as u32; } } #[doc(hidden)] impl IntoGlib for ParamFlags { type GlibType = gobject_ffi::GParamFlags; fn into_glib(self) -> gobject_ffi::GParamFlags { self.bits() } } #[doc(hidden)] impl FromGlib for ParamFlags { unsafe fn from_glib(value: gobject_ffi::GParamFlags) -> Self { Self::from_bits_truncate(value) } } glib-0.14.8/src/gobject/mod.rs000064400000000000000000000003350072674642500142150ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! GObject bindings mod auto; mod binding; mod flags; pub use self::auto::*; pub use self::flags::*; //pub use self::auto::functions::*; glib-0.14.8/src/gstring.rs000064400000000000000000000426450072674642500135100ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::*; use crate::types::{StaticType, Type}; use std::borrow::Borrow; use std::cmp::Ordering; use std::ffi::{CStr, CString, OsStr}; use std::fmt; use std::hash; use std::ops::Deref; use std::os::raw::{c_char, c_void}; use std::ptr; use std::slice; use std::string::String; pub struct GString(Inner); enum Inner { Native(Option), Foreign(ptr::NonNull, usize), } unsafe impl Send for GString {} unsafe impl Sync for GString {} impl GString { /// Create a new GString from a glib-originated string, taking ownership. /// /// # Safety /// /// The provided string must be a valid C string (i.e. `'0'` terminated). /// /// The provided pointer must be allocated by glib such that `g_free(ptr)` /// is valid, as the `GString` will call `g_free(ptr)` on drop. /// /// It is essential that noone else free this pointer as it owned by the /// returned `GString`. /// /// The underlying string must not be mutated, in particular in terms of /// length, underneath the `GString` instance. unsafe fn new(ptr: *mut c_char) -> Self { assert!(!ptr.is_null()); Self(Inner::Foreign( ptr::NonNull::new_unchecked(ptr), libc::strlen(ptr), )) } /// Create a new GString from a glib-originated string, borrowing it rather /// than taking ownership. /// /// # Safety /// /// The provided string must be a valid C string (i.e. `'0'` terminated). /// /// It is essential that noone else free this pointer as it owned by the /// returned `GString` until the borrow is dropped. /// /// The underlying string must not be mutated, in particular in terms of /// length, underneath the `GString` instance for the duration of the borrow. unsafe fn new_borrowed(ptr: *const c_char) -> Borrowed { assert!(!ptr.is_null()); Borrowed::new(GString(Inner::Foreign( ptr::NonNull::new_unchecked(ptr as *mut _), libc::strlen(ptr), ))) } pub fn as_str(&self) -> &str { let cstr = match self { GString(Inner::Foreign(ptr, length)) => unsafe { let bytes = slice::from_raw_parts(ptr.as_ptr() as *const u8, length + 1); CStr::from_bytes_with_nul_unchecked(bytes) }, GString(Inner::Native(cstring)) => cstring .as_ref() .expect("Native shouldn't be empty") .as_c_str(), }; cstr.to_str().unwrap() } } impl Clone for GString { fn clone(&self) -> GString { let cstring = CString::new(self.as_str().to_string()).expect("CString::new failed"); GString(Inner::Native(Some(cstring))) } } impl fmt::Debug for GString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { <&str as fmt::Debug>::fmt(&self.as_str(), f) } } impl Drop for GString { fn drop(&mut self) { if let GString(Inner::Foreign(ptr, _len)) = self { unsafe { ffi::g_free(ptr.as_ptr() as *mut _); } } } } impl fmt::Display for GString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.as_str()) } } impl hash::Hash for GString { fn hash(&self, state: &mut H) { let bytes = match self { GString(Inner::Foreign(ptr, length)) => unsafe { slice::from_raw_parts(ptr.as_ptr() as *const u8, length + 1) }, GString(Inner::Native(cstring)) => cstring .as_ref() .expect("Native shouldn't be empty") .as_bytes(), }; state.write(bytes); } } impl Borrow for GString { fn borrow(&self) -> &str { self.as_str() } } impl Ord for GString { fn cmp(&self, other: &GString) -> Ordering { self.as_str().cmp(other.as_str()) } } impl PartialOrd for GString { fn partial_cmp(&self, other: &GString) -> Option { Some(self.cmp(other)) } } impl PartialEq for GString { fn eq(&self, other: &GString) -> bool { self.as_str() == other.as_str() } } impl PartialEq for String { fn eq(&self, other: &GString) -> bool { self.as_str() == other.as_str() } } impl PartialEq for GString { fn eq(&self, other: &str) -> bool { self.as_str() == other } } impl<'a> PartialEq<&'a str> for GString { fn eq(&self, other: &&'a str) -> bool { self.as_str() == *other } } impl<'a> PartialEq for &'a str { fn eq(&self, other: &GString) -> bool { *self == other.as_str() } } impl PartialEq for GString { fn eq(&self, other: &String) -> bool { self.as_str() == other.as_str() } } impl PartialEq for str { fn eq(&self, other: &GString) -> bool { self == other.as_str() } } impl PartialOrd for String { fn partial_cmp(&self, other: &GString) -> Option { Some(self.cmp(&String::from(other.as_str()))) } } impl PartialOrd for GString { fn partial_cmp(&self, other: &String) -> Option { Some(self.as_str().cmp(other.as_str())) } } impl PartialOrd for str { fn partial_cmp(&self, other: &GString) -> Option { Some(self.cmp(other)) } } impl PartialOrd for GString { fn partial_cmp(&self, other: &str) -> Option { Some(self.as_str().cmp(other)) } } impl Eq for GString {} impl AsRef for GString { fn as_ref(&self) -> &str { self.as_str() } } impl AsRef for GString { fn as_ref(&self) -> &OsStr { OsStr::new(self.as_str()) } } impl Deref for GString { type Target = str; fn deref(&self) -> &str { self.as_str() } } impl From for String { #[inline] fn from(mut s: GString) -> Self { if let GString(Inner::Native(ref mut cstring)) = s { if let Ok(s) = cstring .take() .expect("Native shouldn't be empty") .into_string() { return s; } } Self::from(s.as_str()) } } impl From for Box { #[inline] fn from(s: GString) -> Self { let st: String = s.into(); st.into_boxed_str() } } impl From for GString { #[inline] fn from(s: String) -> Self { s.into_bytes().into() } } impl From> for GString { #[inline] fn from(s: Box) -> Self { s.as_bytes().to_vec().into() } } impl<'a> From<&'a str> for GString { #[inline] fn from(s: &'a str) -> Self { s.as_bytes().to_vec().into() } } impl From> for GString { #[inline] fn from(s: Vec) -> Self { let cstring = CString::new(s).expect("CString::new failed"); cstring.into() } } impl From for GString { #[inline] fn from(s: CString) -> Self { Self(Inner::Native(Some(s))) } } impl<'a> From<&'a CStr> for GString { #[inline] fn from(c: &'a CStr) -> Self { CString::from(c).into() } } #[doc(hidden)] impl FromGlibPtrFull<*const c_char> for GString { #[inline] unsafe fn from_glib_full(ptr: *const c_char) -> Self { Self::new(ptr as *mut _) } } #[doc(hidden)] impl FromGlibPtrFull<*mut u8> for GString { #[inline] unsafe fn from_glib_full(ptr: *mut u8) -> Self { Self::new(ptr as *mut _) } } #[doc(hidden)] impl FromGlibPtrFull<*mut i8> for GString { #[inline] unsafe fn from_glib_full(ptr: *mut i8) -> Self { Self::new(ptr as *mut _) } } #[doc(hidden)] impl FromGlibPtrNone<*const c_char> for GString { #[inline] unsafe fn from_glib_none(ptr: *const c_char) -> Self { assert!(!ptr.is_null()); let cstr = CStr::from_ptr(ptr); cstr.into() } } #[doc(hidden)] impl FromGlibPtrNone<*mut u8> for GString { #[inline] unsafe fn from_glib_none(ptr: *mut u8) -> Self { assert!(!ptr.is_null()); let cstr = CStr::from_ptr(ptr as *mut _); cstr.into() } } #[doc(hidden)] impl FromGlibPtrNone<*mut i8> for GString { #[inline] unsafe fn from_glib_none(ptr: *mut i8) -> Self { assert!(!ptr.is_null()); let cstr = CStr::from_ptr(ptr as *mut _); cstr.into() } } #[doc(hidden)] impl FromGlibPtrBorrow<*const c_char> for GString { #[inline] unsafe fn from_glib_borrow(ptr: *const c_char) -> Borrowed { Self::new_borrowed(ptr) } } #[doc(hidden)] impl FromGlibPtrBorrow<*mut u8> for GString { #[inline] unsafe fn from_glib_borrow(ptr: *mut u8) -> Borrowed { Self::new_borrowed(ptr as *const c_char) } } #[doc(hidden)] impl FromGlibPtrBorrow<*mut i8> for GString { #[inline] unsafe fn from_glib_borrow(ptr: *mut i8) -> Borrowed { Self::new_borrowed(ptr as *const c_char) } } #[doc(hidden)] impl<'a> ToGlibPtr<'a, *const c_char> for GString { type Storage = &'a Self; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> { Stash(self.as_ptr() as *const _, self) } #[inline] fn to_glib_full(&self) -> *const c_char { unsafe { ffi::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t) as *const c_char } } } #[doc(hidden)] impl<'a> ToGlibPtr<'a, *mut c_char> for GString { type Storage = &'a Self; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> { Stash(self.as_ptr() as *mut _, self) } #[inline] fn to_glib_full(&self) -> *mut c_char { unsafe { ffi::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t) as *mut c_char } } } #[doc(hidden)] impl<'a> FromGlibContainer<*const c_char, *const i8> for GString { unsafe fn from_glib_none_num(ptr: *const i8, num: usize) -> Self { if num == 0 || ptr.is_null() { return Self::from(""); } let mut bytes = Vec::with_capacity(num + 1); let slice = slice::from_raw_parts(ptr as *const u8, num); bytes.extend_from_slice(slice); bytes.push(0); CStr::from_bytes_with_nul_unchecked(bytes.as_slice()).into() } unsafe fn from_glib_container_num(ptr: *const i8, num: usize) -> Self { if num == 0 || ptr.is_null() { return Self::from(""); } GString(Inner::Foreign( ptr::NonNull::new_unchecked(ptr as *mut _), num, )) } unsafe fn from_glib_full_num(ptr: *const i8, num: usize) -> Self { if num == 0 || ptr.is_null() { return Self::from(""); } GString(Inner::Foreign( ptr::NonNull::new_unchecked(ptr as *mut _), num, )) } } #[doc(hidden)] impl<'a> FromGlibContainer<*const c_char, *mut i8> for GString { unsafe fn from_glib_none_num(ptr: *mut i8, num: usize) -> Self { FromGlibContainer::from_glib_none_num(ptr as *const i8, num) } unsafe fn from_glib_container_num(ptr: *mut i8, num: usize) -> Self { FromGlibContainer::from_glib_container_num(ptr as *const i8, num) } unsafe fn from_glib_full_num(ptr: *mut i8, num: usize) -> Self { FromGlibContainer::from_glib_full_num(ptr as *const i8, num) } } #[doc(hidden)] impl<'a> FromGlibContainer<*const c_char, *const u8> for GString { unsafe fn from_glib_none_num(ptr: *const u8, num: usize) -> Self { FromGlibContainer::from_glib_none_num(ptr as *const i8, num) } unsafe fn from_glib_container_num(ptr: *const u8, num: usize) -> Self { FromGlibContainer::from_glib_container_num(ptr as *const i8, num) } unsafe fn from_glib_full_num(ptr: *const u8, num: usize) -> Self { FromGlibContainer::from_glib_full_num(ptr as *const i8, num) } } #[doc(hidden)] impl<'a> FromGlibContainer<*const c_char, *mut u8> for GString { unsafe fn from_glib_none_num(ptr: *mut u8, num: usize) -> Self { FromGlibContainer::from_glib_none_num(ptr as *const i8, num) } unsafe fn from_glib_container_num(ptr: *mut u8, num: usize) -> Self { FromGlibContainer::from_glib_container_num(ptr as *const i8, num) } unsafe fn from_glib_full_num(ptr: *mut u8, num: usize) -> Self { FromGlibContainer::from_glib_full_num(ptr as *const i8, num) } } impl GlibPtrDefault for GString { type GlibType = *const c_char; } impl StaticType for GString { fn static_type() -> Type { String::static_type() } } impl crate::value::ValueType for GString { type Type = String; } unsafe impl<'a> crate::value::FromValue<'a> for GString { type Checker = crate::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a crate::Value) -> Self { Self::from(<&str>::from_value(value)) } } impl crate::value::ToValue for GString { fn to_value(&self) -> crate::Value { <&str>::to_value(&self.as_str()) } fn value_type(&self) -> Type { String::static_type() } } impl crate::value::ToValueOptional for GString { fn to_value_optional(s: Option<&Self>) -> crate::Value { ::to_value_optional(s.as_ref().map(|s| s.as_str())) } } impl StaticType for Vec { fn static_type() -> Type { >::static_type() } } impl crate::value::ValueType for Vec { type Type = Vec; } unsafe impl<'a> crate::value::FromValue<'a> for Vec { type Checker = crate::value::GenericValueTypeChecker; unsafe fn from_value(value: &'a crate::value::Value) -> Self { let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char; FromGlibPtrContainer::from_glib_none(ptr) } } impl crate::value::ToValue for Vec { fn to_value(&self) -> crate::value::Value { unsafe { let mut value = crate::value::Value::for_value_type::(); let ptr: *mut *mut c_char = self.to_glib_full(); gobject_ffi::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void); value } } fn value_type(&self) -> Type { >::static_type() } } impl_from_glib_container_as_vec_string!(GString, *const c_char); impl_from_glib_container_as_vec_string!(GString, *mut c_char); #[cfg(test)] #[allow(clippy::blacklisted_name)] mod tests { use super::{FromGlibContainer, GString}; use std::ffi::CString; #[test] fn test_gstring() { let data = CString::new("foo").unwrap(); let ptr = data.as_ptr(); unsafe { let ptr_copy = ffi::g_strdup(ptr); let gstring = GString::new(ptr_copy); assert_eq!(gstring.as_str(), "foo"); let foo: Box = gstring.into(); assert_eq!(foo.as_ref(), "foo"); } } #[test] fn test_owned_glib_string() { let data = CString::new("foo").unwrap(); let ptr = data.as_ptr(); unsafe { let ptr_copy = ffi::g_strdup(ptr); let gstr = GString::new(ptr_copy); assert_eq!(gstr, "foo"); } } #[test] fn test_gstring_from_str() { let gstring: GString = "foo".into(); assert_eq!(gstring.as_str(), "foo"); let foo: Box = gstring.into(); assert_eq!(foo.as_ref(), "foo"); } #[test] fn test_gstring_from_cstring() { let cstr = CString::new("foo").unwrap(); let gstring = GString::from(cstr); assert_eq!(gstring.as_str(), "foo"); let foo: Box = gstring.into(); assert_eq!(foo.as_ref(), "foo"); } #[test] fn test_string_from_gstring() { let cstr = CString::new("foo").unwrap(); let gstring = GString::from(cstr); assert_eq!(gstring.as_str(), "foo"); let s = String::from(gstring); assert_eq!(s, "foo"); } #[test] fn test_vec_u8_to_gstring() { let v: &[u8] = b"foo"; let s: GString = Vec::from(v).into(); assert_eq!(s.as_str(), "foo"); } #[test] fn test_from_glib_container() { unsafe { let test_a: GString = FromGlibContainer::from_glib_container_num( ffi::g_strdup("hello_world".as_ptr() as *const _), 5, ); assert_eq!("hello", test_a.as_str()); let test_b: GString = FromGlibContainer::from_glib_none_num("hello_world".as_ptr(), 5); assert_eq!("hello", test_b.as_str()); let test_c: GString = FromGlibContainer::from_glib_none_num(std::ptr::null::(), 0); assert_eq!("", test_c.as_str()); let test_d: GString = FromGlibContainer::from_glib_none_num("".as_ptr(), 0); assert_eq!("", test_d.as_str()); let test_e: GString = FromGlibContainer::from_glib_container_num(ffi::g_strdup(std::ptr::null()), 0); assert_eq!("", test_e.as_str()); } } #[test] fn test_hashmap() { use std::collections::HashMap; let cstr = CString::new("foo").unwrap(); let gstring = GString::from(cstr); assert_eq!(gstring.as_str(), "foo"); let mut h: HashMap = HashMap::new(); h.insert(gstring, 42); let gstring: GString = "foo".into(); assert!(h.contains_key(&gstring)); } } glib-0.14.8/src/key_file.rs000064400000000000000000000204020072674642500136050ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::error::Error; use crate::gstring::GString; use crate::translate::*; use crate::KeyFileFlags; use std::mem; use std::path; use std::ptr; use crate::KeyFile; impl KeyFile { #[doc(alias = "g_key_file_save_to_file")] pub fn save_to_file>(&self, filename: T) -> Result<(), Error> { unsafe { let mut error = ptr::null_mut(); let _ = ffi::g_key_file_save_to_file( self.to_glib_none().0, filename.as_ref().to_glib_none().0, &mut error, ); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_load_from_data_dirs")] pub fn load_from_data_dirs>( &self, file: T, flags: KeyFileFlags, ) -> Result { unsafe { let mut error = ptr::null_mut(); let mut full_path: *mut libc::c_char = ptr::null_mut(); let _ = ffi::g_key_file_load_from_data_dirs( self.to_glib_none().0, file.as_ref().to_glib_none().0, &mut full_path, flags.into_glib(), &mut error, ); if error.is_null() { let path: GString = from_glib_full(full_path); Ok(path::PathBuf::from(&path)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_load_from_dirs")] pub fn load_from_dirs, U: AsRef>( &self, file: T, search_dirs: &[U], flags: KeyFileFlags, ) -> Result { unsafe { let search_dirs: Vec<&std::path::Path> = search_dirs.iter().map(AsRef::as_ref).collect(); let mut error = ptr::null_mut(); let mut full_path: *mut libc::c_char = ptr::null_mut(); let _ = ffi::g_key_file_load_from_dirs( self.to_glib_none().0, file.as_ref().to_glib_none().0, search_dirs.to_glib_none().0, &mut full_path, flags.into_glib(), &mut error, ); if error.is_null() { let path: GString = from_glib_full(full_path); Ok(path::PathBuf::from(&path)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_to_data")] pub fn to_data(&self) -> GString { unsafe { let ret = ffi::g_key_file_to_data(self.to_glib_none().0, ptr::null_mut(), ptr::null_mut()); from_glib_full(ret) } } #[doc(alias = "g_key_file_get_boolean")] #[doc(alias = "get_boolean")] pub fn boolean(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_boolean( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(from_glib(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_has_key")] pub fn has_key(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_key_file_has_key( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(from_glib(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_boolean_list")] #[doc(alias = "get_boolean_list")] pub fn boolean_list(&self, group_name: &str, key: &str) -> Result, Error> { unsafe { let mut length = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_boolean_list( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, length.as_mut_ptr(), &mut error, ); if !error.is_null() { return Err(from_glib_full(error)); } Ok(FromGlibContainer::from_glib_container_num( ret, length.assume_init() as usize, )) } } #[doc(alias = "g_key_file_get_string")] #[doc(alias = "get_string")] pub fn string(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_string( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { if !ret.is_null() { ffi::g_free(ret as *mut _); } Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_string_list")] #[doc(alias = "get_string_list")] pub fn string_list(&self, group_name: &str, key: &str) -> Result, Error> { unsafe { let mut length = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_string_list( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, length.as_mut_ptr(), &mut error, ); if error.is_null() { Ok(FromGlibContainer::from_glib_full_num( ret, length.assume_init() as usize, )) } else { if !ret.is_null() { ffi::g_strfreev(ret); } Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_locale_string")] #[doc(alias = "get_locale_string")] pub fn locale_string( &self, group_name: &str, key: &str, locale: Option<&str>, ) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_locale_string( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, locale.to_glib_none().0, &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { if !ret.is_null() { ffi::g_free(ret as *mut _); } Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_locale_string_list")] #[doc(alias = "get_locale_string_list")] pub fn locale_string_list( &self, group_name: &str, key: &str, locale: Option<&str>, ) -> Result, Error> { unsafe { let mut length = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_locale_string_list( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, locale.to_glib_none().0, length.as_mut_ptr(), &mut error, ); if error.is_null() { Ok(FromGlibContainer::from_glib_full_num( ret, length.assume_init() as usize, )) } else { if !ret.is_null() { ffi::g_strfreev(ret); } Err(from_glib_full(error)) } } } } glib-0.14.8/src/lib.rs000064400000000000000000000203100072674642500125620ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! # Rust GLib and GObject bindings //! //! This library contains bindings to GLib and GObject types and APIs as well as //! common building blocks used in both handmade and machine generated //! bindings to GTK and other GLib-based libraries. //! //! It is the foundation for higher level libraries with uniform Rusty (safe and //! strongly typed) APIs. It avoids exposing GLib-specific data types where //! possible and is not meant to provide comprehensive GLib bindings, which //! would often amount to duplicating the Rust Standard Library or other utility //! crates. //! //! GLib 2.48 is the lowest supported version for the underlying library. //! //! # Dynamic typing //! //! Most types in the GLib family have [`Type`] identifiers. //! Their corresponding Rust types implement the [`StaticType`] trait. //! //! A dynamically typed [`Value`] can carry values of any [`StaticType`]. //! [`Variant`]s can carry values of [`StaticVariantType`]. //! //! # Errors //! //! Errors are represented by [`Error`], which can //! carry values from various [error domains](error::ErrorDomain) such as //! [`FileError`]. //! //! # Objects //! //! Each class and interface has a corresponding smart pointer struct //! representing an instance of that type (e.g. [`Object`] for `GObject` or //! `gtk::Widget` for `GtkWidget`). They are reference counted and feature //! interior mutability similarly to Rust's `Rc>` idiom. //! Consequently, cloning objects is cheap and their methods never require //! mutable borrows. Two smart pointers are equal if they point to the same //! object. //! //! The root of the object hierarchy is [`Object`]. //! Inheritance and subtyping is denoted with the [`IsA`] //! marker trait. The [`Cast`] trait enables upcasting //! and downcasting. //! //! Interfaces and non-leaf classes also have corresponding traits (e.g. //! [`ObjectExt`] or `gtk::WidgetExt`), which are blanketly implemented for all //! their subtypes. //! //! You can create new subclasses of [`Object`] or other object types. Look at //! the module's documentation for further details and a code example. //! //! # Under the hood //! //! GLib-based libraries largely operate on pointers to various boxed or //! reference counted structures so the bindings have to implement corresponding //! smart pointers (wrappers), which encapsulate resource management and safety //! checks. Such wrappers are defined via the //! [`macro@wrapper`] macro, which uses abstractions //! defined in the [`mod@wrapper`], [`mod@boxed`], //! [`mod@shared`] and [`mod@object`] modules. //! //! The [`mod@translate`] module defines and partly implements //! conversions between high level Rust types (including the aforementioned //! wrappers) and their FFI counterparts. #![cfg_attr(feature = "dox", feature(doc_cfg))] #![allow(clippy::missing_safety_doc)] #![allow(clippy::wrong_self_convention)] pub use ffi; pub use gobject_ffi; #[doc(hidden)] pub use bitflags; #[doc(hidden)] pub use once_cell; pub use glib_macros::{ clone, gflags, object_interface, object_subclass, Downgrade, GBoxed, GEnum, GErrorDomain, GSharedBoxed, }; pub use self::array::Array; pub use self::byte_array::ByteArray; pub use self::bytes::Bytes; pub use self::closure::Closure; pub use self::error::{BoolError, Error}; pub use self::file_error::FileError; pub use self::object::{ Cast, Class, InitiallyUnowned, Interface, IsA, Object, ObjectExt, ObjectType, SendWeakRef, WeakRef, }; pub use self::signal::{ signal_handler_block, signal_handler_disconnect, signal_handler_unblock, signal_stop_emission_by_name, SignalHandlerId, }; pub use self::string::String; use std::ffi::CStr; pub use self::enums::{EnumClass, EnumValue, FlagsBuilder, FlagsClass, FlagsValue, UserDirectory}; pub use self::types::{ILong, StaticType, Type, ULong}; pub use self::value::{BoxedValue, SendValue, ToSendValue, ToValue, Value}; pub use self::variant::{FromVariant, StaticVariantType, ToVariant, Variant}; pub use self::variant_dict::VariantDict; pub use self::variant_iter::{VariantIter, VariantStrIter}; pub use self::variant_type::{VariantTy, VariantType}; pub mod clone; #[macro_use] pub mod wrapper; #[macro_use] pub mod boxed; #[macro_use] pub mod shared; #[macro_use] pub mod error; #[macro_use] pub mod object; pub use self::auto::functions::*; pub use self::auto::*; #[allow(non_upper_case_globals)] #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] #[allow(unused_imports)] mod auto; pub use self::gobject::*; mod gobject; mod array; mod byte_array; mod bytes; pub mod char; mod string; pub use self::char::*; mod checksum; pub mod closure; mod enums; mod file_error; mod functions; pub use self::functions::*; mod key_file; pub mod prelude; pub mod signal; pub mod source; pub use self::source::*; #[macro_use] pub mod translate; mod gstring; pub use self::gstring::GString; pub mod types; mod unicollate; pub use self::unicollate::{CollationKey, FilenameCollationKey}; mod utils; pub use self::utils::*; mod main_context; mod main_context_channel; pub use self::main_context::MainContextAcquireGuard; pub use self::main_context_channel::{Receiver, Sender, SyncSender}; mod date; pub mod value; pub mod variant; mod variant_dict; mod variant_iter; mod variant_type; pub use self::date::Date; mod value_array; pub use self::value_array::ValueArray; mod param_spec; pub use self::param_spec::*; mod quark; pub use self::quark::Quark; #[macro_use] mod log; pub use self::log::log_set_handler; // #[cfg(any(feature = "v2_50", feature = "dox"))] // pub use log::log_variant; pub use self::log::{ log_default_handler, log_remove_handler, log_set_always_fatal, log_set_default_handler, log_set_fatal_mask, log_unset_default_handler, set_print_handler, set_printerr_handler, unset_print_handler, unset_printerr_handler, LogHandlerId, LogLevel, LogLevels, }; #[doc(hidden)] #[cfg(any(feature = "dox", feature = "log_macros"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "log_macros")))] pub use rs_log; #[cfg(any(feature = "log", feature = "dox"))] #[macro_use] mod bridged_logging; #[cfg(any(feature = "log", feature = "dox"))] pub use self::bridged_logging::{rust_log_handler, GlibLogger, GlibLoggerDomain, GlibLoggerFormat}; pub mod send_unique; pub use self::send_unique::{SendUnique, SendUniqueCell}; #[macro_use] pub mod subclass; mod main_context_futures; mod source_futures; pub use self::source_futures::*; mod thread_pool; pub use self::thread_pool::ThreadPool; /// This is the log domain used by the [`clone!`][crate::clone!] macro. If you want to use a custom /// logger (it prints to stdout by default), you can set your own logger using the corresponding /// `log` functions. pub const CLONE_MACRO_LOG_DOMAIN: &str = "glib-rs-clone"; // Actual thread IDs can be reused by the OS once the old thread finished. // This works around it by using our own counter for threads. // // Taken from the fragile crate use std::sync::atomic::{AtomicUsize, Ordering}; fn next_thread_id() -> usize { static mut COUNTER: AtomicUsize = AtomicUsize::new(0); unsafe { COUNTER.fetch_add(1, Ordering::SeqCst) } } #[doc(alias = "get_thread_id")] pub(crate) fn thread_id() -> usize { thread_local!(static THREAD_ID: usize = next_thread_id()); THREAD_ID.with(|&x| x) } pub(crate) struct ThreadGuard { thread_id: usize, value: T, } impl ThreadGuard { pub(crate) fn new(value: T) -> Self { Self { thread_id: thread_id(), value, } } pub(crate) fn get_ref(&self) -> &T { if self.thread_id != thread_id() { panic!("Value accessed from different thread than where it was created"); } &self.value } pub(crate) fn get_mut(&mut self) -> &mut T { if self.thread_id != thread_id() { panic!("Value accessed from different thread than where it was created"); } &mut self.value } } impl Drop for ThreadGuard { fn drop(&mut self) { if self.thread_id != thread_id() { panic!("Value dropped on a different thread than where it was created"); } } } unsafe impl Send for ThreadGuard {} #[cfg(target_family = "windows")] mod win32; #[cfg(target_family = "windows")] pub use self::win32::*; glib-0.14.8/src/log.rs000064400000000000000000000577010072674642500126130ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::*; use crate::GString; use once_cell::sync::Lazy; use std::boxed::Box as Box_; use std::sync::{Arc, Mutex}; #[derive(Debug)] pub struct LogHandlerId(u32); #[doc(hidden)] impl FromGlib for LogHandlerId { unsafe fn from_glib(value: u32) -> Self { Self(value) } } #[doc(hidden)] impl IntoGlib for LogHandlerId { type GlibType = u32; fn into_glib(self) -> u32 { self.0 } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum LogLevel { #[doc(alias = "G_LOG_LEVEL_ERROR")] Error, #[doc(alias = "G_LOG_LEVEL_CRITICAL")] Critical, #[doc(alias = "G_LOG_LEVEL_WARNING")] Warning, #[doc(alias = "G_LOG_LEVEL_MESSAGE")] Message, #[doc(alias = "G_LOG_LEVEL_INFO")] Info, #[doc(alias = "G_LOG_LEVEL_DEBUG")] Debug, } #[doc(hidden)] impl IntoGlib for LogLevel { type GlibType = u32; fn into_glib(self) -> u32 { match self { Self::Error => ffi::G_LOG_LEVEL_ERROR, Self::Critical => ffi::G_LOG_LEVEL_CRITICAL, Self::Warning => ffi::G_LOG_LEVEL_WARNING, Self::Message => ffi::G_LOG_LEVEL_MESSAGE, Self::Info => ffi::G_LOG_LEVEL_INFO, Self::Debug => ffi::G_LOG_LEVEL_DEBUG, } } } #[doc(hidden)] impl FromGlib for LogLevel { unsafe fn from_glib(value: u32) -> Self { if value & ffi::G_LOG_LEVEL_ERROR != 0 { Self::Error } else if value & ffi::G_LOG_LEVEL_CRITICAL != 0 { Self::Critical } else if value & ffi::G_LOG_LEVEL_WARNING != 0 { Self::Warning } else if value & ffi::G_LOG_LEVEL_MESSAGE != 0 { Self::Message } else if value & ffi::G_LOG_LEVEL_INFO != 0 { Self::Info } else if value & ffi::G_LOG_LEVEL_DEBUG != 0 { Self::Debug } else { panic!("Unknown log level: {}", value) } } } bitflags::bitflags! { #[doc(alias = "GLogLevelFlags")] pub struct LogLevels: u32 { #[doc(alias = "G_LOG_LEVEL_ERROR")] const LEVEL_ERROR = ffi::G_LOG_LEVEL_ERROR; #[doc(alias = "G_LOG_LEVEL_CRITICAL")] const LEVEL_CRITICAL = ffi::G_LOG_LEVEL_CRITICAL; #[doc(alias = "G_LOG_LEVEL_WARNING")] const LEVEL_WARNING = ffi::G_LOG_LEVEL_WARNING; #[doc(alias = "G_LOG_LEVEL_MESSAGE")] const LEVEL_MESSAGE = ffi::G_LOG_LEVEL_MESSAGE; #[doc(alias = "G_LOG_LEVEL_INFO")] const LEVEL_INFO = ffi::G_LOG_LEVEL_INFO; #[doc(alias = "G_LOG_LEVEL_DEBUG")] const LEVEL_DEBUG = ffi::G_LOG_LEVEL_DEBUG; } } #[doc(hidden)] impl IntoGlib for LogLevels { type GlibType = ffi::GLogLevelFlags; fn into_glib(self) -> ffi::GLogLevelFlags { self.bits() } } #[doc(hidden)] impl FromGlib for LogLevels { unsafe fn from_glib(value: ffi::GLogLevelFlags) -> Self { Self::from_bits_truncate(value) } } fn to_log_flags(fatal: bool, recursion: bool) -> u32 { (if fatal { ffi::G_LOG_FLAG_FATAL } else { 0 }) | if recursion { ffi::G_LOG_FLAG_RECURSION } else { 0 } } #[doc(alias = "g_log_set_handler_full")] pub fn log_set_handler, LogLevel, &str) + Send + Sync + 'static>( log_domain: Option<&str>, log_levels: LogLevels, fatal: bool, recursion: bool, log_func: P, ) -> LogHandlerId { let log_func_data: Box_

= Box_::new(log_func); unsafe extern "C" fn log_func_func< P: Fn(Option<&str>, LogLevel, &str) + Send + Sync + 'static, >( log_domain: *const libc::c_char, log_level: ffi::GLogLevelFlags, message: *const libc::c_char, user_data: ffi::gpointer, ) { let log_domain: Borrowed> = from_glib_borrow(log_domain); let message: Borrowed = from_glib_borrow(message); let callback: &P = &*(user_data as *mut _); (*callback)( (*log_domain).as_deref(), from_glib(log_level), message.as_str(), ); } let log_func = Some(log_func_func::

as _); unsafe extern "C" fn destroy_func< P: Fn(Option<&str>, LogLevel, &str) + Send + Sync + 'static, >( data: ffi::gpointer, ) { let _callback: Box_

= Box_::from_raw(data as *mut _); } let destroy_call4 = Some(destroy_func::

as _); let super_callback0: Box_

= log_func_data; unsafe { from_glib(ffi::g_log_set_handler_full( log_domain.to_glib_none().0, log_levels.into_glib() | to_log_flags(fatal, recursion), log_func, Box_::into_raw(super_callback0) as *mut _, destroy_call4, )) } } #[doc(alias = "g_log_remove_handler")] pub fn log_remove_handler(log_domain: Option<&str>, handler_id: LogHandlerId) { unsafe { ffi::g_log_remove_handler(log_domain.to_glib_none().0, handler_id.into_glib()); } } #[doc(alias = "g_log_set_always_fatal")] pub fn log_set_always_fatal(fatal_levels: LogLevels) -> LogLevels { unsafe { from_glib(ffi::g_log_set_always_fatal(fatal_levels.into_glib())) } } #[doc(alias = "g_log_set_fatal_mask")] pub fn log_set_fatal_mask(log_domain: Option<&str>, fatal_levels: LogLevels) -> LogLevels { unsafe { from_glib(ffi::g_log_set_fatal_mask( log_domain.to_glib_none().0, fatal_levels.into_glib(), )) } } // #[cfg(any(feature = "v2_50", feature = "dox"))] // pub fn log_variant(log_domain: Option<&str>, log_level: LogLevel, fields: &Variant) { // unsafe { // ffi::g_log_variant( // log_domain.to_glib_none().0, // log_level.into_glib(), // fields.to_glib_none().0, // ); // } // } type PrintCallback = dyn Fn(&str) + Send + Sync + 'static; static PRINT_HANDLER: Lazy>>> = Lazy::new(|| Mutex::new(None)); /// To set back the default print handler, use the [`unset_print_handler`] function. #[doc(alias = "g_set_print_handler")] pub fn set_print_handler(func: P) { unsafe extern "C" fn func_func(string: *const libc::c_char) { if let Some(callback) = PRINT_HANDLER .lock() .expect("Failed to lock PRINT_HANDLER") .as_ref() .map(Arc::clone) { let string: Borrowed = from_glib_borrow(string); (*callback)(string.as_str()) } } *PRINT_HANDLER .lock() .expect("Failed to lock PRINT_HANDLER to change callback") = Some(Arc::new(func)); unsafe { ffi::g_set_print_handler(Some(func_func as _)) }; } /// To set the default print handler, use the [`set_print_handler`] function. pub fn unset_print_handler() { *PRINT_HANDLER .lock() .expect("Failed to lock PRINT_HANDLER to remove callback") = None; unsafe { ffi::g_set_print_handler(None) }; } static PRINTERR_HANDLER: Lazy>>> = Lazy::new(|| Mutex::new(None)); /// To set back the default print handler, use the [`unset_printerr_handler`] function. #[doc(alias = "g_set_printerr_handler")] pub fn set_printerr_handler(func: P) { unsafe extern "C" fn func_func(string: *const libc::c_char) { if let Some(callback) = PRINTERR_HANDLER .lock() .expect("Failed to lock PRINTERR_HANDLER") .as_ref() .map(Arc::clone) { let string: Borrowed = from_glib_borrow(string); (*callback)(string.as_str()) } } *PRINTERR_HANDLER .lock() .expect("Failed to lock PRINTERR_HANDLER to change callback") = Some(Arc::new(func)); unsafe { ffi::g_set_printerr_handler(Some(func_func as _)) }; } /// To set the default print handler, use the [`set_printerr_handler`] function. pub fn unset_printerr_handler() { *PRINTERR_HANDLER .lock() .expect("Failed to lock PRINTERR_HANDLER to remove callback") = None; unsafe { ffi::g_set_printerr_handler(None) }; } type LogCallback = dyn Fn(Option<&str>, LogLevel, &str) + Send + Sync + 'static; static DEFAULT_HANDLER: Lazy>>> = Lazy::new(|| Mutex::new(None)); /// To set back the default print handler, use the [`log_unset_default_handler`] function. #[doc(alias = "g_log_set_default_handler")] pub fn log_set_default_handler, LogLevel, &str) + Send + Sync + 'static>( log_func: P, ) { unsafe extern "C" fn func_func( log_domain: *const libc::c_char, log_levels: ffi::GLogLevelFlags, message: *const libc::c_char, _user_data: ffi::gpointer, ) { if let Some(callback) = DEFAULT_HANDLER .lock() .expect("Failed to lock DEFAULT_HANDLER") .as_ref() .map(Arc::clone) { let log_domain: Borrowed> = from_glib_borrow(log_domain); let message: Borrowed = from_glib_borrow(message); (*callback)( (*log_domain).as_deref(), from_glib(log_levels), message.as_str(), ); } } *DEFAULT_HANDLER .lock() .expect("Failed to lock DEFAULT_HANDLER to change callback") = Some(Arc::new(log_func)); unsafe { ffi::g_log_set_default_handler(Some(func_func as _), std::ptr::null_mut()) }; } /// To set the default print handler, use the [`log_set_default_handler`] function. #[doc(alias = "g_log_set_default_handler")] pub fn log_unset_default_handler() { *DEFAULT_HANDLER .lock() .expect("Failed to lock DEFAULT_HANDLER to remove callback") = None; unsafe { ffi::g_log_set_default_handler(Some(ffi::g_log_default_handler), std::ptr::null_mut()) }; } #[doc(alias = "g_log_default_handler")] pub fn log_default_handler(log_domain: Option<&str>, log_level: LogLevel, message: Option<&str>) { unsafe { ffi::g_log_default_handler( log_domain.to_glib_none().0, log_level.into_glib(), message.to_glib_none().0, std::ptr::null_mut(), ) } } /// Macro used to log using GLib logging system. It uses [g_log]. /// /// [g_log]: https://developer.gnome.org/glib/stable/glib-Message-Logging.html#g-log /// /// Example: /// /// ```no_run /// use glib::{LogLevel, g_log}; /// /// g_log!("test", LogLevel::Debug, "test"); /// g_log!("test", LogLevel::Message, "test"); /// // trailing commas work as well: /// g_log!("test", LogLevel::Message, "test",); /// /// // You can also pass arguments like in format! or println!: /// let x = 12; /// g_log!("test", LogLevel::Error, "test: {}", x); /// g_log!("test", LogLevel::Critical, "test: {}", x); /// g_log!("test", LogLevel::Warning, "test: {} {}", x, "a"); /// // trailing commas work as well: /// g_log!("test", LogLevel::Warning, "test: {} {}", x, "a",); /// ``` /// /// To be noted that the log domain is optional: /// /// ```no_run /// use glib::{LogLevel, g_log}; /// /// // As you can see: no log domain: /// g_log!(LogLevel::Message, "test"); /// // For the rest, it's just like when you have the log domain: /// // trailing commas: /// g_log!(LogLevel::Message, "test",); /// /// // formatting: /// let x = 12; /// g_log!(LogLevel::Warning, "test: {} {}", x, "a"); /// g_log!(LogLevel::Warning, "test: {} {}", x, "a",); /// ``` #[macro_export] macro_rules! g_log { ($log_level:expr, $format:literal, $($arg:expr),* $(,)?) => {{ use $crate::translate::{IntoGlib, ToGlibPtr}; use $crate::LogLevel; fn check_log_args(_log_level: LogLevel, _format: &str) {} check_log_args($log_level, $format); // to prevent the glib formatter to look for arguments which don't exist let f = format!($format, $($arg),*).replace("%", "%%"); unsafe { $crate::ffi::g_log( std::ptr::null(), $log_level.into_glib(), f.to_glib_none().0, ); } }}; ($log_level:expr, $format:literal $(,)?) => {{ use $crate::translate::{IntoGlib, ToGlibPtr}; use $crate::LogLevel; fn check_log_args(_log_level: LogLevel, _format: &str) {} check_log_args($log_level, $format); // to prevent the glib formatter to look for arguments which don't exist let f = $format.replace("%", "%%"); unsafe { $crate::ffi::g_log( std::ptr::null(), $log_level.into_glib(), f.to_glib_none().0, ); } }}; ($log_domain:expr, $log_level:expr, $format:literal, $($arg:expr),* $(,)?) => {{ use $crate::translate::{IntoGlib, ToGlibPtr}; use $crate::LogLevel; fn check_log_args(_log_level: LogLevel, _format: &str) {} // the next line is used to enforce the type for the macro checker... let log_domain: Option<&str> = $log_domain.into(); check_log_args($log_level, $format); // to prevent the glib formatter to look for arguments which don't exist let f = format!($format, $($arg),*).replace("%", "%%"); unsafe { $crate::ffi::g_log( log_domain.to_glib_none().0, $log_level.into_glib(), f.to_glib_none().0, ); } }}; ($log_domain:expr, $log_level:expr, $format:literal $(,)?) => {{ use $crate::translate::{IntoGlib, ToGlibPtr}; use $crate::LogLevel; fn check_log_args(_log_level: LogLevel, _format: &str) {} // the next line is used to enforce the type for the macro checker... let log_domain: Option<&str> = $log_domain.into(); check_log_args($log_level, $format); // to prevent the glib formatter to look for arguments which don't exist let f = $format.replace("%", "%%"); unsafe { $crate::ffi::g_log( log_domain.to_glib_none().0, $log_level.into_glib(), f.to_glib_none().0, ); } }}; } /// Macro used to log using GLib logging system. It uses [g_log]. /// /// [g_log]: https://developer.gnome.org/glib/stable/glib-Message-Logging.html#g-log /// /// It is the same as calling the [`g_log!`] macro with [`LogLevel::Error`]. /// /// Example: /// /// ```no_run /// use glib::g_error; /// /// g_error!("test", "test"); /// // Equivalent to: /// use glib::{g_log, LogLevel}; /// g_log!("test", LogLevel::Error, "test"); /// /// // trailing commas work as well: /// g_error!("test", "test",); /// /// // You can also pass arguments like in format! or println!: /// let x = 12; /// g_error!("test", "test: {}", x); /// g_error!("test", "test: {} {}", x, "a"); /// // trailing commas work as well: /// g_error!("test", "test: {} {}", x, "a",); /// ``` #[macro_export] macro_rules! g_error { ($log_domain:expr, $format:literal, $($arg:expr),* $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Error, $format, $($arg),*); }}; ($log_domain:expr, $format:literal $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Error, $format); }}; } /// Macro used to log using GLib logging system. It uses [g_log]. /// /// [g_log]: https://developer.gnome.org/glib/stable/glib-Message-Logging.html#g-log /// /// It is the same as calling the [`g_log!`] macro with [`LogLevel::Critical`]. /// /// Example: /// /// ```no_run /// use glib::g_critical; /// /// g_critical!("test", "test"); /// // Equivalent to: /// use glib::{g_log, LogLevel}; /// g_log!("test", LogLevel::Critical, "test"); /// /// // trailing commas work as well: /// g_critical!("test", "test",); /// /// // You can also pass arguments like in format! or println!: /// let x = 12; /// g_critical!("test", "test: {}", x); /// g_critical!("test", "test: {} {}", x, "a"); /// // trailing commas work as well: /// g_critical!("test", "test: {} {}", x, "a",); /// ``` #[macro_export] macro_rules! g_critical { ($log_domain:expr, $format:literal, $($arg:expr),* $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Critical, $format, $($arg),*); }}; ($log_domain:expr, $format:literal $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Critical, $format); }}; } /// Macro used to log using GLib logging system. It uses [g_log]. /// /// [g_log]: https://developer.gnome.org/glib/stable/glib-Message-Logging.html#g-log /// /// It is the same as calling the [`g_log!`] macro with [`LogLevel::Warning`]. /// /// Example: /// /// ```no_run /// use glib::g_warning; /// /// g_warning!("test", "test"); /// // Equivalent to: /// use glib::{g_log, LogLevel}; /// g_log!("test", LogLevel::Warning, "test"); /// /// // trailing commas work as well: /// g_warning!("test", "test",); /// /// // You can also pass arguments like in format! or println!: /// let x = 12; /// g_warning!("test", "test: {}", x); /// g_warning!("test", "test: {} {}", x, "a"); /// // trailing commas work as well: /// g_warning!("test", "test: {} {}", x, "a",); /// ``` #[macro_export] macro_rules! g_warning { ($log_domain:expr, $format:literal, $($arg:expr),* $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Warning, $format, $($arg),*); }}; ($log_domain:expr, $format:literal $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Warning, $format); }}; } /// Macro used to log using GLib logging system. It uses [g_log]. /// /// [g_log]: https://developer.gnome.org/glib/stable/glib-Message-Logging.html#g-log /// /// It is the same as calling the [`g_log!`] macro with [`LogLevel::Message`]. /// /// Example: /// /// ```no_run /// use glib::g_message; /// /// g_message!("test", "test"); /// // Equivalent to: /// use glib::{g_log, LogLevel}; /// g_log!("test", LogLevel::Message, "test"); /// /// // trailing commas work as well: /// g_message!("test", "test",); /// /// // You can also pass arguments like in format! or println!: /// let x = 12; /// g_message!("test", "test: {}", x); /// g_message!("test", "test: {} {}", x, "a"); /// // trailing commas work as well: /// g_message!("test", "test: {} {}", x, "a",); /// ``` #[macro_export] macro_rules! g_message { ($log_domain:expr, $format:literal, $($arg:expr),* $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Message, $format, $($arg),*); }}; ($log_domain:expr, $format:literal $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Message, $format); }}; } /// Macro used to log using GLib logging system. It uses [g_log]. /// /// [g_log]: https://developer.gnome.org/glib/stable/glib-Message-Logging.html#g-log /// /// It is the same as calling the [`g_log!`] macro with [`LogLevel::Info`]. /// /// Example: /// /// ```no_run /// use glib::g_info; /// /// g_info!("test", "test"); /// // Equivalent to: /// use glib::{g_log, LogLevel}; /// g_log!("test", LogLevel::Info, "test"); /// /// // trailing commas work as well: /// g_info!("test", "test",); /// /// // You can also pass arguments like in format! or println!: /// let x = 12; /// g_info!("test", "test: {}", x); /// g_info!("test", "test: {} {}", x, "a"); /// // trailing commas work as well: /// g_info!("test", "test: {} {}", x, "a",); /// ``` #[macro_export] macro_rules! g_info { ($log_domain:expr, $format:literal, $($arg:expr),* $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Info, $format, $($arg),*); }}; ($log_domain:expr, $format:literal $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Info, $format); }}; } /// Macro used to log using GLib logging system. It uses [g_log]. /// /// [g_log]: https://developer.gnome.org/glib/stable/glib-Message-Logging.html#g-log /// /// It is the same as calling the [`g_log!`] macro with [`LogLevel::Debug`]. /// /// Example: /// /// ```no_run /// use glib::g_debug; /// /// g_debug!("test", "test"); /// // Equivalent to: /// use glib::{g_log, LogLevel}; /// g_log!("test", LogLevel::Debug, "test"); /// /// // trailing commas work as well: /// g_debug!("test", "test",); /// /// // You can also pass arguments like in format! or println!: /// let x = 12; /// g_debug!("test", "test: {}", x); /// g_debug!("test", "test: {} {}", x, "a"); /// // trailing commas work as well: /// g_debug!("test", "test: {} {}", x, "a",); /// ``` #[macro_export] macro_rules! g_debug { ($log_domain:expr, $format:literal, $($arg:expr),* $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Debug, $format, $($arg),*); }}; ($log_domain:expr, $format:literal $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Debug, $format); }}; } #[doc(hidden)] #[macro_export] macro_rules! g_print_inner { ($func:ident, $format:expr) => {{ use $crate::translate::ToGlibPtr; fn check_arg(_format: &str) {} check_arg($format); // to prevent the glib formatter to look for arguments which don't exist let f = $format.replace("%", "%%"); unsafe { $crate::ffi::$func(f.to_glib_none().0); } }}; ($func:ident, $format:expr, $($arg:expr),*) => {{ use $crate::translate::ToGlibPtr; fn check_arg(_format: &str) {} check_arg($format); // to prevent the glib formatter to look for arguments which don't exist let f = format!($format, $($arg),*).replace("%", "%%"); unsafe { $crate::ffi::$func(f.to_glib_none().0); } }}; } /// Macro used to print messages. It uses [g_print]. /// /// [g_print]: https://developer.gnome.org/glib/stable/glib-Warnings-and-Assertions.html#g-print /// /// Example: /// /// ```no_run /// use glib::g_print; /// /// g_print!("test"); /// // trailing commas work as well: /// g_print!("test",); /// /// let x = 12; /// g_print!("test: {}", x); /// g_print!("test: {} {}", x, "a"); /// // trailing commas work as well: /// g_print!("test: {} {}", x, "a",); /// ``` #[macro_export] macro_rules! g_print { ($format:expr, $($arg:expr),* $(,)?) => {{ $crate::g_print_inner!(g_print, $format, $($arg),*); }}; ($format:expr $(,)?) => {{ $crate::g_print_inner!(g_print, $format); }}; } /// Macro used to print error messages. It uses [g_printerr]. /// /// [g_printerr]: https://developer.gnome.org/glib/stable/glib-Warnings-and-Assertions.html#g-printerr /// /// Example: /// /// ```no_run /// use glib::g_printerr; /// /// g_printerr!("test"); /// // trailing commas work as well: /// g_printerr!("test",); /// /// let x = 12; /// g_printerr!("test: {}", x); /// g_printerr!("test: {} {}", x, "a"); /// // trailing commas work as well: /// g_printerr!("test: {} {}", x, "a",); /// ``` #[macro_export] macro_rules! g_printerr { ($format:expr $(,)?) => {{ $crate::g_print_inner!(g_printerr, $format); }}; ($format:expr, $($arg:expr),* $(,)?) => {{ $crate::g_print_inner!(g_printerr, $format, $($arg),*); }}; } // /// Macro used to log using GLib logging system. It uses [g_log_structured][gls]. // /// // /// [gls]: https://developer.gnome.org/glib/stable/glib-Message-Logging.html#g-log-structured) // /// // /// Example: // /// // /// ```no_run // /// use glib::{LogLevel, g_log_structured}; // /// // /// g_log_structured!("test", LogLevel::Debug, {"MESSAGE" => "tadam!"}); // /// g_log_structured!("test", LogLevel::Debug, {"MESSAGE" => "tadam!", "random" => "yes"}); // /// ``` // #[cfg(any(feature = "v2_50", feature = "dox"))] // #[macro_export] // macro_rules! g_log_structured { // ($log_domain:expr, $log_level:expr, {$($key:expr => $value:expr),+}) => {{ // use $crate::translate::{Stash, IntoGlib, ToGlibPtr}; // use $crate::LogLevel; // use std::ffi::CString; // fn check_log_args(_log_domain: &str, _log_level: LogLevel) {} // fn check_key(key: &str) -> Stash<*const i8, str> { key.to_glib_none() } // check_log_args(&$log_domain, $log_level); // unsafe { // ffi::g_log_structured( // $log_domain.to_glib_none().0, // $log_level.into_glib(), // $(check_key($key).0, check_key(format!("{}", $value).as_str()).0 ),+ // ) // } // }}; // } glib-0.14.8/src/main_context.rs000064400000000000000000000157430072674642500145220ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::source::Priority; use crate::translate::*; use crate::MainContext; use crate::Source; use crate::SourceId; use ffi::{self, gboolean, gpointer}; use std::mem; impl MainContext { #[doc(alias = "g_main_context_prepare")] pub fn prepare(&self) -> (bool, i32) { unsafe { let mut priority = mem::MaybeUninit::uninit(); let res = from_glib(ffi::g_main_context_prepare( self.to_glib_none().0, priority.as_mut_ptr(), )); let priority = priority.assume_init(); (res, priority) } } #[doc(alias = "g_main_context_find_source_by_id")] pub fn find_source_by_id(&self, source_id: &SourceId) -> Option { unsafe { from_glib_none(ffi::g_main_context_find_source_by_id( self.to_glib_none().0, source_id.as_raw(), )) } } /// Invokes `func` on the main context. pub fn invoke(&self, func: F) where F: FnOnce() + Send + 'static, { self.invoke_with_priority(crate::PRIORITY_DEFAULT_IDLE, func); } /// Invokes `func` on the main context with the given priority. pub fn invoke_with_priority(&self, priority: Priority, func: F) where F: FnOnce() + Send + 'static, { unsafe { self.invoke_unsafe(priority, func); } } /// Invokes `func` on the main context. /// /// Different to `invoke()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. pub fn invoke_local(&self, func: F) where F: FnOnce() + 'static, { self.invoke_local_with_priority(crate::PRIORITY_DEFAULT_IDLE, func); } /// Invokes `func` on the main context with the given priority. /// /// Different to `invoke_with_priority()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. pub fn invoke_local_with_priority(&self, priority: Priority, func: F) where F: FnOnce() + 'static, { unsafe { assert!(self.is_owner()); self.invoke_unsafe(priority, func); } } #[doc(alias = "g_main_context_invoke_full")] unsafe fn invoke_unsafe(&self, priority: Priority, func: F) where F: FnOnce() + 'static, { unsafe extern "C" fn trampoline(func: gpointer) -> gboolean { let func: &mut Option = &mut *(func as *mut Option); let func = func .take() .expect("MainContext::invoke() closure called multiple times"); func(); ffi::G_SOURCE_REMOVE } unsafe extern "C" fn destroy_closure(ptr: gpointer) { Box::>::from_raw(ptr as *mut _); } let func = Box::into_raw(Box::new(Some(func))); ffi::g_main_context_invoke_full( self.to_glib_none().0, priority.into_glib(), Some(trampoline::), func as gpointer, Some(destroy_closure::), ) } /// Calls closure with context configured as the thread default one. /// /// Thread default context is changed in panic-safe manner by calling /// [`push_thread_default`][push_thread_default] before calling closure /// and [`pop_thread_default`][pop_thread_default] afterwards regardless /// of whether closure panicked or not. /// /// [push_thread_default]: struct.MainContext.html#method.push_thread_default /// [pop_thread_default]: struct.MainContext.html#method.pop_thread_default pub fn with_thread_default(&self, func: F) -> R where F: FnOnce() -> R, { let _thread_default = ThreadDefaultContext::new(self); func() } #[doc(alias = "g_main_context_acquire")] pub fn acquire(&self) -> Result { unsafe { let ret: bool = from_glib(ffi::g_main_context_acquire(self.to_glib_none().0)); if ret { Ok(MainContextAcquireGuard(self)) } else { Err(bool_error!("Failed to acquire main context")) } } } } #[must_use = "if unused the main context will be released immediately"] pub struct MainContextAcquireGuard<'a>(&'a MainContext); impl<'a> Drop for MainContextAcquireGuard<'a> { #[doc(alias = "g_main_context_release")] fn drop(&mut self) { unsafe { ffi::g_main_context_release(self.0.to_glib_none().0); } } } struct ThreadDefaultContext<'a>(&'a MainContext); impl<'a> ThreadDefaultContext<'a> { fn new(ctx: &MainContext) -> ThreadDefaultContext { ctx.push_thread_default(); ThreadDefaultContext(ctx) } } impl<'a> Drop for ThreadDefaultContext<'a> { fn drop(&mut self) { self.0.pop_thread_default(); } } #[cfg(test)] mod tests { use super::*; use std::panic; use std::ptr; use std::thread; #[test] fn test_invoke() { let c = MainContext::new(); let l = crate::MainLoop::new(Some(&c), false); let l_clone = l.clone(); thread::spawn(move || { c.invoke(move || l_clone.quit()); }); l.run(); } fn is_same_context(a: &MainContext, b: &MainContext) -> bool { ptr::eq(a.to_glib_none().0, b.to_glib_none().0) } #[test] fn test_with_thread_default() { let a = MainContext::new(); let b = MainContext::new(); assert!(!is_same_context(&a, &b)); a.with_thread_default(|| { let t = MainContext::thread_default().unwrap(); assert!(is_same_context(&a, &t)); b.with_thread_default(|| { let t = MainContext::thread_default().unwrap(); assert!(is_same_context(&b, &t)); }); let t = MainContext::thread_default().unwrap(); assert!(is_same_context(&a, &t)); }); } #[test] fn test_with_thread_default_is_panic_safe() { let a = MainContext::new(); let b = MainContext::new(); assert!(!is_same_context(&a, &b)); a.with_thread_default(|| { let t = MainContext::thread_default().unwrap(); assert!(is_same_context(&a, &t)); let result = panic::catch_unwind(|| { b.with_thread_default(|| { panic!(); }); }); assert!(result.is_err()); let t = MainContext::thread_default().unwrap(); assert!(is_same_context(&a, &t)); }); } } glib-0.14.8/src/main_context_channel.rs000064400000000000000000000706030072674642500162060ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::{mut_override, FromGlibPtrFull, IntoGlib}; use crate::Continue; use crate::MainContext; use crate::Priority; use crate::Source; use crate::SourceId; use crate::ThreadGuard; use std::collections::VecDeque; use std::fmt; use std::mem; use std::ptr; use std::sync::mpsc; use std::sync::{Arc, Condvar, Mutex}; enum ChannelSourceState { NotAttached, Attached(*mut ffi::GSource), Destroyed, } unsafe impl Send for ChannelSourceState {} unsafe impl Sync for ChannelSourceState {} struct ChannelInner { queue: VecDeque, source: ChannelSourceState, num_senders: usize, } impl ChannelInner { fn receiver_disconnected(&self) -> bool { match self.source { ChannelSourceState::Destroyed => true, // Receiver exists but is already destroyed ChannelSourceState::Attached(source) if unsafe { ffi::g_source_is_destroyed(source) } != ffi::GFALSE => { true } // Not attached yet so the Receiver still exists ChannelSourceState::NotAttached => false, // Receiver still running ChannelSourceState::Attached(_) => false, } } #[doc(alias = "g_source_set_ready_time")] fn set_ready_time(&mut self, ready_time: i64) { if let ChannelSourceState::Attached(source) = self.source { unsafe { ffi::g_source_set_ready_time(source, ready_time); } } } } struct ChannelBound { bound: usize, cond: Condvar, } struct Channel(Arc<(Mutex>, Option)>); impl Clone for Channel { fn clone(&self) -> Channel { Channel(self.0.clone()) } } impl Channel { fn new(bound: Option) -> Channel { Channel(Arc::new(( Mutex::new(ChannelInner { queue: VecDeque::new(), source: ChannelSourceState::NotAttached, num_senders: 0, }), bound.map(|bound| ChannelBound { bound, cond: Condvar::new(), }), ))) } fn send(&self, t: T) -> Result<(), mpsc::SendError> { let mut inner = (self.0).0.lock().unwrap(); // If we have a bounded channel then we need to wait here until enough free space is // available or the receiver disappears // // A special case here is a bound of 0: the queue must be empty for accepting // new data and then we will again wait later for the data to be actually taken // out if let Some(ChannelBound { bound, ref cond }) = (self.0).1 { while inner.queue.len() >= bound && !inner.queue.is_empty() && !inner.receiver_disconnected() { inner = cond.wait(inner).unwrap(); } } // Error out directly if the receiver is disconnected if inner.receiver_disconnected() { return Err(mpsc::SendError(t)); } // Store the item on our queue inner.queue.push_back(t); // and then wake up the GSource inner.set_ready_time(0); // If we have a bound of 0 we need to wait until the receiver actually // handled the data if let Some(ChannelBound { bound: 0, ref cond }) = (self.0).1 { while !inner.queue.is_empty() && !inner.receiver_disconnected() { inner = cond.wait(inner).unwrap(); } // If the receiver was destroyed in the meantime take out the item and report an error if inner.receiver_disconnected() { // If the item is not in the queue anymore then the receiver just handled it before // getting disconnected and all is good if let Some(t) = inner.queue.pop_front() { return Err(mpsc::SendError(t)); } } } Ok(()) } fn try_send(&self, t: T) -> Result<(), mpsc::TrySendError> { let mut inner = (self.0).0.lock().unwrap(); let ChannelBound { bound, ref cond } = (self.0) .1 .as_ref() .expect("called try_send() on an unbounded channel"); // Check if the queue is full and handle the special case of a 0 bound if inner.queue.len() >= *bound && !inner.queue.is_empty() { return Err(mpsc::TrySendError::Full(t)); } // Error out directly if the receiver is disconnected if inner.receiver_disconnected() { return Err(mpsc::TrySendError::Disconnected(t)); } // Store the item on our queue inner.queue.push_back(t); // and then wake up the GSource inner.set_ready_time(0); // If we have a bound of 0 we need to wait until the receiver actually // handled the data if *bound == 0 { while !inner.queue.is_empty() && !inner.receiver_disconnected() { inner = cond.wait(inner).unwrap(); } // If the receiver was destroyed in the meantime take out the item and report an error if inner.receiver_disconnected() { // If the item is not in the queue anymore then the receiver just handled it before // getting disconnected and all is good if let Some(t) = inner.queue.pop_front() { return Err(mpsc::TrySendError::Disconnected(t)); } } } Ok(()) } fn try_recv(&self) -> Result { let mut inner = (self.0).0.lock().unwrap(); // Pop item if we have any if let Some(item) = inner.queue.pop_front() { // Wake up a sender that is currently waiting, if any if let Some(ChannelBound { ref cond, .. }) = (self.0).1 { cond.notify_one(); } return Ok(item); } // If there are no senders left we are disconnected or otherwise empty. That's the case if // the only remaining strong reference is the one of the receiver if inner.num_senders == 0 { Err(mpsc::TryRecvError::Disconnected) } else { Err(mpsc::TryRecvError::Empty) } } } #[repr(C)] struct ChannelSource Continue + 'static> { source: ffi::GSource, source_funcs: Option>, channel: Option>, callback: Option>, } unsafe extern "C" fn dispatch Continue + 'static>( source: *mut ffi::GSource, callback: ffi::GSourceFunc, _user_data: ffi::gpointer, ) -> ffi::gboolean { let source = &mut *(source as *mut ChannelSource); assert!(callback.is_none()); // Set ready-time to -1 so that we won't get called again before a new item is added // to the channel queue. ffi::g_source_set_ready_time(&mut source.source, -1); // Get a reference to the callback. This will panic if we're called from a different // thread than where the source was attached to the main context. let callback = source .callback .as_mut() .expect("ChannelSource called before Receiver was attached") .get_mut(); // Now iterate over all items that we currently have in the channel until it is // empty again. If all senders are disconnected at some point we remove the GSource // from the main context it was attached to as it will never ever be called again. let channel = source .channel .as_ref() .expect("ChannelSource without Channel"); loop { match channel.try_recv() { Err(mpsc::TryRecvError::Empty) => break, Err(mpsc::TryRecvError::Disconnected) => return ffi::G_SOURCE_REMOVE, Ok(item) => { if callback(item) == Continue(false) { return ffi::G_SOURCE_REMOVE; } } } } ffi::G_SOURCE_CONTINUE } #[cfg(feature = "v2_64")] unsafe extern "C" fn dispose Continue + 'static>(source: *mut ffi::GSource) { let source = &mut *(source as *mut ChannelSource); if let Some(ref channel) = source.channel { // Set the source inside the channel to None so that all senders know that there // is no receiver left and wake up the condition variable if any let mut inner = (channel.0).0.lock().unwrap(); inner.source = ChannelSourceState::Destroyed; if let Some(ChannelBound { ref cond, .. }) = (channel.0).1 { cond.notify_all(); } } } unsafe extern "C" fn finalize Continue + 'static>(source: *mut ffi::GSource) { let source = &mut *(source as *mut ChannelSource); // Drop all memory we own by taking it out of the Options #[cfg(feature = "v2_64")] { let _ = source.channel.take().expect("Receiver without channel"); } #[cfg(not(feature = "v2_64"))] { let channel = source.channel.take().expect("Receiver without channel"); // FIXME: This is the same as would otherwise be done in the dispose() function but // unfortunately it doesn't exist in older version of GLib. Doing it only here can // cause a channel sender to get a reference to the source with reference count 0 // if it happens just before the mutex is taken below. // // This is exactly the pattern why g_source_set_dispose_function() was added. // // Set the source inside the channel to None so that all senders know that there // is no receiver left and wake up the condition variable if any let mut inner = (channel.0).0.lock().unwrap(); inner.source = ChannelSourceState::Destroyed; if let Some(ChannelBound { ref cond, .. }) = (channel.0).1 { cond.notify_all(); } } let _ = source.source_funcs.take(); // Take the callback out of the source. This will panic if the value is dropped // from a different thread than where the callback was created let _ = source.callback.take(); } /// A `Sender` that can be used to send items to the corresponding main context receiver. /// /// This `Sender` behaves the same as `std::sync::mpsc::Sender`. /// /// See [`MainContext::channel()`] for how to create such a `Sender`. /// /// [`MainContext::channel()`]: struct.MainContext.html#method.channel pub struct Sender(Channel); impl fmt::Debug for Sender { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Sender").finish() } } impl Clone for Sender { fn clone(&self) -> Sender { Self::new(&self.0) } } impl Sender { fn new(channel: &Channel) -> Self { let mut inner = (channel.0).0.lock().unwrap(); inner.num_senders += 1; Self(channel.clone()) } /// Sends a value to the channel. pub fn send(&self, t: T) -> Result<(), mpsc::SendError> { self.0.send(t) } } impl Drop for Sender { fn drop(&mut self) { // Decrease the number of senders and wake up the channel if this // was the last sender that was dropped. let mut inner = ((self.0).0).0.lock().unwrap(); inner.num_senders -= 1; if inner.num_senders == 0 { inner.set_ready_time(0); } } } /// A `SyncSender` that can be used to send items to the corresponding main context receiver. /// /// This `SyncSender` behaves the same as `std::sync::mpsc::SyncSender`. /// /// See [`MainContext::sync_channel()`] for how to create such a `SyncSender`. /// /// [`MainContext::sync_channel()`]: struct.MainContext.html#method.sync_channel pub struct SyncSender(Channel); impl fmt::Debug for SyncSender { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("SyncSender").finish() } } impl Clone for SyncSender { fn clone(&self) -> SyncSender { Self::new(&self.0) } } impl SyncSender { fn new(channel: &Channel) -> Self { let mut inner = (channel.0).0.lock().unwrap(); inner.num_senders += 1; Self(channel.clone()) } /// Sends a value to the channel and blocks if the channel is full. pub fn send(&self, t: T) -> Result<(), mpsc::SendError> { self.0.send(t) } /// Sends a value to the channel. pub fn try_send(&self, t: T) -> Result<(), mpsc::TrySendError> { self.0.try_send(t) } } impl Drop for SyncSender { fn drop(&mut self) { // Decrease the number of senders and wake up the channel if this // was the last sender that was dropped. let mut inner = ((self.0).0).0.lock().unwrap(); inner.num_senders -= 1; if inner.num_senders == 0 { inner.set_ready_time(0); } } } /// A `Receiver` that can be attached to a main context to receive items from its corresponding /// `Sender` or `SyncSender`. /// /// See [`MainContext::channel()`] or [`MainContext::sync_channel()`] for how to create /// such a `Receiver`. /// /// [`MainContext::channel()`]: struct.MainContext.html#method.channel /// [`MainContext::sync_channel()`]: struct.MainContext.html#method.sync_channel pub struct Receiver(Option>, Priority); impl fmt::Debug for Receiver { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Receiver").finish() } } // It's safe to send the Receiver to other threads for attaching it as // long as the items to be sent can also be sent between threads. unsafe impl Send for Receiver {} impl Drop for Receiver { fn drop(&mut self) { // If the receiver was never attached to a main context we need to let all the senders know if let Some(channel) = self.0.take() { let mut inner = (channel.0).0.lock().unwrap(); inner.source = ChannelSourceState::Destroyed; if let Some(ChannelBound { ref cond, .. }) = (channel.0).1 { cond.notify_all(); } } } } impl Receiver { /// Attaches the receiver to the given `context` and calls `func` whenever an item is /// available on the channel. /// /// Passing `None` for the context will attach it to the thread default main context. /// /// # Panics /// /// This function panics if called from a thread that is not the owner of the provided /// `context`, or, if `None` is provided, of the thread default main context. pub fn attach Continue + 'static>( mut self, context: Option<&MainContext>, func: F, ) -> SourceId { unsafe { let channel = self.0.take().expect("Receiver without channel"); let source_funcs = Box::new(ffi::GSourceFuncs { check: None, prepare: None, dispatch: Some(dispatch::), finalize: Some(finalize::), closure_callback: None, closure_marshal: None, }); let source = ffi::g_source_new( mut_override(&*source_funcs), mem::size_of::>() as u32, ) as *mut ChannelSource; assert!(!source.is_null()); #[cfg(feature = "v2_64")] { ffi::g_source_set_dispose_function( source as *mut ffi::GSource, Some(dispose::), ); } // Set up the GSource { let source = &mut *source; let mut inner = (channel.0).0.lock().unwrap(); ffi::g_source_set_priority(mut_override(&source.source), self.1.into_glib()); // We're immediately ready if the queue is not empty or if no sender is left at this point ffi::g_source_set_ready_time( mut_override(&source.source), if !inner.queue.is_empty() || inner.num_senders == 0 { 0 } else { -1 }, ); inner.source = ChannelSourceState::Attached(&mut source.source); } // Store all our data inside our part of the GSource { let source = &mut *source; ptr::write(&mut source.channel, Some(channel)); ptr::write(&mut source.callback, Some(ThreadGuard::new(func))); ptr::write(&mut source.source_funcs, Some(source_funcs)); } let source = Source::from_glib_full(mut_override(&(*source).source)); if let Some(context) = context { assert!(context.is_owner()); source.attach(Some(context)) } else { let context = MainContext::ref_thread_default(); assert!(context.is_owner()); source.attach(Some(&context)) } } } } impl MainContext { /// Creates a channel for a main context. /// /// The `Receiver` has to be attached to a main context at a later time, together with a /// closure that will be called for every item sent to a `Sender`. /// /// The `Sender` can be cloned and both the `Sender` and `Receiver` can be sent to different /// threads as long as the item type implements the `Send` trait. /// /// When the last `Sender` is dropped the channel is removed from the main context. If the /// `Receiver` is dropped and not attached to a main context all sending to the `Sender` /// will fail. /// /// The returned `Sender` behaves the same as `std::sync::mpsc::Sender`. pub fn channel(priority: Priority) -> (Sender, Receiver) { let channel = Channel::new(None); let receiver = Receiver(Some(channel.clone()), priority); let sender = Sender::new(&channel); (sender, receiver) } /// Creates a synchronous channel for a main context with a given bound on the capacity of the /// channel. /// /// The `Receiver` has to be attached to a main context at a later time, together with a /// closure that will be called for every item sent to a `SyncSender`. /// /// The `SyncSender` can be cloned and both the `SyncSender` and `Receiver` can be sent to different /// threads as long as the item type implements the `Send` trait. /// /// When the last `SyncSender` is dropped the channel is removed from the main context. If the /// `Receiver` is dropped and not attached to a main context all sending to the `SyncSender` /// will fail. /// /// The returned `SyncSender` behaves the same as `std::sync::mpsc::SyncSender`. pub fn sync_channel(priority: Priority, bound: usize) -> (SyncSender, Receiver) { let channel = Channel::new(Some(bound)); let receiver = Receiver(Some(channel.clone()), priority); let sender = SyncSender::new(&channel); (sender, receiver) } } #[cfg(test)] mod tests { use super::*; use crate::MainLoop; use std::cell::RefCell; use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; use std::thread; use std::time; #[test] fn test_channel() { let c = MainContext::new(); let l = MainLoop::new(Some(&c), false); let _guard = c.acquire().unwrap(); let (sender, receiver) = MainContext::channel(Priority::default()); let sum = Rc::new(RefCell::new(0)); let sum_clone = sum.clone(); let l_clone = l.clone(); receiver.attach(Some(&c), move |item| { *sum_clone.borrow_mut() += item; if *sum_clone.borrow() == 6 { l_clone.quit(); Continue(false) } else { Continue(true) } }); sender.send(1).unwrap(); sender.send(2).unwrap(); sender.send(3).unwrap(); l.run(); assert_eq!(*sum.borrow(), 6); } #[test] fn test_drop_sender() { let c = MainContext::new(); let l = MainLoop::new(Some(&c), false); let _guard = c.acquire().unwrap(); let (sender, receiver) = MainContext::channel::(Priority::default()); struct Helper(MainLoop); impl Drop for Helper { fn drop(&mut self) { self.0.quit(); } } let helper = Helper(l.clone()); receiver.attach(Some(&c), move |_| { let _ = helper; Continue(true) }); drop(sender); l.run(); } #[test] fn test_drop_receiver() { let (sender, receiver) = MainContext::channel::(Priority::default()); drop(receiver); assert_eq!(sender.send(1), Err(mpsc::SendError(1))); } #[test] fn test_remove_receiver() { let c = MainContext::new(); let _guard = c.acquire().unwrap(); let (sender, receiver) = MainContext::channel::(Priority::default()); let source_id = receiver.attach(Some(&c), move |_| Continue(true)); let source = c.find_source_by_id(&source_id).unwrap(); source.destroy(); assert_eq!(sender.send(1), Err(mpsc::SendError(1))); } #[test] fn test_remove_receiver_and_drop_source() { let c = MainContext::new(); let _guard = c.acquire().unwrap(); let (sender, receiver) = MainContext::channel::(Priority::default()); struct Helper(Arc); impl Drop for Helper { fn drop(&mut self) { self.0.store(true, Ordering::Relaxed); } } let dropped = Arc::new(AtomicBool::new(false)); let helper = Helper(dropped.clone()); let source_id = receiver.attach(Some(&c), move |_| { let _helper = &helper; Continue(true) }); let source = c.find_source_by_id(&source_id).unwrap(); source.destroy(); // This should drop the closure drop(source); assert!(dropped.load(Ordering::Relaxed)); assert_eq!(sender.send(1), Err(mpsc::SendError(1))); } #[test] fn test_sync_channel() { let c = MainContext::new(); let l = MainLoop::new(Some(&c), false); let _guard = c.acquire().unwrap(); let (sender, receiver) = MainContext::sync_channel(Priority::default(), 2); let sum = Rc::new(RefCell::new(0)); let sum_clone = sum.clone(); let l_clone = l.clone(); receiver.attach(Some(&c), move |item| { *sum_clone.borrow_mut() += item; if *sum_clone.borrow() == 6 { l_clone.quit(); Continue(false) } else { Continue(true) } }); let (wait_sender, wait_receiver) = mpsc::channel(); let thread = thread::spawn(move || { // The first two must succeed sender.try_send(1).unwrap(); sender.try_send(2).unwrap(); // This fill up the channel assert!(sender.try_send(3).is_err()); wait_sender.send(()).unwrap(); // This will block sender.send(3).unwrap(); }); // Wait until the channel is full, and then another // 50ms to make sure the sender is blocked now and // can wake up properly once an item was consumed assert!(wait_receiver.recv().is_ok()); thread::sleep(time::Duration::from_millis(50)); l.run(); thread.join().unwrap(); assert_eq!(*sum.borrow(), 6); } #[test] fn test_sync_channel_drop_wakeup() { let c = MainContext::new(); let l = MainLoop::new(Some(&c), false); let _guard = c.acquire().unwrap(); let (sender, receiver) = MainContext::sync_channel(Priority::default(), 3); let sum = Rc::new(RefCell::new(0)); let sum_clone = sum.clone(); let l_clone = l.clone(); receiver.attach(Some(&c), move |item| { *sum_clone.borrow_mut() += item; if *sum_clone.borrow() == 6 { l_clone.quit(); Continue(false) } else { Continue(true) } }); let (wait_sender, wait_receiver) = mpsc::channel(); let thread = thread::spawn(move || { // The first three must succeed sender.try_send(1).unwrap(); sender.try_send(2).unwrap(); sender.try_send(3).unwrap(); wait_sender.send(()).unwrap(); for i in 4.. { // This will block at some point until the // receiver is removed from the main context if sender.send(i).is_err() { break; } } }); // Wait until the channel is full, and then another // 50ms to make sure the sender is blocked now and // can wake up properly once an item was consumed assert!(wait_receiver.recv().is_ok()); thread::sleep(time::Duration::from_millis(50)); l.run(); thread.join().unwrap(); assert_eq!(*sum.borrow(), 6); } #[test] fn test_sync_channel_drop_receiver_wakeup() { let c = MainContext::new(); let _guard = c.acquire().unwrap(); let (sender, receiver) = MainContext::sync_channel(Priority::default(), 2); let (wait_sender, wait_receiver) = mpsc::channel(); let thread = thread::spawn(move || { // The first two must succeed sender.try_send(1).unwrap(); sender.try_send(2).unwrap(); wait_sender.send(()).unwrap(); // This will block and then error out because the receiver is destroyed assert!(sender.send(3).is_err()); }); // Wait until the channel is full, and then another // 50ms to make sure the sender is blocked now and // can wake up properly once an item was consumed assert!(wait_receiver.recv().is_ok()); thread::sleep(time::Duration::from_millis(50)); drop(receiver); thread.join().unwrap(); } #[test] fn test_sync_channel_rendezvous() { let c = MainContext::new(); let l = MainLoop::new(Some(&c), false); let _guard = c.acquire().unwrap(); let (sender, receiver) = MainContext::sync_channel(Priority::default(), 0); let (wait_sender, wait_receiver) = mpsc::channel(); let thread = thread::spawn(move || { wait_sender.send(()).unwrap(); sender.send(1).unwrap(); wait_sender.send(()).unwrap(); sender.send(2).unwrap(); wait_sender.send(()).unwrap(); sender.send(3).unwrap(); wait_sender.send(()).unwrap(); }); // Wait until the thread is started, then wait another 50ms and // during that time it must not have proceeded yet to send the // second item because we did not yet receive the first item. assert!(wait_receiver.recv().is_ok()); assert_eq!( wait_receiver.recv_timeout(time::Duration::from_millis(50)), Err(mpsc::RecvTimeoutError::Timeout) ); let sum = Rc::new(RefCell::new(0)); let sum_clone = sum.clone(); let l_clone = l.clone(); receiver.attach(Some(&c), move |item| { // We consumed one item so there should be one item on // the other receiver now. assert!(wait_receiver.recv().is_ok()); *sum_clone.borrow_mut() += item; if *sum_clone.borrow() == 6 { // But as we didn't consume the next one yet, there must be no // other item available yet assert_eq!( wait_receiver.recv_timeout(time::Duration::from_millis(50)), Err(mpsc::RecvTimeoutError::Disconnected) ); l_clone.quit(); Continue(false) } else { // But as we didn't consume the next one yet, there must be no // other item available yet assert_eq!( wait_receiver.recv_timeout(time::Duration::from_millis(50)), Err(mpsc::RecvTimeoutError::Timeout) ); Continue(true) } }); l.run(); thread.join().unwrap(); assert_eq!(*sum.borrow(), 6); } } glib-0.14.8/src/main_context_futures.rs000064400000000000000000000307770072674642500163030ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::{from_glib_borrow, from_glib_full, mut_override, Borrowed, IntoGlib}; use crate::ThreadGuard; use futures_core::future::Future; use futures_core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; use futures_task::{FutureObj, LocalFutureObj, LocalSpawn, Spawn, SpawnError}; use std::mem; use std::pin::{self, Pin}; use std::ptr; use crate::MainContext; use crate::MainLoop; use crate::Priority; use crate::Source; // Wrapper around Send Futures and non-Send Futures that will panic // if the non-Send Future is polled/dropped from a different thread // than where this was created. enum FutureWrapper { Send(FutureObj<'static, ()>), NonSend(ThreadGuard>), } impl Future for FutureWrapper { type Output = (); fn poll(self: pin::Pin<&mut Self>, ctx: &mut Context) -> Poll<()> { match self.get_mut() { FutureWrapper::Send(fut) => Pin::new(fut).poll(ctx), FutureWrapper::NonSend(fut) => Pin::new(fut.get_mut()).poll(ctx), } } } // The TaskSource and WakerSource are split up as the TaskSource // must only be finalized on the thread that owns the main context, // but the WakerSource is passed around to arbitrary threads for // being able to wake up the TaskSource. // // The WakerSource is set up as a child source of the TaskSource, i.e. // whenever it is ready also the TaskSource is ready. #[repr(C)] struct TaskSource { source: ffi::GSource, future: FutureWrapper, waker: Waker, } #[repr(C)] struct WakerSource { source: ffi::GSource, } impl TaskSource { unsafe extern "C" fn dispatch( source: *mut ffi::GSource, callback: ffi::GSourceFunc, _user_data: ffi::gpointer, ) -> ffi::gboolean { let source = &mut *(source as *mut TaskSource); assert!(callback.is_none()); // Poll the TaskSource and ensure we're never called again if the // contained Future resolved now. if let Poll::Ready(()) = source.poll() { ffi::G_SOURCE_REMOVE } else { ffi::G_SOURCE_CONTINUE } } unsafe extern "C" fn finalize(source: *mut ffi::GSource) { let source = source as *mut TaskSource; // This will panic if the future was a local future and is dropped from // a different thread than where it was created. ptr::drop_in_place(&mut (*source).future); // Drop the waker to unref the underlying GSource ptr::drop_in_place(&mut (*source).waker); } } impl WakerSource { unsafe fn clone_raw(waker: *const ()) -> RawWaker { static VTABLE: RawWakerVTable = RawWakerVTable::new( WakerSource::clone_raw, WakerSource::wake_raw, WakerSource::wake_by_ref_raw, WakerSource::drop_raw, ); let waker = waker as *const ffi::GSource; ffi::g_source_ref(mut_override(waker)); RawWaker::new(waker as *const (), &VTABLE) } unsafe fn wake_raw(waker: *const ()) { Self::wake_by_ref_raw(waker); Self::drop_raw(waker); } unsafe fn wake_by_ref_raw(waker: *const ()) { let waker = waker as *const ffi::GSource; ffi::g_source_set_ready_time(mut_override(waker), 0); } unsafe fn drop_raw(waker: *const ()) { let waker = waker as *const ffi::GSource; ffi::g_source_unref(mut_override(waker)); } unsafe extern "C" fn dispatch( source: *mut ffi::GSource, _callback: ffi::GSourceFunc, _user_data: ffi::gpointer, ) -> ffi::gboolean { // Set ready-time to -1 so that we're not called again before // being woken up another time. ffi::g_source_set_ready_time(mut_override(source), -1); ffi::G_SOURCE_CONTINUE } } unsafe impl Send for TaskSource {} unsafe impl Sync for TaskSource {} unsafe impl Send for WakerSource {} unsafe impl Sync for WakerSource {} impl TaskSource { #[allow(clippy::new_ret_no_self)] #[doc(alias = "g_source_new")] fn new(priority: Priority, future: FutureWrapper) -> Source { unsafe { static TASK_SOURCE_FUNCS: ffi::GSourceFuncs = ffi::GSourceFuncs { check: None, prepare: None, dispatch: Some(TaskSource::dispatch), finalize: Some(TaskSource::finalize), closure_callback: None, closure_marshal: None, }; static WAKER_SOURCE_FUNCS: ffi::GSourceFuncs = ffi::GSourceFuncs { check: None, prepare: None, dispatch: Some(WakerSource::dispatch), finalize: None, closure_callback: None, closure_marshal: None, }; let source = ffi::g_source_new( mut_override(&TASK_SOURCE_FUNCS), mem::size_of::() as u32, ); let waker_source = ffi::g_source_new( mut_override(&WAKER_SOURCE_FUNCS), mem::size_of::() as u32, ); ffi::g_source_set_priority(source, priority.into_glib()); ffi::g_source_add_child_source(source, waker_source); { let source = &mut *(source as *mut TaskSource); ptr::write(&mut source.future, future); // This creates a new reference to the waker source. let waker = Waker::from_raw(WakerSource::clone_raw(waker_source as *const ())); ptr::write(&mut source.waker, waker); } // Set ready time to 0 so that the source is immediately dispatched // for doing the initial polling. This will then either resolve the // future or register the waker wherever necessary. ffi::g_source_set_ready_time(waker_source, 0); // Unref the waker source, a strong reference to it is stored inside // the task source directly and inside the task source as child source. ffi::g_source_unref(waker_source); from_glib_full(source) } } fn poll(&mut self) -> Poll<()> { let source = &self.source as *const _; let executor: Borrowed = unsafe { from_glib_borrow(ffi::g_source_get_context(mut_override(source))) }; assert!( executor.is_owner(), "Polling futures only allowed if the thread is owning the MainContext" ); executor.with_thread_default(|| { let _enter = futures_executor::enter().unwrap(); let mut context = Context::from_waker(&self.waker); // This will panic if the future was a local future and is called from // a different thread than where it was created. Pin::new(&mut self.future).poll(&mut context) }) } } impl MainContext { /// Spawn a new infallible `Future` on the main context. /// /// This can be called from any thread and will execute the future from the thread /// where main context is running, e.g. via a `MainLoop`. pub fn spawn + Send + 'static>(&self, f: F) { self.spawn_with_priority(crate::PRIORITY_DEFAULT, f); } /// Spawn a new infallible `Future` on the main context. /// /// The given `Future` does not have to be `Send`. /// /// This can be called only from the thread where the main context is running, e.g. /// from any other `Future` that is executed on this main context, or after calling /// `push_thread_default` or `acquire` on the main context. pub fn spawn_local + 'static>(&self, f: F) { self.spawn_local_with_priority(crate::PRIORITY_DEFAULT, f); } /// Spawn a new infallible `Future` on the main context, with a non-default priority. /// /// This can be called from any thread and will execute the future from the thread /// where main context is running, e.g. via a `MainLoop`. pub fn spawn_with_priority + Send + 'static>( &self, priority: Priority, f: F, ) { let f = FutureObj::new(Box::new(f)); let source = TaskSource::new(priority, FutureWrapper::Send(f)); source.attach(Some(&*self)); } /// Spawn a new infallible `Future` on the main context, with a non-default priority. /// /// The given `Future` does not have to be `Send`. /// /// This can be called only from the thread where the main context is running, e.g. /// from any other `Future` that is executed on this main context, or after calling /// `push_thread_default` or `acquire` on the main context. pub fn spawn_local_with_priority + 'static>( &self, priority: Priority, f: F, ) { assert!( self.is_owner(), "Spawning local futures only allowed on the thread owning the MainContext" ); let f = LocalFutureObj::new(Box::new(f)); let source = TaskSource::new(priority, FutureWrapper::NonSend(ThreadGuard::new(f))); source.attach(Some(&*self)); } /// Runs a new, infallible `Future` on the main context and block until it finished, returning /// the result of the `Future`. /// /// The given `Future` does not have to be `Send` or `'static`. /// /// This must only be called if no `MainLoop` or anything else is running on this specific main /// context. #[allow(clippy::transmute_ptr_to_ptr)] pub fn block_on(&self, f: F) -> F::Output { let mut res = None; let l = MainLoop::new(Some(&*self), false); let l_clone = l.clone(); let f = async { res = Some(f.await); l_clone.quit(); }; unsafe { // Super-unsafe: We transmute here to get rid of the 'static lifetime let f = LocalFutureObj::new(Box::new(f)); let f: LocalFutureObj<'static, ()> = mem::transmute(f); let source = TaskSource::new( crate::PRIORITY_DEFAULT, FutureWrapper::NonSend(ThreadGuard::new(f)), ); source.attach(Some(&*self)); } l.run(); res.unwrap() } } impl Spawn for MainContext { fn spawn_obj(&self, f: FutureObj<'static, ()>) -> Result<(), SpawnError> { let source = TaskSource::new(crate::PRIORITY_DEFAULT, FutureWrapper::Send(f)); source.attach(Some(&*self)); Ok(()) } } impl LocalSpawn for MainContext { fn spawn_local_obj(&self, f: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> { let source = TaskSource::new( crate::PRIORITY_DEFAULT, FutureWrapper::NonSend(ThreadGuard::new(f)), ); source.attach(Some(&*self)); Ok(()) } } #[cfg(test)] mod tests { use super::*; use futures_channel::oneshot; use futures_util::future::{FutureExt, TryFutureExt}; use std::sync::mpsc; use std::thread; #[test] fn test_spawn() { let c = MainContext::new(); let l = crate::MainLoop::new(Some(&c), false); let (sender, receiver) = mpsc::channel(); let (o_sender, o_receiver) = oneshot::channel(); let l_clone = l.clone(); c.spawn( o_receiver .and_then(move |()| { sender.send(()).unwrap(); l_clone.quit(); futures_util::future::ok(()) }) .then(|res| { assert!(res.is_ok()); futures_util::future::ready(()) }), ); thread::spawn(move || { l.run(); }); o_sender.send(()).unwrap(); receiver.recv().unwrap(); } #[test] fn test_spawn_local() { let c = MainContext::new(); let l = crate::MainLoop::new(Some(&c), false); c.push_thread_default(); let l_clone = l.clone(); c.spawn_local(futures_util::future::lazy(move |_ctx| { l_clone.quit(); })); l.run(); c.pop_thread_default(); } #[test] fn test_block_on() { let c = MainContext::new(); let mut v = None; { let v = &mut v; let future = futures_util::future::lazy(|_ctx| { *v = Some(123); Ok::(123) }); let res = c.block_on(future); assert_eq!(res, Ok(123)); } assert_eq!(v, Some(123)); } } glib-0.14.8/src/object.rs000064400000000000000000003117120072674642500132730ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! `IMPL` Object wrapper implementation and `Object` binding. use crate::translate::*; use crate::types::StaticType; use crate::{quark::Quark, subclass::signal::SignalQuery}; use std::cmp; use std::fmt; use std::hash; use std::marker::PhantomData; use std::mem; use std::ops; use std::pin::Pin; use std::ptr; use crate::subclass::{prelude::ObjectSubclass, SignalId}; use crate::value::ToValue; use crate::BoolError; use crate::Closure; use crate::SignalHandlerId; use crate::Type; use crate::Value; use crate::thread_id; #[doc(hidden)] pub use gobject_ffi::GObject; #[doc(hidden)] pub use gobject_ffi::GObjectClass; /// Implemented by types representing `glib::Object` and subclasses of it. pub unsafe trait ObjectType: UnsafeFrom + Into + StaticType + fmt::Debug + Clone + PartialEq + Eq + PartialOrd + Ord + hash::Hash + crate::value::ValueType + crate::value::ToValue + crate::value::ToValueOptional + crate::value::FromValueOptional<'static> + for<'a> ToGlibPtr<'a, *mut ::GlibType> + 'static { /// type of the FFI Instance structure. type GlibType: 'static; /// type of the FFI Class structure. type GlibClassType: 'static; fn as_object_ref(&self) -> &ObjectRef; fn as_ptr(&self) -> *mut Self::GlibType; } /// Unsafe variant of the `From` trait. pub trait UnsafeFrom { /// # Safety /// /// It is the responsibility of the caller to ensure *all* invariants of /// the `T` hold before this is called, and that after conversion /// to assume nothing other than the invariants of the output. Implementors /// of this must ensure that the invariants of the output type hold. unsafe fn unsafe_from(t: T) -> Self; } /// Declares the "is a" relationship. /// /// `Self` is said to implement `T`. /// /// For instance, since originally `GtkWidget` is a subclass of `GObject` and /// implements the `GtkBuildable` interface, `gtk::Widget` implements /// `IsA` and `IsA`. /// /// /// The trait can only be implemented if the appropriate `ToGlibPtr` /// implementations exist. pub unsafe trait IsA: ObjectType + AsRef + 'static {} /// Upcasting and downcasting support. /// /// Provides conversions up and down the class hierarchy tree. pub trait Cast: ObjectType { /// Upcasts an object to a superclass or interface `T`. /// /// *NOTE*: This statically checks at compile-time if casting is possible. It is not always /// known at compile-time, whether a specific object implements an interface or not, in which case /// `upcast` would fail to compile. `dynamic_cast` can be used in these circumstances, which /// is checking the types at runtime. /// /// # Example /// /// ```ignore /// let button = gtk::Button::new(); /// let widget = button.upcast::(); /// ``` #[inline] fn upcast(self) -> T where Self: IsA, { unsafe { self.unsafe_cast() } } /// Upcasts an object to a reference of its superclass or interface `T`. /// /// *NOTE*: This statically checks at compile-time if casting is possible. It is not always /// known at compile-time, whether a specific object implements an interface or not, in which case /// `upcast` would fail to compile. `dynamic_cast` can be used in these circumstances, which /// is checking the types at runtime. /// /// # Example /// /// ```ignore /// let button = gtk::Button::new(); /// let widget = button.upcast_ref::(); /// ``` #[inline] fn upcast_ref(&self) -> &T where Self: IsA, { unsafe { self.unsafe_cast_ref() } } /// Tries to downcast to a subclass or interface implementor `T`. /// /// Returns `Ok(T)` if the object is an instance of `T` and `Err(self)` /// otherwise. /// /// *NOTE*: This statically checks at compile-time if casting is possible. It is not always /// known at compile-time, whether a specific object implements an interface or not, in which case /// `upcast` would fail to compile. `dynamic_cast` can be used in these circumstances, which /// is checking the types at runtime. /// /// # Example /// /// ```ignore /// let button = gtk::Button::new(); /// let widget = button.upcast::(); /// assert!(widget.downcast::().is_ok()); /// ``` #[inline] fn downcast(self) -> Result where Self: CanDowncast, { if self.is::() { Ok(unsafe { self.unsafe_cast() }) } else { Err(self) } } /// Tries to downcast to a reference of its subclass or interface implementor `T`. /// /// Returns `Some(T)` if the object is an instance of `T` and `None` /// otherwise. /// /// *NOTE*: This statically checks at compile-time if casting is possible. It is not always /// known at compile-time, whether a specific object implements an interface or not, in which case /// `upcast` would fail to compile. `dynamic_cast` can be used in these circumstances, which /// is checking the types at runtime. /// /// # Example /// /// ```ignore /// let button = gtk::Button::new(); /// let widget = button.upcast::(); /// assert!(widget.downcast_ref::().is_some()); /// ``` #[inline] fn downcast_ref(&self) -> Option<&T> where Self: CanDowncast, { if self.is::() { Some(unsafe { self.unsafe_cast_ref() }) } else { None } } /// Tries to cast to an object of type `T`. This handles upcasting, downcasting /// and casting between interface and interface implementors. All checks are performed at /// runtime, while `downcast` and `upcast` will do many checks at compile-time already. /// /// It is not always known at compile-time, whether a specific object implements an interface or /// not, and checking as to be performed at runtime. /// /// Returns `Ok(T)` if the object is an instance of `T` and `Err(self)` /// otherwise. /// /// # Example /// /// ```ignore /// let button = gtk::Button::new(); /// let widget = button.dynamic_cast::(); /// assert!(widget.is_ok()); /// let widget = widget.unwrap(); /// assert!(widget.dynamic_cast::().is_ok()); /// ``` #[inline] fn dynamic_cast(self) -> Result { if !self.is::() { Err(self) } else { Ok(unsafe { self.unsafe_cast() }) } } /// Tries to cast to reference to an object of type `T`. This handles upcasting, downcasting /// and casting between interface and interface implementors. All checks are performed at /// runtime, while `downcast` and `upcast` will do many checks at compile-time already. /// /// It is not always known at compile-time, whether a specific object implements an interface or /// not, and checking as to be performed at runtime. /// /// Returns `Some(T)` if the object is an instance of `T` and `None` /// otherwise. /// /// # Example /// /// ```ignore /// let button = gtk::Button::new(); /// let widget = button.dynamic_cast_ref::(); /// assert!(widget.is_some()); /// let widget = widget.unwrap(); /// assert!(widget.dynamic_cast_ref::().is_some()); /// ``` #[inline] fn dynamic_cast_ref(&self) -> Option<&T> { if !self.is::() { None } else { // This cast is safe because all our wrapper types have the // same representation except for the name and the phantom data // type. IsA<> is an unsafe trait that must only be implemented // if this is a valid wrapper type Some(unsafe { self.unsafe_cast_ref() }) } } /// Casts to `T` unconditionally. /// /// # Panics /// /// Panics if compiled with `debug_assertions` and the instance doesn't implement `T`. /// /// # Safety /// /// If not running with `debug_assertions` enabled, the caller is responsible /// for ensuring that the instance implements `T` unsafe fn unsafe_cast(self) -> T { debug_assert!(self.is::()); T::unsafe_from(self.into()) } /// Casts to `&T` unconditionally. /// /// # Panics /// /// Panics if compiled with `debug_assertions` and the instance doesn't implement `T`. /// /// # Safety /// /// If not running with `debug_assertions` enabled, the caller is responsible /// for ensuring that the instance implements `T` unsafe fn unsafe_cast_ref(&self) -> &T { debug_assert!(self.is::()); // This cast is safe because all our wrapper types have the // same representation except for the name and the phantom data // type. IsA<> is an unsafe trait that must only be implemented // if this is a valid wrapper type &*(self as *const Self as *const T) } } impl Cast for T {} /// Marker trait for the statically known possibility of downcasting from `Self` to `T`. pub trait CanDowncast {} impl, Sub: IsA> CanDowncast for Super {} // Manual implementation of glib_shared_wrapper! because of special cases pub struct ObjectRef { inner: ptr::NonNull, } impl Clone for ObjectRef { fn clone(&self) -> Self { unsafe { Self { inner: ptr::NonNull::new_unchecked(gobject_ffi::g_object_ref(self.inner.as_ptr())), } } } } impl Drop for ObjectRef { fn drop(&mut self) { unsafe { gobject_ffi::g_object_unref(self.inner.as_ptr()); } } } impl fmt::Debug for ObjectRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let type_ = unsafe { let klass = (*self.inner.as_ptr()).g_type_instance.g_class as *const ObjectClass; (&*klass).type_() }; f.debug_struct("ObjectRef") .field("inner", &self.inner) .field("type", &type_) .finish() } } impl PartialOrd for ObjectRef { fn partial_cmp(&self, other: &Self) -> Option { self.inner.partial_cmp(&other.inner) } } impl Ord for ObjectRef { fn cmp(&self, other: &Self) -> cmp::Ordering { self.inner.cmp(&other.inner) } } impl PartialEq for ObjectRef { fn eq(&self, other: &Self) -> bool { self.inner == other.inner } } impl Eq for ObjectRef {} impl hash::Hash for ObjectRef { fn hash(&self, state: &mut H) where H: hash::Hasher, { self.inner.hash(state) } } #[doc(hidden)] impl GlibPtrDefault for ObjectRef { type GlibType = *mut GObject; } #[doc(hidden)] impl<'a> ToGlibPtr<'a, *mut GObject> for ObjectRef { type Storage = &'a ObjectRef; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut GObject, Self> { Stash(self.inner.as_ptr(), self) } #[inline] fn to_glib_full(&self) -> *mut GObject { unsafe { gobject_ffi::g_object_ref(self.inner.as_ptr()) } } } #[doc(hidden)] impl<'a> ToGlibContainerFromSlice<'a, *mut *mut GObject> for ObjectRef { type Storage = ( Vec>, Option>, ); fn to_glib_none_from_slice(t: &'a [ObjectRef]) -> (*mut *mut GObject, Self::Storage) { let v: Vec<_> = t.iter().map(|s| s.to_glib_none()).collect(); let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect(); v_ptr.push(ptr::null_mut() as *mut GObject); (v_ptr.as_ptr() as *mut *mut GObject, (v, Some(v_ptr))) } fn to_glib_container_from_slice(t: &'a [ObjectRef]) -> (*mut *mut GObject, Self::Storage) { let v: Vec<_> = t.iter().map(|s| s.to_glib_none()).collect(); let v_ptr = unsafe { let v_ptr = ffi::g_malloc0(mem::size_of::<*mut GObject>() * (t.len() + 1)) as *mut *mut GObject; for (i, s) in v.iter().enumerate() { ptr::write(v_ptr.add(i), s.0); } v_ptr }; (v_ptr, (v, None)) } fn to_glib_full_from_slice(t: &[ObjectRef]) -> *mut *mut GObject { unsafe { let v_ptr = ffi::g_malloc0(std::mem::size_of::<*mut GObject>() * (t.len() + 1)) as *mut *mut GObject; for (i, s) in t.iter().enumerate() { ptr::write(v_ptr.add(i), s.to_glib_full()); } v_ptr } } } #[doc(hidden)] impl<'a> ToGlibContainerFromSlice<'a, *const *mut GObject> for ObjectRef { type Storage = ( Vec>, Option>, ); fn to_glib_none_from_slice(t: &'a [ObjectRef]) -> (*const *mut GObject, Self::Storage) { let (ptr, stash) = ToGlibContainerFromSlice::<'a, *mut *mut GObject>::to_glib_none_from_slice(t); (ptr as *const *mut GObject, stash) } fn to_glib_container_from_slice(_: &'a [ObjectRef]) -> (*const *mut GObject, Self::Storage) { // Can't have consumer free a *const pointer unimplemented!() } fn to_glib_full_from_slice(_: &[ObjectRef]) -> *const *mut GObject { // Can't have consumer free a *const pointer unimplemented!() } } #[doc(hidden)] impl FromGlibPtrNone<*mut GObject> for ObjectRef { #[inline] unsafe fn from_glib_none(ptr: *mut GObject) -> Self { assert!(!ptr.is_null()); assert_ne!((*ptr).ref_count, 0); // Attention: This takes ownership of floating references! Self { inner: ptr::NonNull::new_unchecked(gobject_ffi::g_object_ref_sink(ptr)), } } } #[doc(hidden)] impl FromGlibPtrNone<*const GObject> for ObjectRef { #[inline] unsafe fn from_glib_none(ptr: *const GObject) -> Self { // Attention: This takes ownership of floating references! from_glib_none(ptr as *mut GObject) } } #[doc(hidden)] impl FromGlibPtrFull<*mut GObject> for ObjectRef { #[inline] unsafe fn from_glib_full(ptr: *mut GObject) -> Self { assert!(!ptr.is_null()); assert_ne!((*ptr).ref_count, 0); Self { inner: ptr::NonNull::new_unchecked(ptr), } } } #[doc(hidden)] impl FromGlibPtrBorrow<*mut GObject> for ObjectRef { #[inline] unsafe fn from_glib_borrow(ptr: *mut GObject) -> Borrowed { assert!(!ptr.is_null()); assert_ne!((*ptr).ref_count, 0); Borrowed::new(Self { inner: ptr::NonNull::new_unchecked(ptr), }) } } #[doc(hidden)] impl FromGlibPtrBorrow<*const GObject> for ObjectRef { #[inline] unsafe fn from_glib_borrow(ptr: *const GObject) -> Borrowed { from_glib_borrow(ptr as *mut GObject) } } #[doc(hidden)] impl FromGlibContainerAsVec<*mut GObject, *mut *mut GObject> for ObjectRef { unsafe fn from_glib_none_num_as_vec(ptr: *mut *mut GObject, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } // Attention: This takes ownership of floating references! let mut res = Vec::with_capacity(num); for i in 0..num { res.push(from_glib_none(ptr::read(ptr.add(i)))); } res } unsafe fn from_glib_container_num_as_vec(ptr: *mut *mut GObject, num: usize) -> Vec { // Attention: This takes ownership of floating references! let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut *mut GObject, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for i in 0..num { res.push(from_glib_full(ptr::read(ptr.add(i)))); } ffi::g_free(ptr as *mut _); res } } #[doc(hidden)] impl FromGlibPtrArrayContainerAsVec<*mut GObject, *mut *mut GObject> for ObjectRef { unsafe fn from_glib_none_as_vec(ptr: *mut *mut GObject) -> Vec { // Attention: This takes ownership of floating references! FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr)) } unsafe fn from_glib_container_as_vec(ptr: *mut *mut GObject) -> Vec { // Attention: This takes ownership of floating references! FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, c_ptr_array_len(ptr)) } unsafe fn from_glib_full_as_vec(ptr: *mut *mut GObject) -> Vec { FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr)) } } #[doc(hidden)] impl FromGlibContainerAsVec<*mut GObject, *const *mut GObject> for ObjectRef { unsafe fn from_glib_none_num_as_vec(ptr: *const *mut GObject, num: usize) -> Vec { // Attention: This takes ownership of floating references! FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *mut *mut _, num) } unsafe fn from_glib_container_num_as_vec(_: *const *mut GObject, _: usize) -> Vec { // Can't free a *const unimplemented!() } unsafe fn from_glib_full_num_as_vec(_: *const *mut GObject, _: usize) -> Vec { // Can't free a *const unimplemented!() } } #[doc(hidden)] impl FromGlibPtrArrayContainerAsVec<*mut GObject, *const *mut GObject> for ObjectRef { unsafe fn from_glib_none_as_vec(ptr: *const *mut GObject) -> Vec { // Attention: This takes ownership of floating references! FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr as *mut *mut _) } unsafe fn from_glib_container_as_vec(_: *const *mut GObject) -> Vec { // Can't free a *const unimplemented!() } unsafe fn from_glib_full_as_vec(_: *const *mut GObject) -> Vec { // Can't free a *const unimplemented!() } } #[doc(hidden)] #[macro_export] macro_rules! glib_weak_impl { ($name:ident) => { #[doc(hidden)] impl $crate::clone::Downgrade for $name { type Weak = $crate::object::WeakRef; fn downgrade(&self) -> Self::Weak { ::downgrade(&self) } } }; } /// ObjectType implementations for Object types. See `wrapper!`. #[macro_export] macro_rules! glib_object_wrapper { (@generic_impl [$($attr:meta)*] $name:ident, $ffi_name:ty, $ffi_class_name:ty, @type_ $get_type_expr:expr) => { $(#[$attr])* // Always derive Hash/Ord (and below impl Debug, PartialEq, Eq, PartialOrd) for object // types. Due to inheritance and up/downcasting we must implement these by pointer or // otherwise they would potentially give different results for the same object depending on // the type we currently know for it #[derive(Clone, Hash, Ord, Eq, Debug)] pub struct $name($crate::object::ObjectRef); #[doc(hidden)] impl From<$name> for $crate::object::ObjectRef { fn from(s: $name) -> $crate::object::ObjectRef { s.0 } } #[doc(hidden)] impl $crate::object::UnsafeFrom<$crate::object::ObjectRef> for $name { unsafe fn unsafe_from(t: $crate::object::ObjectRef) -> Self { $name(t) } } #[doc(hidden)] impl $crate::translate::GlibPtrDefault for $name { type GlibType = *mut $ffi_name; } #[doc(hidden)] unsafe impl $crate::object::ObjectType for $name { type GlibType = $ffi_name; type GlibClassType = $ffi_class_name; fn as_object_ref(&self) -> &$crate::object::ObjectRef { &self.0 } fn as_ptr(&self) -> *mut Self::GlibType { $crate::translate::ToGlibPtr::to_glib_none(&self.0).0 as *mut _ } } #[doc(hidden)] impl AsRef<$crate::object::ObjectRef> for $name { fn as_ref(&self) -> &$crate::object::ObjectRef { &self.0 } } #[doc(hidden)] impl AsRef<$name> for $name { fn as_ref(&self) -> &$name { self } } #[doc(hidden)] unsafe impl $crate::object::IsA<$name> for $name { } #[doc(hidden)] impl<'a> $crate::translate::ToGlibPtr<'a, *const $ffi_name> for $name { type Storage = <$crate::object::ObjectRef as $crate::translate::ToGlibPtr<'a, *mut $crate::object::GObject>>::Storage; #[inline] fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *const $ffi_name, Self> { let stash = $crate::translate::ToGlibPtr::to_glib_none(&self.0); $crate::translate::Stash(stash.0 as *const _, stash.1) } #[inline] fn to_glib_full(&self) -> *const $ffi_name { $crate::translate::ToGlibPtr::to_glib_full(&self.0) as *const _ } } #[doc(hidden)] impl<'a> $crate::translate::ToGlibPtr<'a, *mut $ffi_name> for $name { type Storage = <$crate::object::ObjectRef as $crate::translate::ToGlibPtr<'a, *mut $crate::object::GObject>>::Storage; #[inline] fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *mut $ffi_name, Self> { let stash = $crate::translate::ToGlibPtr::to_glib_none(&self.0); $crate::translate::Stash(stash.0 as *mut _, stash.1) } #[inline] fn to_glib_full(&self) -> *mut $ffi_name { $crate::translate::ToGlibPtr::to_glib_full(&self.0) as *mut _ } } #[doc(hidden)] impl<'a> $crate::translate::ToGlibContainerFromSlice<'a, *mut *mut $ffi_name> for $name { type Storage = (Vec<$crate::translate::Stash<'a, *mut $ffi_name, $name>>, Option>); fn to_glib_none_from_slice(t: &'a [$name]) -> (*mut *mut $ffi_name, Self::Storage) { let v: Vec<_> = t.iter().map(|s| $crate::translate::ToGlibPtr::to_glib_none(s)).collect(); let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect(); v_ptr.push(std::ptr::null_mut() as *mut $ffi_name); (v_ptr.as_ptr() as *mut *mut $ffi_name, (v, Some(v_ptr))) } fn to_glib_container_from_slice(t: &'a [$name]) -> (*mut *mut $ffi_name, Self::Storage) { let v: Vec<_> = t.iter().map(|s| $crate::translate::ToGlibPtr::to_glib_none(s)).collect(); let v_ptr = unsafe { let v_ptr = $crate::ffi::g_malloc0(std::mem::size_of::<*mut $ffi_name>() * (t.len() + 1)) as *mut *mut $ffi_name; for (i, s) in v.iter().enumerate() { std::ptr::write(v_ptr.add(i), s.0); } v_ptr }; (v_ptr, (v, None)) } fn to_glib_full_from_slice(t: &[$name]) -> *mut *mut $ffi_name { unsafe { let v_ptr = $crate::ffi::g_malloc0(std::mem::size_of::<*mut $ffi_name>() * (t.len() + 1)) as *mut *mut $ffi_name; for (i, s) in t.iter().enumerate() { std::ptr::write(v_ptr.add(i), $crate::translate::ToGlibPtr::to_glib_full(s)); } v_ptr } } } #[doc(hidden)] impl<'a> $crate::translate::ToGlibContainerFromSlice<'a, *const *mut $ffi_name> for $name { type Storage = (Vec<$crate::translate::Stash<'a, *mut $ffi_name, $name>>, Option>); fn to_glib_none_from_slice(t: &'a [$name]) -> (*const *mut $ffi_name, Self::Storage) { let (ptr, stash) = $crate::translate::ToGlibContainerFromSlice::<'a, *mut *mut $ffi_name>::to_glib_none_from_slice(t); (ptr as *const *mut $ffi_name, stash) } fn to_glib_container_from_slice(_: &'a [$name]) -> (*const *mut $ffi_name, Self::Storage) { // Can't have consumer free a *const pointer unimplemented!() } fn to_glib_full_from_slice(_: &[$name]) -> *const *mut $ffi_name { // Can't have consumer free a *const pointer unimplemented!() } } #[doc(hidden)] impl $crate::translate::FromGlibPtrNone<*mut $ffi_name> for $name { #[inline] #[allow(clippy::cast_ptr_alignment)] unsafe fn from_glib_none(ptr: *mut $ffi_name) -> Self { debug_assert!($crate::types::instance_of::(ptr as *const _)); $name($crate::translate::from_glib_none(ptr as *mut _)) } } #[doc(hidden)] impl $crate::translate::FromGlibPtrNone<*const $ffi_name> for $name { #[inline] #[allow(clippy::cast_ptr_alignment)] unsafe fn from_glib_none(ptr: *const $ffi_name) -> Self { debug_assert!($crate::types::instance_of::(ptr as *const _)); $name($crate::translate::from_glib_none(ptr as *mut _)) } } #[doc(hidden)] impl $crate::translate::FromGlibPtrFull<*mut $ffi_name> for $name { #[inline] #[allow(clippy::cast_ptr_alignment)] unsafe fn from_glib_full(ptr: *mut $ffi_name) -> Self { debug_assert!($crate::types::instance_of::(ptr as *const _)); $name($crate::translate::from_glib_full(ptr as *mut _)) } } #[doc(hidden)] impl $crate::translate::FromGlibPtrBorrow<*mut $ffi_name> for $name { #[inline] #[allow(clippy::cast_ptr_alignment)] unsafe fn from_glib_borrow(ptr: *mut $ffi_name) -> $crate::translate::Borrowed { debug_assert!($crate::types::instance_of::(ptr as *const _)); $crate::translate::Borrowed::new( $name( $crate::translate::from_glib_borrow::<_, $crate::object::ObjectRef>(ptr as *mut _).into_inner() ) ) } } #[doc(hidden)] impl $crate::translate::FromGlibPtrBorrow<*const $ffi_name> for $name { #[inline] #[allow(clippy::cast_ptr_alignment)] unsafe fn from_glib_borrow(ptr: *const $ffi_name) -> $crate::translate::Borrowed { $crate::translate::from_glib_borrow::<_, $name>(ptr as *mut $ffi_name) } } #[doc(hidden)] impl $crate::translate::FromGlibContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name { unsafe fn from_glib_none_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for i in 0..num { res.push($crate::translate::from_glib_none(std::ptr::read(ptr.add(i)))); } res } unsafe fn from_glib_container_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { let res = $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); $crate::ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for i in 0..num { res.push($crate::translate::from_glib_full(std::ptr::read(ptr.add(i)))); } $crate::ffi::g_free(ptr as *mut _); res } } #[doc(hidden)] impl $crate::translate::FromGlibPtrArrayContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name { unsafe fn from_glib_none_as_vec(ptr: *mut *mut $ffi_name) -> Vec { $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr)) } unsafe fn from_glib_container_as_vec(ptr: *mut *mut $ffi_name) -> Vec { $crate::translate::FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr)) } unsafe fn from_glib_full_as_vec(ptr: *mut *mut $ffi_name) -> Vec { $crate::translate::FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr)) } } #[doc(hidden)] impl $crate::translate::FromGlibContainerAsVec<*mut $ffi_name, *const *mut $ffi_name> for $name { unsafe fn from_glib_none_num_as_vec(ptr: *const *mut $ffi_name, num: usize) -> Vec { $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *mut *mut _, num) } unsafe fn from_glib_container_num_as_vec(_: *const *mut $ffi_name, _: usize) -> Vec { // Can't free a *const unimplemented!() } unsafe fn from_glib_full_num_as_vec(_: *const *mut $ffi_name, _: usize) -> Vec { // Can't free a *const unimplemented!() } } #[doc(hidden)] impl $crate::translate::FromGlibPtrArrayContainerAsVec<*mut $ffi_name, *const *mut $ffi_name> for $name { unsafe fn from_glib_none_as_vec(ptr: *const *mut $ffi_name) -> Vec { $crate::translate::FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr as *mut *mut _) } unsafe fn from_glib_container_as_vec(_: *const *mut $ffi_name) -> Vec { // Can't free a *const unimplemented!() } unsafe fn from_glib_full_as_vec(_: *const *mut $ffi_name) -> Vec { // Can't free a *const unimplemented!() } } impl $crate::types::StaticType for $name { fn static_type() -> $crate::types::Type { #[allow(unused_unsafe)] unsafe { $crate::translate::from_glib($get_type_expr) } } } impl std::cmp::PartialEq for $name { #[inline] fn eq(&self, other: &T) -> bool { std::cmp::PartialEq::eq(&self.0, $crate::object::ObjectType::as_object_ref(other)) } } impl std::cmp::PartialOrd for $name { #[inline] fn partial_cmp(&self, other: &T) -> Option { std::cmp::PartialOrd::partial_cmp(&self.0, $crate::object::ObjectType::as_object_ref(other)) } } #[doc(hidden)] impl $crate::value::ValueType for $name { type Type = $name; } #[doc(hidden)] unsafe impl<'a> $crate::value::FromValue<'a> for $name { type Checker = $crate::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a $crate::Value) -> Self { let ptr = $crate::gobject_ffi::g_value_dup_object($crate::translate::ToGlibPtr::to_glib_none(value).0); assert!(!ptr.is_null()); assert_ne!((*ptr).ref_count, 0); <$name as $crate::translate::FromGlibPtrFull<*mut $ffi_name>>::from_glib_full(ptr as *mut $ffi_name) } } #[doc(hidden)] impl $crate::value::ToValue for $name { fn to_value(&self) -> $crate::Value { unsafe { let mut value = $crate::Value::from_type(<$name as $crate::StaticType>::static_type()); $crate::gobject_ffi::g_value_take_object( $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::translate::ToGlibPtr::<*mut $ffi_name>::to_glib_full(self) as *mut _, ); value } } fn value_type(&self) -> $crate::Type { <$name as $crate::StaticType>::static_type() } } #[doc(hidden)] impl $crate::value::ToValueOptional for $name { fn to_value_optional(s: Option<&Self>) -> $crate::Value { let mut value = $crate::Value::for_value_type::(); unsafe { $crate::gobject_ffi::g_value_take_object( $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::translate::ToGlibPtr::<*mut $ffi_name>::to_glib_full(&s) as *mut _, ); } value } } $crate::glib_weak_impl!($name); }; (@munch_impls $name:ident, ) => { }; (@munch_impls $name:ident, $super_name:path) => { unsafe impl $crate::object::IsA<$super_name> for $name { } #[doc(hidden)] impl AsRef<$super_name> for $name { fn as_ref(&self) -> &$super_name { $crate::object::Cast::upcast_ref(self) } } }; (@munch_impls $name:ident, $super_name:path, $($implements:tt)*) => { $crate::glib_object_wrapper!(@munch_impls $name, $super_name); $crate::glib_object_wrapper!(@munch_impls $name, $($implements)*); }; // If there is no parent class, i.e. only glib::Object (@munch_first_impl $name:ident, ) => { $crate::glib_object_wrapper!(@munch_impls $name, ); unsafe impl $crate::object::ParentClassIs for $name { type Parent = $crate::object::Object; } }; // If there is only one parent class (@munch_first_impl $name:ident, $super_name:path) => { $crate::glib_object_wrapper!(@munch_impls $name, $super_name); unsafe impl $crate::object::ParentClassIs for $name { type Parent = $super_name; } }; // If there is more than one parent class (@munch_first_impl $name:ident, $super_name:path, $($implements:tt)*) => { $crate::glib_object_wrapper!(@munch_impls $name, $super_name); unsafe impl $crate::object::ParentClassIs for $name { type Parent = $super_name; } $crate::glib_object_wrapper!(@munch_impls $name, $($implements)*); }; // This case is only for glib::Object itself below. All other cases have glib::Object in its // parent class list (@object [$($attr:meta)*] $name:ident, $ffi_name:ty, $ffi_class_name:ty, @type_ $get_type_expr:expr) => { $crate::glib_object_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name, $ffi_class_name, @type_ $get_type_expr); #[doc(hidden)] unsafe impl $crate::object::IsClass for $name { } }; (@object [$($attr:meta)*] $name:ident, $ffi_name:ty, $ffi_class_name:ty, @type_ $get_type_expr:expr, @extends [$($extends:tt)*], @implements [$($implements:tt)*]) => { $crate::glib_object_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name, $ffi_class_name, @type_ $get_type_expr); $crate::glib_object_wrapper!(@munch_first_impl $name, $($extends)*); $crate::glib_object_wrapper!(@munch_impls $name, $($implements)*); #[doc(hidden)] impl AsRef<$crate::object::Object> for $name { fn as_ref(&self) -> &$crate::object::Object { $crate::object::Cast::upcast_ref(self) } } #[doc(hidden)] unsafe impl $crate::object::IsA<$crate::object::Object> for $name { } #[doc(hidden)] unsafe impl $crate::object::IsClass for $name { } }; (@interface [$($attr:meta)*] $name:ident, $ffi_name:ty, $ffi_class_name:ty, @type_ $get_type_expr:expr, @requires [$($requires:tt)*]) => { $crate::glib_object_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name, $ffi_class_name, @type_ $get_type_expr); $crate::glib_object_wrapper!(@munch_impls $name, $($requires)*); #[doc(hidden)] impl AsRef<$crate::object::Object> for $name { fn as_ref(&self) -> &$crate::object::Object { $crate::object::Cast::upcast_ref(self) } } #[doc(hidden)] unsafe impl $crate::object::IsA<$crate::object::Object> for $name { } #[doc(hidden)] unsafe impl $crate::object::IsInterface for $name { } }; } glib_object_wrapper!(@object [doc = "The base class in the object hierarchy."] Object, GObject, GObjectClass, @type_ gobject_ffi::g_object_get_type() ); pub type ObjectClass = Class; impl Object { #[allow(clippy::new_ret_no_self)] pub fn new + IsClass>( properties: &[(&str, &dyn ToValue)], ) -> Result { Ok(Object::with_type(T::static_type(), properties)? .downcast() .unwrap()) } pub fn with_type( type_: Type, properties: &[(&str, &dyn ToValue)], ) -> Result { use std::ffi::CString; let klass = ObjectClass::from_type(type_) .ok_or_else(|| bool_error!("Can't retrieve class for type '{}'", type_))?; let pspecs = klass.list_properties(); let params = properties .iter() .map(|(name, value)| { let pspec = pspecs.iter().find(|p| p.name() == *name).ok_or_else(|| { bool_error!("Can't find property '{}' for type '{}'", name, type_) })?; let mut value = value.to_value(); validate_property_type(type_, true, pspec, &mut value)?; Ok((CString::new(*name).unwrap(), value)) }) .collect::, _>>()?; unsafe { Object::new_internal(type_, ¶ms) } } pub fn with_values(type_: Type, properties: &[(&str, Value)]) -> Result { use std::ffi::CString; let klass = ObjectClass::from_type(type_) .ok_or_else(|| bool_error!("Can't retrieve class for type '{}'", type_))?; let pspecs = klass.list_properties(); let params = properties .iter() .map(|(name, value)| { let pspec = pspecs.iter().find(|p| p.name() == *name).ok_or_else(|| { bool_error!("Can't find property '{}' for type '{}'", name, type_) })?; let mut value = value.clone(); validate_property_type(type_, true, pspec, &mut value)?; Ok((CString::new(*name).unwrap(), value)) }) .collect::, _>>()?; unsafe { Object::new_internal(type_, ¶ms) } } unsafe fn new_internal( type_: Type, params: &[(std::ffi::CString, Value)], ) -> Result { if !type_.is_a(Object::static_type()) { return Err(bool_error!( "Can't instantiate non-GObject type '{}'", type_ )); } if gobject_ffi::g_type_test_flags( type_.into_glib(), gobject_ffi::G_TYPE_FLAG_INSTANTIATABLE, ) == ffi::GFALSE { return Err(bool_error!("Can't instantiate type '{}'", type_)); } if gobject_ffi::g_type_test_flags(type_.into_glib(), gobject_ffi::G_TYPE_FLAG_ABSTRACT) != ffi::GFALSE { return Err(bool_error!("Can't instantiate abstract type '{}'", type_)); } let params_c = params .iter() .map(|&(ref name, ref value)| gobject_ffi::GParameter { name: name.as_ptr(), value: *value.to_glib_none().0, }) .collect::>(); let ptr = gobject_ffi::g_object_newv( type_.into_glib(), params_c.len() as u32, mut_override(params_c.as_ptr()), ); if ptr.is_null() { Err(bool_error!("Can't instantiate object for type '{}'", type_)) } else if type_.is_a(InitiallyUnowned::static_type()) { // Attention: This takes ownership of the floating reference Ok(from_glib_none(ptr)) } else { Ok(from_glib_full(ptr)) } } } #[must_use = "if unused the property notifications will immediately be thawed"] pub struct PropertyNotificationFreezeGuard(ObjectRef); impl Drop for PropertyNotificationFreezeGuard { #[doc(alias = "g_object_thaw_notify")] fn drop(&mut self) { unsafe { gobject_ffi::g_object_thaw_notify(self.0.to_glib_none().0) } } } pub trait ObjectExt: ObjectType { /// Returns `true` if the object is an instance of (can be cast to) `T`. fn is(&self) -> bool; #[doc(alias = "get_type")] fn type_(&self) -> Type; #[doc(alias = "get_object_class")] fn object_class(&self) -> &ObjectClass; #[doc(alias = "get_class")] fn class(&self) -> &Class where Self: IsClass; #[doc(alias = "get_class_of")] fn class_of(&self) -> Option<&Class>; #[doc(alias = "get_interface")] fn interface(&self) -> Option>; #[doc(alias = "g_object_set_property")] fn set_property<'a, N: Into<&'a str>, V: ToValue>( &self, property_name: N, value: V, ) -> Result<(), BoolError>; fn set_property_from_value<'a, N: Into<&'a str>>( &self, property_name: N, value: &Value, ) -> Result<(), BoolError>; fn set_properties(&self, property_values: &[(&str, &dyn ToValue)]) -> Result<(), BoolError>; fn set_properties_from_value(&self, property_values: &[(&str, Value)]) -> Result<(), BoolError>; #[doc(alias = "get_property")] #[doc(alias = "g_object_get_property")] fn property<'a, N: Into<&'a str>>(&self, property_name: N) -> Result; fn has_property<'a, N: Into<&'a str>>(&self, property_name: N, type_: Option) -> bool; #[doc(alias = "get_property_type")] fn property_type<'a, N: Into<&'a str>>(&self, property_name: N) -> Option; fn find_property<'a, N: Into<&'a str>>(&self, property_name: N) -> Option; fn list_properties(&self) -> Vec; #[doc(alias = "g_object_freeze_notify")] fn freeze_notify(&self) -> PropertyNotificationFreezeGuard; /// # Safety /// /// This function doesn't store type information unsafe fn set_qdata(&self, key: Quark, value: QD); /// # Safety /// /// The returned pointer can become invalid by a call to /// `set_qdata`, `steal_qdata`, `set_data` or `steal_data`. /// /// The caller is responsible for ensuring the returned value is of a suitable type #[doc(alias = "get_qdata")] unsafe fn qdata(&self, key: Quark) -> Option>; /// # Safety /// /// The caller is responsible for ensuring the returned value is of a suitable type unsafe fn steal_qdata(&self, key: Quark) -> Option; /// # Safety /// /// This function doesn't store type information unsafe fn set_data(&self, key: &str, value: QD); /// # Safety /// /// The returned pointer can become invalid by a call to /// `set_qdata`, `steal_qdata`, `set_data` or `steal_data`. /// /// The caller is responsible for ensuring the returned value is of a suitable type #[doc(alias = "get_data")] unsafe fn data(&self, key: &str) -> Option>; /// # Safety /// /// The caller is responsible for ensuring the returned value is of a suitable type unsafe fn steal_data(&self, key: &str) -> Option; fn block_signal(&self, handler_id: &SignalHandlerId); fn unblock_signal(&self, handler_id: &SignalHandlerId); fn stop_signal_emission(&self, signal_name: &str); fn connect<'a, N, F>( &self, signal_name: N, after: bool, callback: F, ) -> Result where N: Into<&'a str>, F: Fn(&[Value]) -> Option + Send + Sync + 'static; /// Same as `connect` but takes a `SignalId` instead of a signal name. fn connect_id( &self, signal_id: SignalId, details: Option, after: bool, callback: F, ) -> Result where F: Fn(&[Value]) -> Option + Send + Sync + 'static; fn connect_local<'a, N, F>( &self, signal_name: N, after: bool, callback: F, ) -> Result where N: Into<&'a str>, F: Fn(&[Value]) -> Option + 'static; /// Same as `connect_local` but takes a `SignalId` instead of a signal name. fn connect_local_id( &self, signal_id: SignalId, details: Option, after: bool, callback: F, ) -> Result where F: Fn(&[Value]) -> Option + 'static; unsafe fn connect_unsafe<'a, N, F>( &self, signal_name: N, after: bool, callback: F, ) -> Result where N: Into<&'a str>, F: Fn(&[Value]) -> Option; /// Same as `connect_unsafe` but takes a `SignalId` instead of a signal name. unsafe fn connect_unsafe_id( &self, signal_id: SignalId, details: Option, after: bool, callback: F, ) -> Result where F: Fn(&[Value]) -> Option; /// Emit signal by signal id. #[doc(alias = "g_signal_emitv")] fn emit(&self, signal_id: SignalId, args: &[&dyn ToValue]) -> Result, BoolError>; /// Same as `emit` but takes `Value` for the arguments. fn emit_with_values( &self, signal_id: SignalId, args: &[Value], ) -> Result, BoolError>; /// Emit signal by its name. fn emit_by_name<'a, N: Into<&'a str>>( &self, signal_name: N, args: &[&dyn ToValue], ) -> Result, BoolError>; /// Same as `emit_by_name` but takes `Value` for the arguments. fn emit_by_name_with_values<'a, N: Into<&'a str>>( &self, signal_name: N, args: &[Value], ) -> Result, BoolError>; /// Emit signal with details by signal id. fn emit_with_details( &self, signal_id: SignalId, details: Quark, args: &[&dyn ToValue], ) -> Result, BoolError>; /// Same as `emit_with_details` but takes `Value` for the arguments. fn emit_with_details_and_values( &self, signal_id: SignalId, details: Quark, args: &[Value], ) -> Result, BoolError>; #[doc(alias = "g_signal_handler_disconnect")] fn disconnect(&self, handler_id: SignalHandlerId); fn connect_notify( &self, name: Option<&str>, f: F, ) -> SignalHandlerId; fn connect_notify_local( &self, name: Option<&str>, f: F, ) -> SignalHandlerId; unsafe fn connect_notify_unsafe( &self, name: Option<&str>, f: F, ) -> SignalHandlerId; #[doc(alias = "g_object_notify")] fn notify<'a, N: Into<&'a str>>(&self, property_name: N); #[doc(alias = "g_object_notify_by_pspec")] fn notify_by_pspec(&self, pspec: &crate::ParamSpec); fn downgrade(&self) -> WeakRef; fn bind_property<'a, O: ObjectType, N: Into<&'a str>, M: Into<&'a str>>( &'a self, source_property: N, target: &'a O, target_property: M, ) -> BindingBuilder<'a>; fn ref_count(&self) -> u32; } impl ObjectExt for T { fn is(&self) -> bool { self.type_().is_a(U::static_type()) } fn type_(&self) -> Type { self.object_class().type_() } fn object_class(&self) -> &ObjectClass { unsafe { let obj: *mut gobject_ffi::GObject = self.as_object_ref().to_glib_none().0; let klass = (*obj).g_type_instance.g_class as *const ObjectClass; &*klass } } fn class(&self) -> &Class where Self: IsClass, { unsafe { let obj: *mut gobject_ffi::GObject = self.as_object_ref().to_glib_none().0; let klass = (*obj).g_type_instance.g_class as *const Class; &*klass } } fn class_of(&self) -> Option<&Class> { if !self.is::() { return None; } unsafe { let obj: *mut gobject_ffi::GObject = self.as_object_ref().to_glib_none().0; let klass = (*obj).g_type_instance.g_class as *const Class; Some(&*klass) } } fn interface(&self) -> Option> { Interface::from_class(self.object_class()) } fn set_property<'a, N: Into<&'a str>, V: ToValue>( &self, property_name: N, value: V, ) -> Result<(), BoolError> { let property_name = property_name.into(); let pspec = match self.find_property(property_name) { Some(pspec) => pspec, None => { return Err(bool_error!( "property '{}' of type '{}' not found", property_name, self.type_() )); } }; let mut property_value = value.to_value(); validate_property_type(self.type_(), false, &pspec, &mut property_value)?; unsafe { gobject_ffi::g_object_set_property( self.as_object_ref().to_glib_none().0, property_name.to_glib_none().0, property_value.to_glib_none().0, ); } Ok(()) } fn set_property_from_value<'a, N: Into<&'a str>>( &self, property_name: N, value: &Value, ) -> Result<(), BoolError> { let property_name = property_name.into(); let pspec = match self.find_property(property_name) { Some(pspec) => pspec, None => { return Err(bool_error!( "property '{}' of type '{}' not found", property_name, self.type_() )); } }; let mut property_value = value.clone(); validate_property_type(self.type_(), false, &pspec, &mut property_value)?; unsafe { gobject_ffi::g_object_set_property( self.as_object_ref().to_glib_none().0, property_name.to_glib_none().0, property_value.to_glib_none().0, ); } Ok(()) } fn set_properties(&self, property_values: &[(&str, &dyn ToValue)]) -> Result<(), BoolError> { use std::ffi::CString; let pspecs = self.list_properties(); let params = property_values .iter() .map(|&(name, value)| { let pspec = pspecs.iter().find(|p| p.name() == name).ok_or_else(|| { bool_error!("Can't find property '{}' for type '{}'", name, self.type_()) })?; let mut value = value.to_value(); validate_property_type(self.type_(), false, pspec, &mut value)?; Ok((CString::new(name).unwrap(), value)) }) .collect::, _>>()?; for (name, value) in params { unsafe { gobject_ffi::g_object_set_property( self.as_object_ref().to_glib_none().0, name.as_ptr(), value.to_glib_none().0, ); } } Ok(()) } fn set_properties_from_value( &self, property_values: &[(&str, Value)], ) -> Result<(), BoolError> { use std::ffi::CString; let pspecs = self.list_properties(); let params = property_values .iter() .map(|(name, value)| { let pspec = pspecs.iter().find(|p| p.name() == *name).ok_or_else(|| { bool_error!("Can't find property '{}' for type '{}'", name, self.type_()) })?; let mut value = value.clone(); validate_property_type(self.type_(), false, pspec, &mut value)?; Ok((CString::new(*name).unwrap(), value)) }) .collect::, _>>()?; for (name, value) in params { unsafe { gobject_ffi::g_object_set_property( self.as_object_ref().to_glib_none().0, name.as_ptr(), value.to_glib_none().0, ); } } Ok(()) } fn property<'a, N: Into<&'a str>>(&self, property_name: N) -> Result { let property_name = property_name.into(); let pspec = match self.find_property(property_name) { Some(pspec) => pspec, None => { return Err(bool_error!( "property '{}' of type '{}' not found", property_name, self.type_() )); } }; if !pspec.flags().contains(crate::ParamFlags::READABLE) { return Err(bool_error!( "property '{}' of type '{}' is not readable", property_name, self.type_() )); } unsafe { let mut value = Value::from_type(pspec.value_type()); gobject_ffi::g_object_get_property( self.as_object_ref().to_glib_none().0, property_name.to_glib_none().0, value.to_glib_none_mut().0, ); // This can't really happen unless something goes wrong inside GObject Some(value).filter(|v| v.type_().is_valid()).ok_or_else(|| { bool_error!( "Failed to get property value for property '{}' of type '{}'", property_name, self.type_() ) }) } } fn has_property<'a, N: Into<&'a str>>(&self, property_name: N, type_: Option) -> bool { self.object_class().has_property(property_name, type_) } fn property_type<'a, N: Into<&'a str>>(&self, property_name: N) -> Option { self.object_class().property_type(property_name) } fn find_property<'a, N: Into<&'a str>>(&self, property_name: N) -> Option { self.object_class().find_property(property_name) } fn list_properties(&self) -> Vec { self.object_class().list_properties() } fn freeze_notify(&self) -> PropertyNotificationFreezeGuard { unsafe { gobject_ffi::g_object_freeze_notify(self.as_object_ref().to_glib_none().0) }; PropertyNotificationFreezeGuard(self.as_object_ref().clone()) } unsafe fn set_qdata(&self, key: Quark, value: QD) { unsafe extern "C" fn drop_value(ptr: ffi::gpointer) { debug_assert!(!ptr.is_null()); let value: Box = Box::from_raw(ptr as *mut QD); drop(value) } let ptr = Box::into_raw(Box::new(value)) as ffi::gpointer; gobject_ffi::g_object_set_qdata_full( self.as_object_ref().to_glib_none().0, key.into_glib(), ptr, Some(drop_value::), ); } unsafe fn qdata(&self, key: Quark) -> Option> { ptr::NonNull::new(gobject_ffi::g_object_get_qdata( self.as_object_ref().to_glib_none().0, key.into_glib(), ) as *mut QD) } unsafe fn steal_qdata(&self, key: Quark) -> Option { let ptr = gobject_ffi::g_object_steal_qdata( self.as_object_ref().to_glib_none().0, key.into_glib(), ); if ptr.is_null() { None } else { let value: Box = Box::from_raw(ptr as *mut QD); Some(*value) } } unsafe fn set_data(&self, key: &str, value: QD) { self.set_qdata::(Quark::from_string(key), value) } unsafe fn data(&self, key: &str) -> Option> { self.qdata::(Quark::from_string(key)) } unsafe fn steal_data(&self, key: &str) -> Option { self.steal_qdata::(Quark::from_string(key)) } fn block_signal(&self, handler_id: &SignalHandlerId) { unsafe { gobject_ffi::g_signal_handler_block( self.as_object_ref().to_glib_none().0, handler_id.as_raw(), ); } } fn unblock_signal(&self, handler_id: &SignalHandlerId) { unsafe { gobject_ffi::g_signal_handler_unblock( self.as_object_ref().to_glib_none().0, handler_id.as_raw(), ); } } fn stop_signal_emission(&self, signal_name: &str) { unsafe { gobject_ffi::g_signal_stop_emission_by_name( self.as_object_ref().to_glib_none().0, signal_name.to_glib_none().0, ); } } fn connect<'a, N, F>( &self, signal_name: N, after: bool, callback: F, ) -> Result where N: Into<&'a str>, F: Fn(&[Value]) -> Option + Send + Sync + 'static, { unsafe { self.connect_unsafe(signal_name, after, callback) } } fn connect_id( &self, signal_id: SignalId, details: Option, after: bool, callback: F, ) -> Result where F: Fn(&[Value]) -> Option + Send + Sync + 'static, { unsafe { self.connect_unsafe_id(signal_id, details, after, callback) } } fn connect_local<'a, N, F>( &self, signal_name: N, after: bool, callback: F, ) -> Result where N: Into<&'a str>, F: Fn(&[Value]) -> Option + 'static, { let callback = crate::ThreadGuard::new(callback); unsafe { self.connect_unsafe(signal_name, after, move |values| { (callback.get_ref())(values) }) } } fn connect_local_id( &self, signal_id: SignalId, details: Option, after: bool, callback: F, ) -> Result where F: Fn(&[Value]) -> Option + 'static, { let callback = crate::ThreadGuard::new(callback); unsafe { self.connect_unsafe_id(signal_id, details, after, move |values| { (callback.get_ref())(values) }) } } unsafe fn connect_unsafe<'a, N, F>( &self, signal_name: N, after: bool, callback: F, ) -> Result where N: Into<&'a str>, F: Fn(&[Value]) -> Option, { let signal_name: &str = signal_name.into(); let type_ = self.type_(); let (signal_id, details) = SignalId::parse_name(signal_name, type_, true) .ok_or_else(|| bool_error!("Signal '{}' of type '{}' not found", signal_name, type_))?; self.connect_unsafe_id(signal_id, Some(details), after, callback) } unsafe fn connect_unsafe_id( &self, signal_id: SignalId, details: Option, after: bool, callback: F, ) -> Result where F: Fn(&[Value]) -> Option, { let signal_query = signal_id.query(); let type_ = self.type_(); let return_type: Type = signal_query.return_type().into(); let signal_name = signal_id.name(); let signal_query_type = signal_query.type_(); if !type_.is_a(signal_query_type) { panic!( "Signal '{}' of type '{}' but got type '{}'", signal_name, type_, signal_query_type ); } let closure = if return_type == Type::UNIT { Closure::new_unsafe(move |values| { let ret = callback(values); if let Some(ret) = ret { panic!( "Signal '{}' of type '{}' required no return value but got value of type '{}'", signal_name, type_, ret.type_() ); } None }) } else { Closure::new_unsafe(move |values| { let mut ret = callback(values).unwrap_or_else(|| { panic!( "Signal '{}' of type '{}' required return value of type '{}' but got None", signal_name, type_, return_type.name() ); }); let valid_type: bool = from_glib(gobject_ffi::g_type_check_value_holds( mut_override(ret.to_glib_none().0), return_type.into_glib(), )); if valid_type { return Some(ret); } // If it's not directly a valid type but an object type, we check if the // actual typed of the contained object is compatible and if so create // a properly typed Value. This can happen if the type field in the // Value is set to a more generic type than the contained value let opt_obj = ret.get::>().unwrap_or_else(|_| { panic!( "Signal '{}' of type '{}' required return value of type '{}' but got '{}'", signal_name, type_, return_type, ret.type_() ); }); let actual_type = opt_obj.map_or_else(|| ret.type_(), |obj| obj.type_()); if !actual_type.is_a(return_type) { panic!( "Signal '{}' of type '{}' required return value of type '{}' but got '{}' (actual '{}')", signal_name, type_, return_type, ret.type_(), actual_type ); } ret.0.g_type = return_type.into_glib(); Some(ret) }) }; let handler = gobject_ffi::g_signal_connect_closure_by_id( self.as_object_ref().to_glib_none().0, signal_id.into_glib(), details.map(|d| d.into_glib()).unwrap_or(0), // 0 matches no detail closure.to_glib_none().0, after.into_glib(), ); if handler == 0 { Err(bool_error!( "Failed to connect to signal '{}' of type '{}'", signal_name, type_ )) } else { Ok(from_glib(handler)) } } fn emit(&self, signal_id: SignalId, args: &[&dyn ToValue]) -> Result, BoolError> { let signal_query = signal_id.query(); unsafe { let type_ = self.type_(); let self_v = { let mut v = Value::uninitialized(); gobject_ffi::g_value_init(v.to_glib_none_mut().0, self.type_().into_glib()); gobject_ffi::g_value_set_object( v.to_glib_none_mut().0, self.as_object_ref().to_glib_none().0, ); v }; let mut args = Iterator::chain( std::iter::once(self_v), args.iter().copied().map(ToValue::to_value), ) .collect::>(); let signal_detail = validate_signal_arguments(type_, &signal_query, &mut args[1..])?; let mut return_value = Value::uninitialized(); if signal_query.return_type() != Type::UNIT { gobject_ffi::g_value_init( return_value.to_glib_none_mut().0, signal_query.return_type().into_glib(), ); } gobject_ffi::g_signal_emitv( mut_override(args.as_ptr()) as *mut gobject_ffi::GValue, signal_id.into_glib(), signal_detail.into_glib(), return_value.to_glib_none_mut().0, ); Ok(Some(return_value).filter(|r| r.type_().is_valid() && r.type_() != Type::UNIT)) } } fn emit_with_values( &self, signal_id: SignalId, args: &[Value], ) -> Result, BoolError> { unsafe { let type_ = self.type_(); let signal_query = signal_id.query(); let self_v = { let mut v = Value::uninitialized(); gobject_ffi::g_value_init(v.to_glib_none_mut().0, self.type_().into_glib()); gobject_ffi::g_value_set_object( v.to_glib_none_mut().0, self.as_object_ref().to_glib_none().0, ); v }; let mut args = Iterator::chain(std::iter::once(self_v), args.iter().cloned()) .collect::>(); let signal_detail = validate_signal_arguments(type_, &signal_query, &mut args[1..])?; let mut return_value = Value::uninitialized(); if signal_query.return_type() != Type::UNIT { gobject_ffi::g_value_init( return_value.to_glib_none_mut().0, signal_query.return_type().into_glib(), ); } gobject_ffi::g_signal_emitv( mut_override(args.as_ptr()) as *mut gobject_ffi::GValue, signal_id.into_glib(), signal_detail.into_glib(), return_value.to_glib_none_mut().0, ); Ok(Some(return_value).filter(|r| r.type_().is_valid() && r.type_() != Type::UNIT)) } } fn emit_by_name<'a, N: Into<&'a str>>( &self, signal_name: N, args: &[&dyn ToValue], ) -> Result, BoolError> { let signal_name: &str = signal_name.into(); let type_ = self.type_(); let signal_id = SignalId::lookup(signal_name, type_) .ok_or_else(|| bool_error!("Signal '{}' of type '{}' not found", signal_name, type_))?; self.emit(signal_id, args) } fn emit_by_name_with_values<'a, N: Into<&'a str>>( &self, signal_name: N, args: &[Value], ) -> Result, BoolError> { let signal_name: &str = signal_name.into(); let type_ = self.type_(); let signal_id = SignalId::lookup(signal_name, type_) .ok_or_else(|| bool_error!("Signal '{}' of type '{}' not found", signal_name, type_))?; self.emit_with_values(signal_id, args) } fn emit_with_details( &self, signal_id: SignalId, details: Quark, args: &[&dyn ToValue], ) -> Result, BoolError> { let signal_query = signal_id.query(); assert!(signal_query.flags().contains(crate::SignalFlags::DETAILED)); unsafe { let type_ = self.type_(); let self_v = { let mut v = Value::uninitialized(); gobject_ffi::g_value_init(v.to_glib_none_mut().0, self.type_().into_glib()); gobject_ffi::g_value_set_object( v.to_glib_none_mut().0, self.as_object_ref().to_glib_none().0, ); v }; let mut args = Iterator::chain( std::iter::once(self_v), args.iter().copied().map(ToValue::to_value), ) .collect::>(); validate_signal_arguments(type_, &signal_query, &mut args)?; let mut return_value = Value::uninitialized(); if signal_query.return_type() != Type::UNIT { gobject_ffi::g_value_init( return_value.to_glib_none_mut().0, signal_query.return_type().into_glib(), ); } gobject_ffi::g_signal_emitv( mut_override(args.as_ptr()) as *mut gobject_ffi::GValue, signal_id.into_glib(), details.into_glib(), return_value.to_glib_none_mut().0, ); Ok(Some(return_value).filter(|r| r.type_().is_valid() && r.type_() != Type::UNIT)) } } fn emit_with_details_and_values( &self, signal_id: SignalId, details: Quark, args: &[Value], ) -> Result, BoolError> { let signal_query = signal_id.query(); assert!(signal_query.flags().contains(crate::SignalFlags::DETAILED)); unsafe { let type_ = self.type_(); let self_v = { let mut v = Value::uninitialized(); gobject_ffi::g_value_init(v.to_glib_none_mut().0, self.type_().into_glib()); gobject_ffi::g_value_set_object( v.to_glib_none_mut().0, self.as_object_ref().to_glib_none().0, ); v }; let mut args = Iterator::chain(std::iter::once(self_v), args.iter().cloned()) .collect::>(); validate_signal_arguments(type_, &signal_query, &mut args)?; let mut return_value = Value::uninitialized(); if signal_query.return_type() != Type::UNIT { gobject_ffi::g_value_init( return_value.to_glib_none_mut().0, signal_query.return_type().into_glib(), ); } gobject_ffi::g_signal_emitv( mut_override(args.as_ptr()) as *mut gobject_ffi::GValue, signal_id.into_glib(), details.into_glib(), return_value.to_glib_none_mut().0, ); Ok(Some(return_value).filter(|r| r.type_().is_valid() && r.type_() != Type::UNIT)) } } fn disconnect(&self, handler_id: SignalHandlerId) { unsafe { gobject_ffi::g_signal_handler_disconnect( self.as_object_ref().to_glib_none().0, handler_id.as_raw(), ); } } fn connect_notify( &self, name: Option<&str>, f: F, ) -> SignalHandlerId { unsafe { self.connect_notify_unsafe(name, f) } } fn connect_notify_local( &self, name: Option<&str>, f: F, ) -> SignalHandlerId { let f = crate::ThreadGuard::new(f); unsafe { self.connect_notify_unsafe(name, move |s, pspec| { (f.get_ref())(s, pspec); }) } } unsafe fn connect_notify_unsafe( &self, name: Option<&str>, f: F, ) -> SignalHandlerId { unsafe extern "C" fn notify_trampoline( this: *mut gobject_ffi::GObject, param_spec: *mut gobject_ffi::GParamSpec, f: ffi::gpointer, ) where P: ObjectType, { let f: &F = &*(f as *const F); f( Object::from_glib_borrow(this).unsafe_cast_ref(), &from_glib_borrow(param_spec), ) } let signal_name = if let Some(name) = name { format!("notify::{}\0", name) } else { "notify\0".into() }; let f: Box = Box::new(f); crate::signal::connect_raw( self.as_object_ref().to_glib_none().0, signal_name.as_ptr() as *const _, Some(mem::transmute::<_, unsafe extern "C" fn()>( notify_trampoline:: as *const (), )), Box::into_raw(f), ) } fn notify<'a, N: Into<&'a str>>(&self, property_name: N) { let property_name = property_name.into(); unsafe { gobject_ffi::g_object_notify( self.as_object_ref().to_glib_none().0, property_name.to_glib_none().0, ); } } fn notify_by_pspec(&self, pspec: &crate::ParamSpec) { unsafe { gobject_ffi::g_object_notify_by_pspec( self.as_object_ref().to_glib_none().0, pspec.to_glib_none().0, ); } } fn downgrade(&self) -> WeakRef { unsafe { let w = WeakRef(Box::pin(mem::zeroed()), PhantomData); gobject_ffi::g_weak_ref_init( mut_override(&*w.0), self.as_object_ref().to_glib_none().0, ); w } } fn bind_property<'a, O: ObjectType, N: Into<&'a str>, M: Into<&'a str>>( &'a self, source_property: N, target: &'a O, target_property: M, ) -> BindingBuilder<'a> { let source_property = source_property.into(); let target_property = target_property.into(); BindingBuilder::new(self, source_property, target, target_property) } fn ref_count(&self) -> u32 { let stash = self.as_object_ref().to_glib_none(); let ptr: *mut gobject_ffi::GObject = stash.0; unsafe { ffi::g_atomic_int_get(&(*ptr).ref_count as *const u32 as *const i32) as u32 } } } // Validate that the given property value has an acceptable type for the given property pspec // and if necessary update the value fn validate_property_type( type_: Type, allow_construct_only: bool, pspec: &crate::ParamSpec, property_value: &mut Value, ) -> Result<(), BoolError> { if !pspec.flags().contains(crate::ParamFlags::WRITABLE) || (!allow_construct_only && pspec.flags().contains(crate::ParamFlags::CONSTRUCT_ONLY)) { return Err(bool_error!( "property '{}' of type '{}' is not writable", pspec.name(), type_ )); } unsafe { // While GLib actually allows all types that can somehow be transformed // into the property type, we're more restrictive here to be consistent // with Rust's type rules. We only allow the exact same type, or if the // value type is a subtype of the property type let valid_type: bool = from_glib(gobject_ffi::g_type_check_value_holds( mut_override(property_value.to_glib_none().0), pspec.value_type().into_glib(), )); // If it's not directly a valid type but an object type, we check if the // actual type of the contained object is compatible and if so create // a properly typed Value. This can happen if the type field in the // Value is set to a more generic type than the contained value if !valid_type && property_value.type_().is_a(Object::static_type()) { match property_value.get::>() { Ok(Some(obj)) => { if obj.type_().is_a(pspec.value_type()) { property_value.0.g_type = pspec.value_type().into_glib(); } else { return Err( bool_error!( "property '{}' of type '{}' can't be set from the given object type (expected: '{}', got: '{}')", pspec.name(), type_, pspec.value_type(), obj.type_(), ) ); } } Ok(None) => { // If the value is None then the type is compatible too property_value.0.g_type = pspec.value_type().into_glib(); } Err(_) => unreachable!("property_value type conformity already checked"), } } else if !valid_type { return Err(bool_error!(format!( "property '{}' of type '{}' can't be set from the given type (expected: '{}', got: '{}')", pspec.name(), type_, pspec.value_type(), property_value.type_(), ))); } let changed: bool = from_glib(gobject_ffi::g_param_value_validate( pspec.to_glib_none().0, property_value.to_glib_none_mut().0, )); let change_allowed = pspec.flags().contains(crate::ParamFlags::LAX_VALIDATION); if changed && !change_allowed { return Err(bool_error!( "property '{}' of type '{}' can't be set from given value, it is invalid or out of range", pspec.name(), type_, )); } } Ok(()) } fn validate_signal_arguments( type_: Type, signal_query: &SignalQuery, args: &mut [Value], ) -> Result { let signal_name = signal_query.signal_name(); let (signal_id, signal_detail) = SignalId::parse_name(signal_name, type_, false) .ok_or_else(|| bool_error!("Signal '{}' of type '{}' not found", signal_name, type_))?; let signal_query = signal_id.query(); if signal_query.n_params() != args.len() as u32 { return Err(bool_error!( "Incompatible number of arguments for signal '{}' of type '{}' (expected {}, got {})", signal_name, type_, signal_query.n_params(), args.len(), )); } let param_types = Iterator::zip(args.iter_mut(), signal_query.param_types()); for (i, (arg, param_type)) in param_types.enumerate() { let param_type: Type = param_type.into(); if arg.type_().is_a(Object::static_type()) { match arg.get::>() { Ok(Some(obj)) => { if obj.type_().is_a(param_type) { arg.0.g_type = param_type.into_glib(); } else { return Err( bool_error!( "Incompatible argument type in argument {} for signal '{}' of type '{}' (expected {}, got {})", i, signal_name, type_, param_type, arg.type_(), ) ); } } Ok(None) => { // If the value is None then the type is compatible too arg.0.g_type = param_type.into_glib(); } Err(_) => unreachable!("property_value type conformity already checked"), } } else if param_type != arg.type_() { return Err( bool_error!( "Incompatible argument type in argument {} for signal '{}' of type '{}' (expected {}, got {})", i, signal_name, type_, param_type, arg.type_(), ) ); } } Ok(signal_detail) } impl ObjectClass { pub fn has_property<'a, N: Into<&'a str>>( &self, property_name: N, type_: Option, ) -> bool { let property_name = property_name.into(); let ptype = self.property_type(property_name); match (ptype, type_) { (None, _) => false, (Some(_), None) => true, (Some(ptype), Some(type_)) => ptype == type_, } } #[doc(alias = "get_property_type")] pub fn property_type<'a, N: Into<&'a str>>(&self, property_name: N) -> Option { self.find_property(property_name) .map(|pspec| pspec.value_type()) } #[doc(alias = "g_object_class_find_property")] pub fn find_property<'a, N: Into<&'a str>>( &self, property_name: N, ) -> Option { let property_name = property_name.into(); unsafe { let klass = self as *const _ as *const gobject_ffi::GObjectClass; from_glib_none(gobject_ffi::g_object_class_find_property( klass as *mut _, property_name.to_glib_none().0, )) } } #[doc(alias = "g_object_class_list_properties")] pub fn list_properties(&self) -> Vec { unsafe { let klass = self as *const _ as *const gobject_ffi::GObjectClass; let mut n_properties = 0; let props = gobject_ffi::g_object_class_list_properties(klass as *mut _, &mut n_properties); FromGlibContainer::from_glib_container_num(props, n_properties as usize) } } } wrapper! { #[doc(alias = "GInitiallyUnowned")] pub struct InitiallyUnowned(Object); match fn { type_ => || gobject_ffi::g_initially_unowned_get_type(), } } #[derive(Debug)] #[doc(alias = "GWeakRef")] pub struct WeakRef(Pin>, PhantomData<*mut T>); impl WeakRef { pub fn new() -> WeakRef { unsafe { let mut w = WeakRef(Box::pin(mem::zeroed()), PhantomData); gobject_ffi::g_weak_ref_init( Pin::as_mut(&mut w.0).get_unchecked_mut(), ptr::null_mut(), ); w } } #[doc(alias = "g_weak_ref_set")] pub fn set(&self, obj: Option<&T>) { unsafe { gobject_ffi::g_weak_ref_set( mut_override(Pin::as_ref(&self.0).get_ref()), obj.map_or(std::ptr::null_mut(), |obj| { obj.as_object_ref().to_glib_none().0 }), ); } } pub fn upgrade(&self) -> Option { unsafe { let ptr = gobject_ffi::g_weak_ref_get(mut_override(Pin::as_ref(&self.0).get_ref())); if ptr.is_null() { None } else { let obj: Object = from_glib_full(ptr); Some(T::unsafe_from(obj.into())) } } } } impl Drop for WeakRef { fn drop(&mut self) { unsafe { gobject_ffi::g_weak_ref_clear(Pin::as_mut(&mut self.0).get_unchecked_mut()); } } } impl Clone for WeakRef { fn clone(&self) -> Self { unsafe { let o = self.upgrade(); let mut c = WeakRef(Box::pin(mem::zeroed()), PhantomData); gobject_ffi::g_weak_ref_init( Pin::as_mut(&mut c.0).get_unchecked_mut(), o.to_glib_none().0 as *mut gobject_ffi::GObject, ); c } } } impl Default for WeakRef { fn default() -> Self { Self::new() } } unsafe impl Sync for WeakRef {} unsafe impl Send for WeakRef {} /// A weak reference to the object it was created for that can be sent to /// different threads even for object types that don't implement `Send`. /// /// Trying to upgrade the weak reference from another thread than the one /// where it was created on will panic but dropping or cloning can be done /// safely from any thread. #[derive(Debug)] pub struct SendWeakRef(WeakRef, Option); impl SendWeakRef { pub fn new() -> SendWeakRef { SendWeakRef(WeakRef::new(), None) } pub fn into_weak_ref(self) -> WeakRef { if self.1.is_some() && self.1 != Some(thread_id()) { panic!("SendWeakRef dereferenced on a different thread"); } self.0 } } impl ops::Deref for SendWeakRef { type Target = WeakRef; fn deref(&self) -> &WeakRef { if self.1.is_some() && self.1 != Some(thread_id()) { panic!("SendWeakRef dereferenced on a different thread"); } &self.0 } } // Deriving this gives the wrong trait bounds impl Clone for SendWeakRef { fn clone(&self) -> Self { Self(self.0.clone(), self.1) } } impl Default for SendWeakRef { fn default() -> Self { Self::new() } } impl From> for SendWeakRef { fn from(v: WeakRef) -> SendWeakRef { SendWeakRef(v, Some(thread_id())) } } unsafe impl Sync for SendWeakRef {} unsafe impl Send for SendWeakRef {} #[derive(Debug)] #[must_use] pub struct BindingBuilder<'a> { source: &'a ObjectRef, source_property: &'a str, target: &'a ObjectRef, target_property: &'a str, flags: crate::BindingFlags, transform_to: Option, transform_from: Option, } impl<'a> BindingBuilder<'a> { fn new( source: &'a S, source_property: &'a str, target: &'a T, target_property: &'a str, ) -> Self { Self { source: source.as_object_ref(), source_property, target: target.as_object_ref(), target_property, flags: crate::BindingFlags::DEFAULT, transform_to: None, transform_from: None, } } fn transform_closure< F: Fn(&crate::Binding, &Value) -> Option + Send + Sync + 'static, >( func: F, ) -> crate::Closure { crate::Closure::new(move |values| { assert_eq!(values.len(), 3); let binding = values[0] .get::() .expect("Invalid GBinding argument"); let from = unsafe { let ptr = gobject_ffi::g_value_get_boxed(mut_override( &values[1] as *const Value as *const gobject_ffi::GValue, )); assert!(!ptr.is_null()); &*(ptr as *const gobject_ffi::GValue as *const Value) }; match func(&binding, from) { None => Some(false.to_value()), Some(value) => { unsafe { gobject_ffi::g_value_set_boxed( mut_override(&values[2] as *const Value as *const gobject_ffi::GValue), &value as *const Value as *const _, ); } Some(true.to_value()) } } }) } pub fn transform_from< F: Fn(&crate::Binding, &Value) -> Option + Send + Sync + 'static, >( self, func: F, ) -> Self { Self { transform_from: Some(Self::transform_closure(func)), ..self } } pub fn transform_to Option + Send + Sync + 'static>( self, func: F, ) -> Self { Self { transform_to: Some(Self::transform_closure(func)), ..self } } pub fn flags(self, flags: crate::BindingFlags) -> Self { Self { flags, ..self } } pub fn build(self) -> Option { unsafe { from_glib_none(gobject_ffi::g_object_bind_property_with_closures( self.source.to_glib_none().0, self.source_property.to_glib_none().0, self.target.to_glib_none().0, self.target_property.to_glib_none().0, self.flags.into_glib(), self.transform_to.to_glib_none().0, self.transform_from.to_glib_none().0, )) } } } /// Class struct of type `T`. #[repr(transparent)] pub struct Class(T::GlibClassType); impl Class { /// Get the type id for this class. /// /// This is not equivalent to `T::static_type()` but is the type of the subclass of `T` where /// this class belongs to. #[doc(alias = "get_type")] pub fn type_(&self) -> Type { unsafe { // This also works for interfaces because they also have the type // as the first struct field. let klass = self as *const _ as *const gobject_ffi::GTypeClass; from_glib((*klass).g_type) } } /// Casts this class to a reference to a parent type's class. pub fn upcast_ref(&self) -> &Class where T: IsA, { unsafe { let klass = self as *const _ as *const Class; &*klass } } /// Casts this class to a mutable reference to a parent type's class. pub fn upcast_ref_mut(&mut self) -> &mut Class where T: IsA, { unsafe { let klass = self as *mut _ as *mut Class; &mut *klass } } /// Casts this class to a reference to a child type's class or /// fails if this class is not implementing the child class. pub fn downcast_ref(&self) -> Option<&Class> where U: IsA, { if !self.type_().is_a(U::static_type()) { return None; } unsafe { let klass = self as *const _ as *const Class; Some(&*klass) } } /// Casts this class to a mutable reference to a child type's class or /// fails if this class is not implementing the child class. pub fn downcast_ref_mut(&mut self) -> Option<&mut Class> where U: IsA, { if !self.type_().is_a(U::static_type()) { return None; } unsafe { let klass = self as *mut _ as *mut Class; Some(&mut *klass) } } /// Gets the class struct for `Self` of `type_`. /// /// This will return `None` if `type_` is not a subclass of `Self`. pub fn from_type(type_: Type) -> Option> { if !type_.is_a(T::static_type()) { return None; } unsafe { let ptr = gobject_ffi::g_type_class_ref(type_.into_glib()); if ptr.is_null() { None } else { Some(ClassRef( ptr::NonNull::new_unchecked(ptr as *mut Self), true, PhantomData, )) } } } /// Gets the parent class struct, if any. #[doc(alias = "g_type_class_peek_parent")] pub fn parent(&self) -> Option> { unsafe { let ptr = gobject_ffi::g_type_class_peek_parent(&self.0 as *const _ as *mut _); if ptr.is_null() { None } else { Some(ClassRef( ptr::NonNull::new_unchecked(ptr as *mut Self), false, PhantomData, )) } } } } unsafe impl Send for Class {} unsafe impl Sync for Class {} impl AsRef for Class { fn as_ref(&self) -> &T::GlibClassType { &self.0 } } impl AsMut for Class { fn as_mut(&mut self) -> &mut T::GlibClassType { &mut self.0 } } /// Reference to the class struct of type `T`. #[derive(Debug)] pub struct ClassRef<'a, T: IsClass>(ptr::NonNull>, bool, PhantomData<&'a ()>); impl<'a, T: IsClass> ops::Deref for ClassRef<'a, T> { type Target = Class; fn deref(&self) -> &Class { unsafe { self.0.as_ref() } } } impl<'a, T: IsClass> Drop for ClassRef<'a, T> { fn drop(&mut self) { if self.1 { unsafe { gobject_ffi::g_type_class_unref(self.0.as_ptr() as *mut _); } } } } unsafe impl<'a, T: IsClass> Send for ClassRef<'a, T> {} unsafe impl<'a, T: IsClass> Sync for ClassRef<'a, T> {} // This should require Self: IsA, but that seems to cause a cycle error pub unsafe trait ParentClassIs: IsClass { type Parent: IsClass; } /// Automatically implemented by `ObjectSubclass` variants of /// [`wrapper!`][crate::wrapper!] pub unsafe trait ObjectSubclassIs: IsClass { type Subclass: ObjectSubclass; } impl ops::Deref for Class { type Target = Class; fn deref(&self) -> &Self::Target { unsafe { let klass = self as *const _ as *const Self::Target; &*klass } } } impl ops::DerefMut for Class { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { let klass = self as *mut _ as *mut Self::Target; &mut *klass } } } /// Trait implemented by class types. pub unsafe trait IsClass: ObjectType {} /// Interface struct of type `T` for some type. #[repr(transparent)] pub struct Interface(T::GlibClassType); impl Interface { /// Get the type id for this interface. /// /// This is equivalent to `T::static_type()`. #[doc(alias = "get_type")] pub fn type_(&self) -> Type { unsafe { let klass = self as *const _ as *const gobject_ffi::GTypeInterface; from_glib((*klass).g_type) } } /// Get the type id for the instance type of this interface. /// /// This is not equivalent to `T::static_type()` but is the type id of the type this specific /// interface belongs to. #[doc(alias = "get_instance_type")] pub fn instance_type(&self) -> Type { unsafe { // This also works for interfaces because they also have the type // as the first struct field. let klass = self as *const _ as *const gobject_ffi::GTypeInterface; from_glib((*klass).g_instance_type) } } /// Gets the interface struct for `Self` of `klass`. /// /// This will return `None` if `klass` is not implementing `Self`. pub fn from_class(klass: &Class) -> Option> { if !klass.type_().is_a(T::static_type()) { return None; } unsafe { let ptr = gobject_ffi::g_type_interface_peek( &klass.0 as *const _ as *mut _, T::static_type().into_glib(), ); if ptr.is_null() { None } else { Some(InterfaceRef( ptr::NonNull::new_unchecked(ptr as *mut Self), false, PhantomData, )) } } } /// Gets the default interface struct for `Self`. /// /// This will return `None` if `type_` is not an interface. pub fn from_type(type_: Type) -> Option> { if !type_.is_a(Type::INTERFACE) { return None; } unsafe { let ptr = gobject_ffi::g_type_default_interface_ref(T::static_type().into_glib()); if ptr.is_null() { None } else { Some(InterfaceRef( ptr::NonNull::new_unchecked(ptr as *mut Self), true, PhantomData, )) } } } /// Gets the default interface struct for `Self`. #[doc(alias = "g_type_default_interface_ref")] pub fn default() -> InterfaceRef<'static, T> { unsafe { let ptr = gobject_ffi::g_type_default_interface_ref(T::static_type().into_glib()); assert!(!ptr.is_null()); InterfaceRef( ptr::NonNull::new_unchecked(ptr as *mut Self), true, PhantomData, ) } } /// Gets the parent interface struct, if any. /// /// This returns the parent interface if a parent type of the instance type also implements the /// interface. #[doc(alias = "g_type_interface_peek_parent")] pub fn parent(&self) -> Option> { unsafe { let ptr = gobject_ffi::g_type_interface_peek_parent(&self.0 as *const _ as *mut _); if ptr.is_null() { None } else { Some(InterfaceRef( ptr::NonNull::new_unchecked(ptr as *mut Self), false, PhantomData, )) } } } } impl + IsInterface> Interface { pub fn has_property<'a, N: Into<&'a str>>( &self, property_name: N, type_: Option, ) -> bool { let property_name = property_name.into(); let ptype = self.property_type(property_name); match (ptype, type_) { (None, _) => false, (Some(_), None) => true, (Some(ptype), Some(type_)) => ptype == type_, } } #[doc(alias = "get_property_type")] pub fn property_type<'a, N: Into<&'a str>>(&self, property_name: N) -> Option { self.find_property(property_name) .map(|pspec| pspec.value_type()) } #[doc(alias = "g_object_interface_find_property")] pub fn find_property<'a, N: Into<&'a str>>( &self, property_name: N, ) -> Option { let property_name = property_name.into(); unsafe { let interface = self as *const _ as *const gobject_ffi::GTypeInterface; from_glib_none(gobject_ffi::g_object_interface_find_property( interface as *mut _, property_name.to_glib_none().0, )) } } #[doc(alias = "g_object_interface_list_properties")] pub fn list_properties(&self) -> Vec { unsafe { let interface = self as *const _ as *const gobject_ffi::GTypeInterface; let mut n_properties = 0; let props = gobject_ffi::g_object_interface_list_properties( interface as *mut _, &mut n_properties, ); FromGlibContainer::from_glib_container_num(props, n_properties as usize) } } } unsafe impl Send for Interface {} unsafe impl Sync for Interface {} impl AsRef for Interface { fn as_ref(&self) -> &T::GlibClassType { &self.0 } } impl AsMut for Interface { fn as_mut(&mut self) -> &mut T::GlibClassType { &mut self.0 } } /// Reference to a class struct of type `T`. #[derive(Debug)] pub struct InterfaceRef<'a, T: IsInterface>(ptr::NonNull>, bool, PhantomData<&'a ()>); impl<'a, T: IsInterface> Drop for InterfaceRef<'a, T> { fn drop(&mut self) { if self.1 { unsafe { gobject_ffi::g_type_default_interface_unref(self.0.as_ptr() as *mut _); } } } } impl<'a, T: IsInterface> ops::Deref for InterfaceRef<'a, T> { type Target = Interface; fn deref(&self) -> &Interface { unsafe { self.0.as_ref() } } } unsafe impl<'a, T: IsInterface> Send for InterfaceRef<'a, T> {} unsafe impl<'a, T: IsInterface> Sync for InterfaceRef<'a, T> {} /// Trait implemented by interface types. pub unsafe trait IsInterface: ObjectType {} #[cfg(test)] mod tests { use super::*; #[test] fn new() { let obj: Object = Object::new(&[]).unwrap(); drop(obj); } #[test] fn data() { let obj: Object = Object::new(&[]).unwrap(); unsafe { obj.set_data::("foo", "hello".into()); let data = obj.data::("foo").unwrap(); assert_eq!(data.as_ref(), "hello"); let data2 = obj.steal_data::("foo").unwrap(); assert_eq!(data2, "hello"); } } #[test] fn weak_ref() { let obj: Object = Object::new(&[]).unwrap(); let weakref: WeakRef = WeakRef::new(); weakref.set(Some(&obj)); assert!(weakref.upgrade().is_some()); weakref.set(None); assert!(weakref.upgrade().is_none()); let weakref = WeakRef::new(); weakref.set(Some(&obj)); assert!(weakref.upgrade().is_some()); drop(obj); assert!(weakref.upgrade().is_none()); } } glib-0.14.8/src/param_spec.rs000064400000000000000000001004330072674642500141330ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::*; use crate::utils::is_canonical_pspec_name; use crate::ParamFlags; use crate::StaticType; use crate::Type; use crate::Value; use std::char::CharTryFromError; use std::convert::TryFrom; use std::ffi::CStr; // Can't use get_type here as this is not a boxed type but another fundamental type wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpec")] pub struct ParamSpec(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr), unref => |ptr| gobject_ffi::g_param_spec_unref(ptr), } } impl StaticType for ParamSpec { fn static_type() -> Type { unsafe { from_glib(gobject_ffi::G_TYPE_PARAM) } } } #[doc(hidden)] impl crate::value::ValueType for ParamSpec { type Type = ParamSpec; } #[doc(hidden)] unsafe impl<'a> crate::value::FromValue<'a> for ParamSpec { type Checker = crate::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a crate::Value) -> Self { let ptr = gobject_ffi::g_value_dup_param(value.to_glib_none().0); assert!(!ptr.is_null()); from_glib_full(ptr as *mut gobject_ffi::GParamSpec) } } #[doc(hidden)] impl crate::value::ToValue for ParamSpec { fn to_value(&self) -> crate::Value { unsafe { let mut value = crate::Value::from_type(ParamSpec::static_type()); gobject_ffi::g_value_take_param( value.to_glib_none_mut().0, self.to_glib_full() as *mut _, ); value } } fn value_type(&self) -> crate::Type { ParamSpec::static_type() } } #[doc(hidden)] impl crate::value::ToValueOptional for ParamSpec { fn to_value_optional(s: Option<&Self>) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { gobject_ffi::g_value_take_param(value.to_glib_none_mut().0, s.to_glib_full() as *mut _); } value } } unsafe impl Send for ParamSpec {} unsafe impl Sync for ParamSpec {} impl ParamSpec { pub fn downcast(self) -> Result { unsafe { if self.type_() == T::static_type() { Ok(from_glib_full(self.to_glib_full())) } else { Err(self) } } } pub fn downcast_ref(&self) -> Option<&T> { unsafe { if self.type_() == T::static_type() { Some(&*(self as *const ParamSpec as *const T)) } else { None } } } #[doc(alias = "get_type")] pub fn type_(&self) -> Type { unsafe { let ptr = self.to_glib_none().0; from_glib((*(*ptr).g_type_instance.g_class).g_type) } } #[doc(alias = "get_value_type")] pub fn value_type(&self) -> crate::Type { unsafe { from_glib((*self.to_glib_none().0).value_type) } } #[doc(alias = "get_owner_type")] pub fn owner_type(&self) -> crate::Type { unsafe { from_glib((*self.to_glib_none().0).owner_type) } } #[doc(alias = "get_flags")] pub fn flags(&self) -> ParamFlags { unsafe { from_glib((*self.to_glib_none().0).flags) } } #[doc(alias = "g_param_spec_get_blurb")] #[doc(alias = "get_blurb")] pub fn blurb(&self) -> &str { unsafe { CStr::from_ptr(gobject_ffi::g_param_spec_get_blurb(self.to_glib_none().0)) .to_str() .unwrap() } } #[doc(alias = "g_param_spec_get_default_value")] #[doc(alias = "get_default_value")] pub fn default_value(&self) -> &Value { unsafe { &*(gobject_ffi::g_param_spec_get_default_value(self.to_glib_none().0) as *const crate::Value) } } #[doc(alias = "g_param_spec_get_name")] #[doc(alias = "get_name")] pub fn name<'a>(&self) -> &'a str { unsafe { CStr::from_ptr(gobject_ffi::g_param_spec_get_name(self.to_glib_none().0)) .to_str() .unwrap() } } #[doc(alias = "g_param_spec_get_name_quark")] #[doc(alias = "get_name_quark")] pub fn name_quark(&self) -> crate::Quark { unsafe { from_glib(gobject_ffi::g_param_spec_get_name_quark( self.to_glib_none().0, )) } } #[doc(alias = "g_param_spec_get_nick")] #[doc(alias = "get_nick")] pub fn nick(&self) -> &str { unsafe { CStr::from_ptr(gobject_ffi::g_param_spec_get_nick(self.to_glib_none().0)) .to_str() .unwrap() } } //pub fn get_qdata(&self, quark: /*Ignored*/glib::Quark) -> /*Unimplemented*/Option { // unsafe { TODO: call gobject_ffi::g_param_spec_get_qdata() } //} #[doc(alias = "g_param_spec_get_redirect_target")] #[doc(alias = "get_redirect_target")] pub fn redirect_target(&self) -> Option { unsafe { from_glib_none(gobject_ffi::g_param_spec_get_redirect_target( self.to_glib_none().0, )) } } //pub fn set_qdata(&self, quark: /*Ignored*/glib::Quark, data: Option) { // unsafe { TODO: call gobject_ffi::g_param_spec_set_qdata() } //} //pub fn set_qdata_full(&self, quark: /*Ignored*/glib::Quark, data: Option, destroy: /*Unknown conversion*//*Unimplemented*/DestroyNotify) { // unsafe { TODO: call gobject_ffi::g_param_spec_set_qdata_full() } //} //pub fn steal_qdata(&self, quark: /*Ignored*/glib::Quark) -> /*Unimplemented*/Option { // unsafe { TODO: call gobject_ffi::g_param_spec_steal_qdata() } //} #[doc(alias = "g_param_spec_boolean")] pub fn new_boolean( name: &str, nick: &str, blurb: &str, default_value: bool, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_boolean( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, default_value.into_glib(), flags.into_glib(), )) } } #[doc(alias = "g_param_spec_boxed")] pub fn new_boxed( name: &str, nick: &str, blurb: &str, boxed_type: crate::Type, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_boxed( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, boxed_type.into_glib(), flags.into_glib(), )) } } #[doc(alias = "g_param_spec_char")] pub fn new_char( name: &str, nick: &str, blurb: &str, minimum: i8, maximum: i8, default_value: i8, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_char( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.into_glib(), )) } } #[doc(alias = "g_param_spec_double")] pub fn new_double( name: &str, nick: &str, blurb: &str, minimum: f64, maximum: f64, default_value: f64, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_double( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.into_glib(), )) } } #[doc(alias = "g_param_spec_enum")] pub fn new_enum( name: &str, nick: &str, blurb: &str, enum_type: crate::Type, default_value: i32, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_enum( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, enum_type.into_glib(), default_value, flags.into_glib(), )) } } #[doc(alias = "g_param_spec_flags")] pub fn new_flags( name: &str, nick: &str, blurb: &str, flags_type: crate::Type, default_value: u32, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_flags( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, flags_type.into_glib(), default_value, flags.into_glib(), )) } } #[doc(alias = "g_param_spec_float")] pub fn new_float( name: &str, nick: &str, blurb: &str, minimum: f32, maximum: f32, default_value: f32, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_float( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.into_glib(), )) } } #[doc(alias = "g_param_spec_gtype")] pub fn new_type( name: &str, nick: &str, blurb: &str, is_a_type: crate::Type, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_gtype( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, is_a_type.into_glib(), flags.into_glib(), )) } } #[doc(alias = "g_param_spec_int")] pub fn new_int( name: &str, nick: &str, blurb: &str, minimum: i32, maximum: i32, default_value: i32, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_int( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.into_glib(), )) } } #[doc(alias = "g_param_spec_int64")] pub fn new_int64( name: &str, nick: &str, blurb: &str, minimum: i64, maximum: i64, default_value: i64, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_int64( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.into_glib(), )) } } #[doc(alias = "g_param_spec_long")] pub fn new_long( name: &str, nick: &str, blurb: &str, minimum: libc::c_long, maximum: libc::c_long, default_value: libc::c_long, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_long( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.into_glib(), )) } } #[doc(alias = "g_param_spec_object")] pub fn new_object( name: &str, nick: &str, blurb: &str, object_type: crate::Type, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_object( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, object_type.into_glib(), flags.into_glib(), )) } } #[doc(alias = "g_param_spec_override")] pub fn new_override(name: &str, overridden: &ParamSpec) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_override( name.to_glib_none().0, overridden.to_glib_none().0, )) } } #[doc(alias = "g_param_spec_param")] pub fn new_param( name: &str, nick: &str, blurb: &str, param_type: crate::Type, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_param( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, param_type.into_glib(), flags.into_glib(), )) } } #[doc(alias = "g_param_spec_pointer")] pub fn new_pointer(name: &str, nick: &str, blurb: &str, flags: ParamFlags) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_pointer( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, flags.into_glib(), )) } } #[doc(alias = "g_param_spec_string")] pub fn new_string( name: &str, nick: &str, blurb: &str, default_value: Option<&str>, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); let default_value = default_value.to_glib_none(); unsafe { from_glib_none(gobject_ffi::g_param_spec_string( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, default_value.0, flags.into_glib(), )) } } #[doc(alias = "g_param_spec_uchar")] pub fn new_uchar( name: &str, nick: &str, blurb: &str, minimum: u8, maximum: u8, default_value: u8, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_uchar( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.into_glib(), )) } } #[doc(alias = "g_param_spec_uint")] pub fn new_uint( name: &str, nick: &str, blurb: &str, minimum: u32, maximum: u32, default_value: u32, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_uint( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.into_glib(), )) } } #[doc(alias = "g_param_spec_uint64")] pub fn new_uint64( name: &str, nick: &str, blurb: &str, minimum: u64, maximum: u64, default_value: u64, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_uint64( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.into_glib(), )) } } #[doc(alias = "g_param_spec_ulong")] pub fn new_ulong( name: &str, nick: &str, blurb: &str, minimum: libc::c_ulong, maximum: libc::c_ulong, default_value: libc::c_ulong, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_ulong( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.into_glib(), )) } } #[doc(alias = "g_param_spec_unichar")] pub fn new_unichar( name: &str, nick: &str, blurb: &str, default_value: char, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_unichar( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, default_value.into_glib(), flags.into_glib(), )) } } #[doc(alias = "g_param_spec_value_array")] pub fn new_value_array( name: &str, nick: &str, blurb: &str, element_spec: &ParamSpec, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_value_array( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, element_spec.to_glib_none().0, flags.into_glib(), )) } } #[doc(alias = "g_param_spec_variant")] pub fn new_variant( name: &str, nick: &str, blurb: &str, type_: &crate::VariantTy, default_value: Option<&crate::Variant>, flags: ParamFlags, ) -> ParamSpec { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical parameter name", name ); unsafe { from_glib_none(gobject_ffi::g_param_spec_variant( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, type_.to_glib_none().0, default_value.to_glib_none().0, flags.into_glib(), )) } } } pub unsafe trait ParamSpecType: StaticType + FromGlibPtrFull<*mut gobject_ffi::GParamSpec> + 'static { } #[link(name = "gobject-2.0")] extern "C" { pub static g_param_spec_types: *const ffi::GType; } macro_rules! define_param_spec { ($rust_type:ident, $ffi_type:path, $mod_name:ident, $rust_type_offset:expr) => { // Can't use get_type here as this is not a boxed type but another fundamental type wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct $rust_type(Shared<$ffi_type>); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut $ffi_type, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } impl StaticType for $rust_type { fn static_type() -> Type { unsafe { from_glib(*g_param_spec_types.add($rust_type_offset)) } } } #[doc(hidden)] impl crate::value::ValueType for $rust_type { type Type = $rust_type; } #[doc(hidden)] unsafe impl<'a> crate::value::FromValue<'a> for $rust_type { type Checker = $crate::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a crate::Value) -> Self { let ptr = gobject_ffi::g_value_dup_param(value.to_glib_none().0); assert!(!ptr.is_null()); from_glib_full(ptr as *mut $ffi_type) } } #[doc(hidden)] impl crate::value::ToValue for $rust_type { fn to_value(&self) -> crate::Value { unsafe { let mut value = crate::Value::from_type($rust_type::static_type()); gobject_ffi::g_value_take_param(value.to_glib_none_mut().0, self.to_glib_full() as *mut _); value } } fn value_type(&self) -> crate::Type { $rust_type::static_type() } } #[doc(hidden)] impl crate::value::ToValueOptional for $rust_type { fn to_value_optional(s: Option<&Self>) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { gobject_ffi::g_value_take_param(value.to_glib_none_mut().0, s.to_glib_full() as *mut _); } value } } unsafe impl Send for $rust_type {} unsafe impl Sync for $rust_type {} impl std::ops::Deref for $rust_type { type Target = ParamSpec; fn deref(&self) -> &Self::Target { unsafe { &*(self as *const $rust_type as *const ParamSpec) } } } unsafe impl ParamSpecType for $rust_type {} #[doc(hidden)] impl FromGlibPtrFull<*mut gobject_ffi::GParamSpec> for $rust_type { unsafe fn from_glib_full(ptr: *mut gobject_ffi::GParamSpec) -> Self { from_glib_full(ptr as *mut $ffi_type) } } impl $rust_type { pub fn upcast(self) -> ParamSpec { unsafe { from_glib_full(self.to_glib_full() as *mut gobject_ffi::GParamSpec) } } pub fn upcast_ref(&self) -> &ParamSpec { &*self } } }; } macro_rules! define_param_spec_default { ($rust_type:ident, $value_type:ty, $from_glib:expr) => { impl $rust_type { pub fn default_value(&self) -> $value_type { unsafe { let ptr = self.to_glib_none().0; $from_glib((*ptr).default_value) } } } }; } macro_rules! define_param_spec_min_max { ($rust_type:ident, $value_type:ty, $from_glib:expr) => { impl $rust_type { pub fn minimum(&self) -> $value_type { unsafe { let ptr = self.to_glib_none().0; $from_glib((*ptr).minimum) } } pub fn maximum(&self) -> $value_type { unsafe { let ptr = self.to_glib_none().0; $from_glib((*ptr).maximum) } } } }; } macro_rules! define_param_spec_numeric { ($rust_type:ident, $ffi_type:path, $value_type:ty, $mod_name:ident, $rust_type_offset:expr, $from_glib:expr) => { define_param_spec!($rust_type, $ffi_type, $mod_name, $rust_type_offset); define_param_spec_default!($rust_type, $value_type, $from_glib); define_param_spec_min_max!($rust_type, $value_type, $from_glib); }; } define_param_spec_numeric!( ParamSpecChar, gobject_ffi::GParamSpecChar, i8, param_spec_char, 0, |x| x ); define_param_spec_numeric!( ParamSpecUChar, gobject_ffi::GParamSpecUChar, u8, param_spec_uchar, 1, |x| x ); define_param_spec!( ParamSpecBoolean, gobject_ffi::GParamSpecBoolean, param_spec_bool, 2 ); define_param_spec_default!(ParamSpecBoolean, bool, |x| from_glib(x)); define_param_spec_numeric!( ParamSpecInt, gobject_ffi::GParamSpecInt, i32, param_spec_int, 3, |x| x ); define_param_spec_numeric!( ParamSpecUInt, gobject_ffi::GParamSpecUInt, u32, param_spec_uint, 4, |x| x ); define_param_spec_numeric!( ParamSpecLong, gobject_ffi::GParamSpecLong, libc::c_long, param_spec_long, 5, |x| x ); define_param_spec_numeric!( ParamSpecULong, gobject_ffi::GParamSpecULong, libc::c_ulong, param_spec_ulong, 6, |x| x ); define_param_spec_numeric!( ParamSpecInt64, gobject_ffi::GParamSpecInt64, i64, param_spec_int64, 7, |x| x ); define_param_spec_numeric!( ParamSpecUInt64, gobject_ffi::GParamSpecUInt64, u64, param_spec_uint64, 8, |x| x ); define_param_spec!( ParamSpecUnichar, gobject_ffi::GParamSpecUnichar, param_spec_unichar, 9 ); define_param_spec_default!(ParamSpecUnichar, Result, TryFrom::try_from); define_param_spec!( ParamSpecEnum, gobject_ffi::GParamSpecEnum, param_spec_enum, 10 ); define_param_spec_default!(ParamSpecEnum, i32, |x| x); impl ParamSpecEnum { #[doc(alias = "get_enum_class")] pub fn enum_class(&self) -> crate::EnumClass { unsafe { let ptr = self.to_glib_none().0; assert!(!(*ptr).enum_class.is_null()); crate::EnumClass::new(from_glib((*(*ptr).enum_class).g_type_class.g_type)) .expect("Invalid enum class") } } } define_param_spec!( ParamSpecFlags, gobject_ffi::GParamSpecFlags, param_spec_flags, 11 ); define_param_spec_default!(ParamSpecFlags, u32, |x| x); impl ParamSpecFlags { #[doc(alias = "get_flags_class")] pub fn flags_class(&self) -> crate::FlagsClass { unsafe { let ptr = self.to_glib_none().0; assert!(!(*ptr).flags_class.is_null()); crate::FlagsClass::new(from_glib((*(*ptr).flags_class).g_type_class.g_type)) .expect("Invalid flags class") } } } define_param_spec_numeric!( ParamSpecFloat, gobject_ffi::GParamSpecFloat, f32, param_spec_float, 12, |x| x ); define_param_spec_numeric!( ParamSpecDouble, gobject_ffi::GParamSpecDouble, f64, param_spec_double, 13, |x| x ); define_param_spec!( ParamSpecString, gobject_ffi::GParamSpecString, param_spec_string, 14 ); define_param_spec_default!(ParamSpecString, Option<&str>, |x: *mut libc::c_char| { use std::ffi::CStr; if x.is_null() { None } else { Some(CStr::from_ptr(x).to_str().unwrap()) } }); define_param_spec!( ParamSpecParam, gobject_ffi::GParamSpecParam, param_spec_param, 15 ); define_param_spec!( ParamSpecBoxed, gobject_ffi::GParamSpecBoxed, param_spec_boxed, 16 ); define_param_spec!( ParamSpecPointer, gobject_ffi::GParamSpecPointer, param_spec_pointer, 17 ); define_param_spec!( ParamSpecValueArray, gobject_ffi::GParamSpecValueArray, param_spec_value_array, 18 ); impl ParamSpecValueArray { #[doc(alias = "get_element_spec")] pub fn element_spec(&self) -> Option { unsafe { let ptr = self.to_glib_none().0; from_glib_none((*ptr).element_spec) } } #[doc(alias = "get_fixed_n_elements")] pub fn fixed_n_elements(&self) -> u32 { unsafe { let ptr = self.to_glib_none().0; (*ptr).fixed_n_elements } } } define_param_spec!( ParamSpecObject, gobject_ffi::GParamSpecObject, param_spec_object, 19 ); define_param_spec!( ParamSpecOverride, gobject_ffi::GParamSpecOverride, param_spec_override, 20 ); impl ParamSpecOverride { #[doc(alias = "get_overridden")] pub fn overridden(&self) -> ParamSpec { unsafe { let ptr = self.to_glib_none().0; from_glib_none((*ptr).overridden) } } } define_param_spec!( ParamSpecGType, gobject_ffi::GParamSpecGType, param_spec_gtype, 21 ); define_param_spec!( ParamSpecVariant, gobject_ffi::GParamSpecVariant, param_spec_variant, 22 ); define_param_spec_default!( ParamSpecVariant, Option, |x: *mut ffi::GVariant| from_glib_none(x) ); impl ParamSpecVariant { #[doc(alias = "get_type")] pub fn type_(&self) -> Option<&crate::VariantTy> { unsafe { let ptr = self.to_glib_none().0; if (*ptr).type_.is_null() { None } else { Some(crate::VariantTy::from_ptr((*ptr).type_)) } } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_param_spec_string() { let pspec = ParamSpec::new_string( "name", "nick", "blurb", Some("default"), ParamFlags::READWRITE, ); assert_eq!(pspec.name(), "name"); assert_eq!(pspec.nick(), "nick"); assert_eq!(pspec.blurb(), "blurb"); let default_value = pspec.default_value(); assert_eq!(default_value.get::<&str>().unwrap(), "default"); assert_eq!(pspec.flags(), ParamFlags::READWRITE); assert_eq!(pspec.value_type(), Type::STRING); assert_eq!(pspec.type_(), ParamSpecString::static_type()); let pspec_ref = pspec .downcast_ref::() .expect("Not a string param spec"); assert_eq!(pspec_ref.default_value(), Some("default")); let pspec = pspec .downcast::() .expect("Not a string param spec"); assert_eq!(pspec.default_value(), Some("default")); } } glib-0.14.8/src/prelude.rs000064400000000000000000000004460072674642500134640ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! Traits and essential types intended for blanket imports. pub use crate::{ Cast, Continue, IsA, ObjectExt, ObjectType, ParamSpecType, StaticType, StaticVariantType, ToSendValue, ToValue, ToVariant, }; glib-0.14.8/src/quark.rs000064400000000000000000000026500072674642500131460ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::*; use std::ffi::CStr; use std::fmt; #[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[repr(transparent)] #[doc(alias = "GQuark")] pub struct Quark(ffi::GQuark); impl Quark { #[doc(alias = "g_quark_from_string")] pub fn from_string(s: &str) -> Quark { unsafe { from_glib(ffi::g_quark_from_string(s.to_glib_none().0)) } } #[allow(clippy::trivially_copy_pass_by_ref)] #[doc(alias = "g_quark_to_string")] pub fn to_string<'a>(&self) -> &'a str { unsafe { CStr::from_ptr(ffi::g_quark_to_string(self.into_glib())) .to_str() .unwrap() } } #[doc(alias = "g_quark_try_string")] pub fn try_string(s: &str) -> Option { unsafe { match ffi::g_quark_try_string(s.to_glib_none().0) { 0 => None, x => Some(from_glib(x)), } } } } impl fmt::Debug for Quark { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.write_str(Quark::to_string(self)) } } #[doc(hidden)] impl FromGlib for Quark { unsafe fn from_glib(value: ffi::GQuark) -> Self { Self(value) } } #[doc(hidden)] impl IntoGlib for Quark { type GlibType = ffi::GQuark; fn into_glib(self) -> ffi::GQuark { self.0 } } glib-0.14.8/src/send_unique.rs000064400000000000000000000104320072674642500143370ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::cell::RefCell; use std::ops; /// Like `Send` but only if we have the unique reference to the object /// /// Note that implementing this trait has to be done especially careful. /// It must only be implemented on types where the uniqueness of a reference /// can be determined, i.e. the reference count field is accessible, and it /// must only have references itself to other types that are `Send`. /// `SendUnique` is *not* enough for the other types unless uniqueness of /// all of them can be guaranteed, which is e.g. not the case if there's a /// getter for them. pub unsafe trait SendUnique: 'static { fn is_unique(&self) -> bool; } /// Allows sending reference counted objects that don't implement `Send` to other threads /// as long as only a single reference to the object exists. #[derive(Debug)] pub struct SendUniqueCell { obj: T, // Thread id and refcount thread: RefCell>, } unsafe impl Send for SendUniqueCell {} #[derive(Debug)] pub struct BorrowError; impl SendUniqueCell { /// Create a new `SendUniqueCell` out of `obj` /// /// Fails if `obj` is not unique at this time pub fn new(obj: T) -> Result { if !obj.is_unique() { return Err(obj); } Ok(SendUniqueCell { obj, thread: RefCell::new(None), }) } /// Borrow the contained object or panic if borrowing /// is not possible at this time pub fn borrow(&self) -> Ref { #[allow(clippy::match_wild_err_arm)] match self.try_borrow() { Err(_) => panic!("Can't borrow"), Ok(r) => r, } } /// Try borrowing the contained object /// /// Borrowing is possible as long as only a single reference /// to the object exists, or it is borrowed from the same /// thread currently pub fn try_borrow(&self) -> Result, BorrowError> { let mut thread = self.thread.borrow_mut(); // If the object is unique, we can borrow it from // any thread we want and just have to keep track // how often we borrowed it if self.obj.is_unique() { if *thread == None { *thread = Some((crate::thread_id(), 1)); } else { thread.as_mut().unwrap().1 += 1; } return Ok(Ref(self)); } // If we don't even know from which thread it is borrowed, this // means it somehow got borrowed from outside the SendUniqueCell if *thread == None { return Err(BorrowError); } // If the object is not unique, we can only borrow it // from the thread that currently has it borrowed if thread.as_ref().unwrap().0 != crate::thread_id() { return Err(BorrowError); } thread.as_mut().unwrap().1 += 1; Ok(Ref(self)) } /// Extract the contained object or panic if it is not possible /// at this time pub fn into_inner(self) -> T { #[allow(clippy::match_wild_err_arm)] match self.try_into_inner() { Err(_) => panic!("Can't convert into inner type"), Ok(obj) => obj, } } /// Try extracting the contained object /// /// Borrowing is possible as long as only a single reference /// to the object exists, or it is borrowed from the same /// thread currently pub fn try_into_inner(self) -> Result { if self.try_borrow().is_err() { Err(self) } else { Ok(self.obj) } } } pub struct Ref<'a, T: SendUnique>(&'a SendUniqueCell); impl<'a, T: SendUnique> AsRef for Ref<'a, T> { fn as_ref(&self) -> &T { &self.0.obj } } impl<'a, T: SendUnique> ops::Deref for Ref<'a, T> { type Target = T; fn deref(&self) -> &T { &self.0.obj } } impl<'a, T: SendUnique> Drop for Ref<'a, T> { fn drop(&mut self) { let is_unique = self.0.obj.is_unique(); let mut thread = self.0.thread.borrow_mut(); if is_unique && thread.as_ref().unwrap().1 == 1 { *thread = None; } else { thread.as_mut().unwrap().1 -= 1; } } } glib-0.14.8/src/shared.rs000064400000000000000000000373510072674642500132770ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! `IMPL` Shared (reference counted) wrapper implementation. use crate::translate::*; use std::cmp; use std::fmt; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::ptr; /// Wrapper implementations for shared types. See `wrapper!`. #[macro_export] macro_rules! glib_shared_wrapper { ([$($attr:meta)*] $name:ident, $ffi_name:ty, @ref $ref_arg:ident $ref_expr:expr, @unref $unref_arg:ident $unref_expr:expr, @type_ $get_type_expr:expr) => { $crate::glib_shared_wrapper!([$($attr)*] $name, $ffi_name, @ref $ref_arg $ref_expr, @unref $unref_arg $unref_expr); impl $crate::types::StaticType for $name { fn static_type() -> $crate::types::Type { #[allow(unused_unsafe)] unsafe { $crate::translate::from_glib($get_type_expr) } } } #[doc(hidden)] impl $crate::value::ValueType for $name { type Type = $name; } #[doc(hidden)] unsafe impl<'a> $crate::value::FromValue<'a> for $name { type Checker = $crate::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a $crate::Value) -> Self { let ptr = $crate::gobject_ffi::g_value_dup_boxed($crate::translate::ToGlibPtr::to_glib_none(value).0); assert!(!ptr.is_null()); <$name as $crate::translate::FromGlibPtrFull<*mut $ffi_name>>::from_glib_full(ptr as *mut $ffi_name) } } #[doc(hidden)] impl $crate::value::ToValue for $name { fn to_value(&self) -> $crate::Value { unsafe { let mut value = $crate::Value::from_type(<$name as $crate::StaticType>::static_type()); $crate::gobject_ffi::g_value_take_boxed( $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::translate::ToGlibPtr::<*mut $ffi_name>::to_glib_full(self) as *mut _, ); value } } fn value_type(&self) -> $crate::Type { <$name as $crate::StaticType>::static_type() } } #[doc(hidden)] impl $crate::value::ToValueOptional for $name { fn to_value_optional(s: Option<&Self>) -> $crate::Value { let mut value = $crate::Value::for_value_type::(); unsafe { $crate::gobject_ffi::g_value_take_boxed( $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::translate::ToGlibPtr::<*mut $ffi_name>::to_glib_full(&s) as *mut _, ); } value } } }; ([$($attr:meta)*] $name:ident, $ffi_name:ty, @ref $ref_arg:ident $ref_expr:expr, @unref $unref_arg:ident $unref_expr:expr) => { $(#[$attr])* #[derive(Clone)] pub struct $name($crate::shared::Shared<$ffi_name, $name>); #[doc(hidden)] impl $crate::shared::SharedMemoryManager<$ffi_name> for $name { #[inline] unsafe fn ref_($ref_arg: *mut $ffi_name) { $ref_expr; } #[inline] #[allow(clippy::no_effect)] unsafe fn unref($unref_arg: *mut $ffi_name) { $unref_expr; } } #[doc(hidden)] impl $crate::translate::GlibPtrDefault for $name { type GlibType = *mut $ffi_name; } #[doc(hidden)] impl<'a> $crate::translate::ToGlibPtr<'a, *mut $ffi_name> for $name { type Storage = &'a $crate::shared::Shared<$ffi_name, $name>; #[inline] fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *mut $ffi_name, Self> { let stash = $crate::translate::ToGlibPtr::to_glib_none(&self.0); $crate::translate::Stash(stash.0, stash.1) } #[inline] fn to_glib_full(&self) -> *mut $ffi_name { $crate::translate::ToGlibPtr::to_glib_full(&self.0) } } #[doc(hidden)] impl<'a> $crate::translate::ToGlibContainerFromSlice<'a, *mut *mut $ffi_name> for $name { type Storage = (Vec<$crate::translate::Stash<'a, *mut $ffi_name, $name>>, Option>); fn to_glib_none_from_slice(t: &'a [$name]) -> (*mut *mut $ffi_name, Self::Storage) { let v: Vec<_> = t.iter().map(|s| $crate::translate::ToGlibPtr::to_glib_none(s)).collect(); let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect(); v_ptr.push(std::ptr::null_mut() as *mut $ffi_name); (v_ptr.as_ptr() as *mut *mut $ffi_name, (v, Some(v_ptr))) } fn to_glib_container_from_slice(t: &'a [$name]) -> (*mut *mut $ffi_name, Self::Storage) { let v: Vec<_> = t.iter().map(|s| $crate::translate::ToGlibPtr::to_glib_none(s)).collect(); let v_ptr = unsafe { let v_ptr = $crate::ffi::g_malloc0(std::mem::size_of::<*mut $ffi_name>() * (t.len() + 1)) as *mut *mut $ffi_name; for (i, s) in v.iter().enumerate() { std::ptr::write(v_ptr.add(i), s.0); } v_ptr }; (v_ptr, (v, None)) } fn to_glib_full_from_slice(t: &[$name]) -> *mut *mut $ffi_name { unsafe { let v_ptr = $crate::ffi::g_malloc0(std::mem::size_of::<*mut $ffi_name>() * (t.len() + 1)) as *mut *mut $ffi_name; for (i, s) in t.iter().enumerate() { std::ptr::write(v_ptr.add(i), $crate::translate::ToGlibPtr::to_glib_full(s)); } v_ptr } } } #[doc(hidden)] impl<'a> $crate::translate::ToGlibContainerFromSlice<'a, *const *mut $ffi_name> for $name { type Storage = (Vec<$crate::translate::Stash<'a, *mut $ffi_name, $name>>, Option>); fn to_glib_none_from_slice(t: &'a [$name]) -> (*const *mut $ffi_name, Self::Storage) { let (ptr, stash) = $crate::translate::ToGlibContainerFromSlice::<'a, *mut *mut $ffi_name>::to_glib_none_from_slice(t); (ptr as *const *mut $ffi_name, stash) } fn to_glib_container_from_slice(_: &'a [$name]) -> (*const *mut $ffi_name, Self::Storage) { // Can't have consumer free a *const pointer unimplemented!() } fn to_glib_full_from_slice(_: &[$name]) -> *const *mut $ffi_name { // Can't have consumer free a *const pointer unimplemented!() } } #[doc(hidden)] impl $crate::translate::FromGlibPtrNone<*mut $ffi_name> for $name { #[inline] unsafe fn from_glib_none(ptr: *mut $ffi_name) -> Self { $name($crate::translate::from_glib_none(ptr)) } } #[doc(hidden)] impl $crate::translate::FromGlibPtrNone<*const $ffi_name> for $name { #[inline] unsafe fn from_glib_none(ptr: *const $ffi_name) -> Self { $name($crate::translate::from_glib_none(ptr)) } } #[doc(hidden)] impl $crate::translate::FromGlibPtrFull<*mut $ffi_name> for $name { #[inline] unsafe fn from_glib_full(ptr: *mut $ffi_name) -> Self { $name($crate::translate::from_glib_full(ptr)) } } #[doc(hidden)] impl $crate::translate::FromGlibPtrBorrow<*mut $ffi_name> for $name { #[inline] unsafe fn from_glib_borrow(ptr: *mut $ffi_name) -> $crate::translate::Borrowed { $crate::translate::Borrowed::new( $name( $crate::translate::from_glib_borrow::<_, $crate::shared::Shared<_, _>>(ptr).into_inner() ) ) } } #[doc(hidden)] impl $crate::translate::FromGlibPtrBorrow<*const $ffi_name> for $name { #[inline] unsafe fn from_glib_borrow(ptr: *const $ffi_name) -> $crate::translate::Borrowed { $crate::translate::from_glib_borrow::<_, $name>(ptr as *mut $ffi_name) } } #[doc(hidden)] impl $crate::translate::FromGlibContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name { unsafe fn from_glib_none_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for i in 0..num { res.push($crate::translate::from_glib_none(std::ptr::read(ptr.add(i)))); } res } unsafe fn from_glib_container_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { let res = $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); $crate::ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for i in 0..num { res.push($crate::translate::from_glib_full(std::ptr::read(ptr.add(i)))); } $crate::ffi::g_free(ptr as *mut _); res } } #[doc(hidden)] impl $crate::translate::FromGlibPtrArrayContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name { unsafe fn from_glib_none_as_vec(ptr: *mut *mut $ffi_name) -> Vec { $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr)) } unsafe fn from_glib_container_as_vec(ptr: *mut *mut $ffi_name) -> Vec { $crate::translate::FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr)) } unsafe fn from_glib_full_as_vec(ptr: *mut *mut $ffi_name) -> Vec { $crate::translate::FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, $crate::translate::c_ptr_array_len(ptr)) } } #[doc(hidden)] impl $crate::translate::FromGlibContainerAsVec<*mut $ffi_name, *const *mut $ffi_name> for $name { unsafe fn from_glib_none_num_as_vec(ptr: *const *mut $ffi_name, num: usize) -> Vec { $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *mut *mut _, num) } unsafe fn from_glib_container_num_as_vec(_: *const *mut $ffi_name, _: usize) -> Vec { // Can't free a *const unimplemented!() } unsafe fn from_glib_full_num_as_vec(_: *const *mut $ffi_name, _: usize) -> Vec { // Can't free a *const unimplemented!() } } #[doc(hidden)] impl $crate::translate::FromGlibPtrArrayContainerAsVec<*mut $ffi_name, *const *mut $ffi_name> for $name { unsafe fn from_glib_none_as_vec(ptr: *const *mut $ffi_name) -> Vec { $crate::translate::FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr as *mut *mut _) } unsafe fn from_glib_container_as_vec(_: *const *mut $ffi_name) -> Vec { // Can't free a *const unimplemented!() } unsafe fn from_glib_full_as_vec(_: *const *mut $ffi_name) -> Vec { // Can't free a *const unimplemented!() } } } } pub trait SharedMemoryManager { /// # Safety /// /// Callers are responsible for ensuring that a matching call to `unref` /// is made at an appropriate time. unsafe fn ref_(ptr: *mut T); /// # Safety /// /// Callers are responsible for ensuring that a matching call to `ref` was /// made before this is called, and that the pointer is not used after the /// `unref` call. unsafe fn unref(ptr: *mut T); } /// Encapsulates memory management logic for shared types. pub struct Shared> { inner: ptr::NonNull, mm: PhantomData<*const MM>, } impl> Drop for Shared { fn drop(&mut self) { unsafe { MM::unref(self.inner.as_ptr()); } } } impl> Clone for Shared { fn clone(&self) -> Self { unsafe { MM::ref_(self.inner.as_ptr()); } Self { inner: self.inner, mm: PhantomData, } } } impl> fmt::Debug for Shared { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Shared") .field("inner", &self.inner) .finish() } } impl> PartialOrd for Shared { fn partial_cmp(&self, other: &Self) -> Option { self.inner.partial_cmp(&other.inner) } } impl> Ord for Shared { fn cmp(&self, other: &Self) -> cmp::Ordering { self.inner.cmp(&other.inner) } } impl> PartialEq for Shared { fn eq(&self, other: &Self) -> bool { self.inner == other.inner } } impl> Eq for Shared {} impl> Hash for Shared { fn hash(&self, state: &mut H) where H: Hasher, { self.inner.hash(state) } } impl<'a, T: 'static, MM> ToGlibPtr<'a, *mut T> for Shared where MM: SharedMemoryManager + 'static, { type Storage = &'a Self; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut T, Self> { Stash(self.inner.as_ptr(), self) } #[inline] fn to_glib_full(&self) -> *mut T { unsafe { MM::ref_(self.inner.as_ptr()); } self.inner.as_ptr() } } impl> FromGlibPtrNone<*mut T> for Shared { #[inline] unsafe fn from_glib_none(ptr: *mut T) -> Self { assert!(!ptr.is_null()); MM::ref_(ptr); Self { inner: ptr::NonNull::new_unchecked(ptr), mm: PhantomData, } } } impl> FromGlibPtrNone<*const T> for Shared { #[inline] unsafe fn from_glib_none(ptr: *const T) -> Self { assert!(!ptr.is_null()); MM::ref_(ptr as *mut _); Self { inner: ptr::NonNull::new_unchecked(ptr as *mut _), mm: PhantomData, } } } impl> FromGlibPtrFull<*mut T> for Shared { #[inline] unsafe fn from_glib_full(ptr: *mut T) -> Self { assert!(!ptr.is_null()); Self { inner: ptr::NonNull::new_unchecked(ptr), mm: PhantomData, } } } impl> FromGlibPtrBorrow<*mut T> for Shared { #[inline] unsafe fn from_glib_borrow(ptr: *mut T) -> Borrowed { assert!(!ptr.is_null()); Borrowed::new(Self { inner: ptr::NonNull::new_unchecked(ptr), mm: PhantomData, }) } } glib-0.14.8/src/signal.rs000064400000000000000000000107210072674642500132760ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! `IMPL` Low level signal support. use crate::object::ObjectType; use crate::translate::{from_glib, FromGlib, IntoGlib, ToGlibPtr}; use ffi::{gboolean, gpointer}; use gobject_ffi::{self, GCallback}; use libc::{c_char, c_ulong, c_void}; use std::mem; use std::num::NonZeroU64; /// The id of a signal that is returned by `connect`. /// /// This type does not implement `Clone` to prevent disconnecting /// the same signal handler multiple times. /// /// ```ignore /// use glib::SignalHandlerId; /// use gtk::prelude::*; /// use std::cell::RefCell; /// /// struct Button { /// widget: gtk::Button, /// clicked_handler_id: RefCell>, /// } /// /// impl Button { /// fn new() -> Self { /// let widget = gtk::Button::new(); /// let clicked_handler_id = RefCell::new(Some(widget.connect_clicked(|_button| { /// // Do something. /// }))); /// Self { /// widget, /// clicked_handler_id, /// } /// } /// /// fn disconnect(&self) { /// if let Some(id) = self.clicked_handler_id.borrow_mut().take() { /// self.widget.disconnect(id) /// } /// } /// } /// ``` #[derive(Debug, Eq, PartialEq)] pub struct SignalHandlerId(NonZeroU64); impl SignalHandlerId { /// Returns the internal signal handler ID. pub unsafe fn as_raw(&self) -> libc::c_ulong { self.0.get() as libc::c_ulong } } impl FromGlib for SignalHandlerId { #[inline] unsafe fn from_glib(val: c_ulong) -> Self { assert_ne!(val, 0); Self(NonZeroU64::new_unchecked(val as u64)) } } /// Whether to propagate the signal to the default handler. /// /// Don't inhibit default handlers without a reason, they're usually helpful. #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] pub struct Inhibit(pub bool); #[doc(hidden)] impl IntoGlib for Inhibit { type GlibType = gboolean; #[inline] fn into_glib(self) -> gboolean { self.0.into_glib() } } pub unsafe fn connect_raw( receiver: *mut gobject_ffi::GObject, signal_name: *const c_char, trampoline: GCallback, closure: *mut F, ) -> SignalHandlerId { unsafe extern "C" fn destroy_closure(ptr: *mut c_void, _: *mut gobject_ffi::GClosure) { // destroy Box::::from_raw(ptr as *mut _); } assert_eq!(mem::size_of::<*mut F>(), mem::size_of::()); assert!(trampoline.is_some()); let handle = gobject_ffi::g_signal_connect_data( receiver, signal_name, trampoline, closure as *mut _, Some(destroy_closure::), 0, ); assert!(handle > 0); from_glib(handle) } #[doc(alias = "g_signal_handler_block")] pub fn signal_handler_block(instance: &T, handler_id: &SignalHandlerId) { unsafe { gobject_ffi::g_signal_handler_block( instance.as_object_ref().to_glib_none().0, handler_id.as_raw(), ); } } #[doc(alias = "g_signal_handler_unblock")] pub fn signal_handler_unblock(instance: &T, handler_id: &SignalHandlerId) { unsafe { gobject_ffi::g_signal_handler_unblock( instance.as_object_ref().to_glib_none().0, handler_id.as_raw(), ); } } #[allow(clippy::needless_pass_by_value)] #[doc(alias = "g_signal_handler_disconnect")] pub fn signal_handler_disconnect(instance: &T, handler_id: SignalHandlerId) { unsafe { gobject_ffi::g_signal_handler_disconnect( instance.as_object_ref().to_glib_none().0, handler_id.as_raw(), ); } } #[doc(alias = "g_signal_stop_emission_by_name")] pub fn signal_stop_emission_by_name(instance: &T, signal_name: &str) { unsafe { gobject_ffi::g_signal_stop_emission_by_name( instance.as_object_ref().to_glib_none().0, signal_name.to_glib_none().0, ); } } #[doc(alias = "g_signal_has_handler_pending")] pub fn signal_has_handler_pending( instance: &T, signal_id: crate::subclass::SignalId, detail: Option, may_be_blocked: bool, ) -> bool { unsafe { from_glib(gobject_ffi::g_signal_has_handler_pending( instance.as_object_ref().to_glib_none().0, signal_id.into_glib(), detail.map_or(0, |d| d.into_glib()), may_be_blocked.into_glib(), )) } } glib-0.14.8/src/source.rs000064400000000000000000000765350072674642500133400ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::{from_glib, from_glib_full, FromGlib, IntoGlib, ToGlibPtr}; #[cfg(any(unix, feature = "dox"))] use crate::IOCondition; use ffi::{self, gboolean, gpointer}; #[cfg(all(not(unix), feature = "dox"))] use libc::c_int as RawFd; use std::cell::RefCell; use std::mem::transmute; use std::num::NonZeroU32; #[cfg(unix)] use std::os::unix::io::RawFd; use std::time::Duration; use crate::MainContext; use crate::Source; /// The id of a source that is returned by `idle_add` and `timeout_add`. /// /// This type does not implement `Clone` to prevent calling [`source_remove()`] /// multiple times on the same source. #[derive(Debug, Eq, PartialEq)] pub struct SourceId(NonZeroU32); impl SourceId { /// Returns the internal source ID. pub unsafe fn as_raw(&self) -> u32 { self.0.get() } } #[doc(hidden)] impl FromGlib for SourceId { #[inline] unsafe fn from_glib(val: u32) -> Self { assert_ne!(val, 0); Self(NonZeroU32::new_unchecked(val)) } } /// Process identificator #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[doc(alias = "GPid")] pub struct Pid(pub ffi::GPid); unsafe impl Send for Pid {} unsafe impl Sync for Pid {} #[doc(hidden)] impl IntoGlib for Pid { type GlibType = ffi::GPid; #[inline] fn into_glib(self) -> ffi::GPid { self.0 } } #[doc(hidden)] impl FromGlib for Pid { #[inline] unsafe fn from_glib(val: ffi::GPid) -> Self { Self(val) } } /// Continue calling the closure in the future iterations or drop it. /// /// This is the return type of `idle_add` and `timeout_add` closures. /// /// `Continue(true)` keeps the closure assigned, to be rerun when appropriate. /// /// `Continue(false)` disconnects and drops it. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Continue(pub bool); #[doc(hidden)] impl IntoGlib for Continue { type GlibType = gboolean; #[inline] fn into_glib(self) -> gboolean { self.0.into_glib() } } unsafe extern "C" fn trampoline Continue + 'static>(func: gpointer) -> gboolean { let func: &RefCell = &*(func as *const RefCell); (&mut *func.borrow_mut())().into_glib() } unsafe extern "C" fn destroy_closure Continue + 'static>(ptr: gpointer) { Box::>::from_raw(ptr as *mut _); } fn into_raw Continue + 'static>(func: F) -> gpointer { let func: Box> = Box::new(RefCell::new(func)); Box::into_raw(func) as gpointer } unsafe extern "C" fn trampoline_child_watch( pid: ffi::GPid, status: i32, func: gpointer, ) { let func: &RefCell = &*(func as *const RefCell); (&mut *func.borrow_mut())(Pid(pid), status) } unsafe extern "C" fn destroy_closure_child_watch(ptr: gpointer) { Box::>::from_raw(ptr as *mut _); } fn into_raw_child_watch(func: F) -> gpointer { let func: Box> = Box::new(RefCell::new(func)); Box::into_raw(func) as gpointer } #[cfg(any(unix, feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(unix)))] unsafe extern "C" fn trampoline_unix_fd Continue + 'static>( fd: i32, condition: ffi::GIOCondition, func: gpointer, ) -> gboolean { let func: &RefCell = &*(func as *const RefCell); (&mut *func.borrow_mut())(fd, from_glib(condition)).into_glib() } #[cfg(any(unix, feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(unix)))] unsafe extern "C" fn destroy_closure_unix_fd Continue + 'static>( ptr: gpointer, ) { Box::>::from_raw(ptr as *mut _); } #[cfg(any(unix, feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(unix)))] fn into_raw_unix_fd Continue + 'static>(func: F) -> gpointer { let func: Box> = Box::new(RefCell::new(func)); Box::into_raw(func) as gpointer } /// Transform a generic FnOnce into a closure that can be used as callback in various glib methods /// /// The resulting function can only be called once and will panic otherwise. It will return `Continue(false)` /// in order to prevent being called twice. #[inline(always)] fn fnmut_callback_wrapper( func: impl FnOnce() + Send + 'static, ) -> impl FnMut() -> Continue + Send + 'static { let mut func = Some(func); move || { let func = func .take() .expect("GSource closure called after returning glib::Continue(false)"); func(); Continue(false) } } /// Transform a generic FnOnce into a closure that can be used as callback in various glib methods /// /// The resulting function can only be called once and will panic otherwise. It will return `Continue(false)` /// in order to prevent being called twice. /// /// Different to `fnmut_callback_wrapper()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. #[inline(always)] fn fnmut_callback_wrapper_local( func: impl FnOnce() + 'static, ) -> impl FnMut() -> Continue + 'static { let mut func = Some(func); move || { let func = func .take() .expect("GSource closure called after returning glib::Continue(false)"); func(); Continue(false) } } /// Adds a closure to be called by the default main loop when it's idle. /// /// `func` will be called repeatedly until it returns `Continue(false)`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. #[doc(alias = "g_idle_add_full")] pub fn idle_add(func: F) -> SourceId where F: FnMut() -> Continue + Send + 'static, { unsafe { from_glib(ffi::g_idle_add_full( ffi::G_PRIORITY_DEFAULT_IDLE, Some(trampoline::), into_raw(func), Some(destroy_closure::), )) } } /// Adds a closure to be called by the default main loop when it's idle. /// /// `func` will be called repeatedly until it returns `Continue(false)`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// In comparison to `idle_add()`, this only requires `func` to be /// `FnOnce`, and will automatically return `Continue(false)`. #[doc(alias = "g_idle_add_full")] pub fn idle_add_once(func: F) -> SourceId where F: FnOnce() + Send + 'static, { idle_add(fnmut_callback_wrapper(func)) } /// Adds a closure to be called by the default main loop when it's idle. /// /// `func` will be called repeatedly until it returns `Continue(false)`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `idle_add()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. #[doc(alias = "g_idle_add_full")] pub fn idle_add_local(func: F) -> SourceId where F: FnMut() -> Continue + 'static, { unsafe { assert!(MainContext::default().is_owner()); from_glib(ffi::g_idle_add_full( ffi::G_PRIORITY_DEFAULT_IDLE, Some(trampoline::), into_raw(func), Some(destroy_closure::), )) } } /// Adds a closure to be called by the default main loop when it's idle. /// /// `func` will be called repeatedly until it returns `Continue(false)`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `idle_add()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. /// /// In comparison to `idle_add_local()`, this only requires `func` to be /// `FnOnce`, and will automatically return `Continue(false)`. #[doc(alias = "g_idle_add_full")] pub fn idle_add_local_once(func: F) -> SourceId where F: FnOnce() + 'static, { idle_add_local(fnmut_callback_wrapper_local(func)) } /// Adds a closure to be called by the default main loop at regular intervals /// with millisecond granularity. /// /// `func` will be called repeatedly every `interval` milliseconds until it /// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. Prefer `timeout_add_seconds` when millisecond /// precision is not necessary. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. #[doc(alias = "g_timeout_add_full")] pub fn timeout_add(interval: Duration, func: F) -> SourceId where F: FnMut() -> Continue + Send + 'static, { unsafe { from_glib(ffi::g_timeout_add_full( ffi::G_PRIORITY_DEFAULT, interval.as_millis() as _, Some(trampoline::), into_raw(func), Some(destroy_closure::), )) } } /// Adds a closure to be called by the default main loop at regular intervals /// with millisecond granularity. /// /// `func` will be called repeatedly every `interval` milliseconds until it /// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. Prefer `timeout_add_seconds` when millisecond /// precision is not necessary. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// In comparison to `timeout_add()`, this only requires `func` to be /// `FnOnce`, and will automatically return `Continue(false)`. #[doc(alias = "g_timeout_add_full")] pub fn timeout_add_once(interval: Duration, func: F) -> SourceId where F: FnOnce() + Send + 'static, { timeout_add(interval, fnmut_callback_wrapper(func)) } /// Adds a closure to be called by the default main loop at regular intervals /// with millisecond granularity. /// /// `func` will be called repeatedly every `interval` milliseconds until it /// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. Prefer `timeout_add_seconds` when millisecond /// precision is not necessary. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `timeout_add()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. #[doc(alias = "g_timeout_add_full")] pub fn timeout_add_local(interval: Duration, func: F) -> SourceId where F: FnMut() -> Continue + 'static, { unsafe { assert!(MainContext::default().is_owner()); from_glib(ffi::g_timeout_add_full( ffi::G_PRIORITY_DEFAULT, interval.as_millis() as _, Some(trampoline::), into_raw(func), Some(destroy_closure::), )) } } /// Adds a closure to be called by the default main loop at regular intervals /// with millisecond granularity. /// /// `func` will be called repeatedly every `interval` milliseconds until it /// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. Prefer `timeout_add_seconds` when millisecond /// precision is not necessary. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `timeout_add()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. /// /// In comparison to `timeout_add_local()`, this only requires `func` to be /// `FnOnce`, and will automatically return `Continue(false)`. #[doc(alias = "g_timeout_add_full")] pub fn timeout_add_local_once(interval: Duration, func: F) -> SourceId where F: FnOnce() + 'static, { timeout_add_local(interval, fnmut_callback_wrapper_local(func)) } /// Adds a closure to be called by the default main loop at regular intervals /// with second granularity. /// /// `func` will be called repeatedly every `interval` seconds until it /// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. #[doc(alias = "g_timeout_add_seconds_full")] pub fn timeout_add_seconds(interval: u32, func: F) -> SourceId where F: FnMut() -> Continue + Send + 'static, { unsafe { from_glib(ffi::g_timeout_add_seconds_full( ffi::G_PRIORITY_DEFAULT, interval, Some(trampoline::), into_raw(func), Some(destroy_closure::), )) } } /// Adds a closure to be called by the default main loop at regular intervals /// with second granularity. /// /// `func` will be called repeatedly every `interval` seconds until it /// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// In comparison to `timeout_add_seconds()`, this only requires `func` to be /// `FnOnce`, and will automatically return `Continue(false)`. #[doc(alias = "g_timeout_add_seconds_full")] pub fn timeout_add_seconds_once(interval: u32, func: F) -> SourceId where F: FnOnce() + Send + 'static, { timeout_add_seconds(interval, fnmut_callback_wrapper(func)) } /// Adds a closure to be called by the default main loop at regular intervals /// with second granularity. /// /// `func` will be called repeatedly every `interval` seconds until it /// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `timeout_add_seconds()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. #[doc(alias = "g_timeout_add_seconds_full")] pub fn timeout_add_seconds_local(interval: u32, func: F) -> SourceId where F: FnMut() -> Continue + 'static, { unsafe { assert!(MainContext::default().is_owner()); from_glib(ffi::g_timeout_add_seconds_full( ffi::G_PRIORITY_DEFAULT, interval, Some(trampoline::), into_raw(func), Some(destroy_closure::), )) } } /// Adds a closure to be called by the default main loop at regular intervals /// with second granularity. /// /// `func` will be called repeatedly every `interval` seconds until it /// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `timeout_add_seconds()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. /// /// In comparison to `timeout_add_seconds_local()`, this only requires `func` to be /// `FnOnce`, and will automatically return `Continue(false)`. #[doc(alias = "g_timeout_add_seconds_full")] pub fn timeout_add_seconds_local_once(interval: u32, func: F) -> SourceId where F: FnOnce() + 'static, { timeout_add_seconds_local(interval, fnmut_callback_wrapper_local(func)) } /// Adds a closure to be called by the main loop the returned `Source` is attached to when a child /// process exits. /// /// `func` will be called when `pid` exits #[doc(alias = "g_child_watch_add_full")] pub fn child_watch_add(pid: Pid, func: F) -> SourceId where F: FnMut(Pid, i32) + Send + 'static, { unsafe { from_glib(ffi::g_child_watch_add_full( ffi::G_PRIORITY_DEFAULT, pid.0, Some(trampoline_child_watch::), into_raw_child_watch(func), Some(destroy_closure_child_watch::), )) } } /// Adds a closure to be called by the main loop the returned `Source` is attached to when a child /// process exits. /// /// `func` will be called when `pid` exits /// /// Different to `child_watch_add()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. #[doc(alias = "g_child_watch_add_full")] pub fn child_watch_add_local(pid: Pid, func: F) -> SourceId where F: FnMut(Pid, i32) + 'static, { unsafe { assert!(MainContext::default().is_owner()); from_glib(ffi::g_child_watch_add_full( ffi::G_PRIORITY_DEFAULT, pid.0, Some(trampoline_child_watch::), into_raw_child_watch(func), Some(destroy_closure_child_watch::), )) } } #[cfg(any(unix, feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(unix)))] /// Adds a closure to be called by the default main loop whenever a UNIX signal is raised. /// /// `func` will be called repeatedly every time `signum` is raised until it /// returns `Continue(false)`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. #[doc(alias = "g_unix_signal_add_full")] pub fn unix_signal_add(signum: i32, func: F) -> SourceId where F: FnMut() -> Continue + Send + 'static, { unsafe { from_glib(ffi::g_unix_signal_add_full( ffi::G_PRIORITY_DEFAULT, signum, Some(trampoline::), into_raw(func), Some(destroy_closure::), )) } } #[cfg(any(unix, feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(unix)))] /// Adds a closure to be called by the default main loop whenever a UNIX signal is raised. /// /// `func` will be called repeatedly every time `signum` is raised until it /// returns `Continue(false)`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// In comparison to `unix_signal_add()`, this only requires `func` to be /// `FnOnce`, and will automatically return `Continue(false)`. #[doc(alias = "g_unix_signal_add_full")] pub fn unix_signal_add_once(signum: i32, func: F) -> SourceId where F: FnOnce() + Send + 'static, { unix_signal_add(signum, fnmut_callback_wrapper(func)) } #[cfg(any(unix, feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(unix)))] /// Adds a closure to be called by the default main loop whenever a UNIX signal is raised. /// /// `func` will be called repeatedly every time `signum` is raised until it /// returns `Continue(false)`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `unix_signal_add()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. #[doc(alias = "g_unix_signal_add_full")] pub fn unix_signal_add_local(signum: i32, func: F) -> SourceId where F: FnMut() -> Continue + 'static, { unsafe { assert!(MainContext::default().is_owner()); from_glib(ffi::g_unix_signal_add_full( ffi::G_PRIORITY_DEFAULT, signum, Some(trampoline::), into_raw(func), Some(destroy_closure::), )) } } #[cfg(any(unix, feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(unix)))] /// Adds a closure to be called by the default main loop whenever a UNIX signal is raised. /// /// `func` will be called repeatedly every time `signum` is raised until it /// returns `Continue(false)`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `unix_signal_add()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. /// /// In comparison to `unix_signal_add_local()`, this only requires `func` to be /// `FnOnce`, and will automatically return `Continue(false)`. #[doc(alias = "g_unix_signal_add_full")] pub fn unix_signal_add_local_once(signum: i32, func: F) -> SourceId where F: FnOnce() + 'static, { unix_signal_add_local(signum, fnmut_callback_wrapper_local(func)) } #[cfg(any(unix, feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(unix)))] /// Adds a closure to be called by the main loop the returned `Source` is attached to whenever a /// UNIX file descriptor reaches the given IO condition. /// /// `func` will be called repeatedly while the file descriptor matches the given IO condition /// until it returns `Continue(false)`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. #[doc(alias = "g_unix_fd_add_full")] pub fn unix_fd_add(fd: RawFd, condition: IOCondition, func: F) -> SourceId where F: FnMut(RawFd, IOCondition) -> Continue + Send + 'static, { unsafe { from_glib(ffi::g_unix_fd_add_full( ffi::G_PRIORITY_DEFAULT, fd, condition.into_glib(), Some(trampoline_unix_fd::), into_raw_unix_fd(func), Some(destroy_closure_unix_fd::), )) } } #[cfg(any(unix, feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(unix)))] /// Adds a closure to be called by the main loop the returned `Source` is attached to whenever a /// UNIX file descriptor reaches the given IO condition. /// /// `func` will be called repeatedly while the file descriptor matches the given IO condition /// until it returns `Continue(false)`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `unix_fd_add()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. #[doc(alias = "g_unix_fd_add_full")] pub fn unix_fd_add_local(fd: RawFd, condition: IOCondition, func: F) -> SourceId where F: FnMut(RawFd, IOCondition) -> Continue + 'static, { unsafe { assert!(MainContext::default().is_owner()); from_glib(ffi::g_unix_fd_add_full( ffi::G_PRIORITY_DEFAULT, fd, condition.into_glib(), Some(trampoline_unix_fd::), into_raw_unix_fd(func), Some(destroy_closure_unix_fd::), )) } } /// Removes the source with the given id `source_id` from the default main context. /// /// It is a programmer error to attempt to remove a non-existent source. /// Note: source id are reused. /// /// For historical reasons, the native function always returns true, so we /// ignore it here. #[allow(clippy::needless_pass_by_value)] #[doc(alias = "g_source_remove")] pub fn source_remove(source_id: SourceId) { unsafe { ffi::g_source_remove(source_id.as_raw()); } } /// The priority of sources /// #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct Priority(i32); #[doc(hidden)] impl IntoGlib for Priority { type GlibType = i32; #[inline] fn into_glib(self) -> i32 { self.0 } } #[doc(hidden)] impl FromGlib for Priority { #[inline] unsafe fn from_glib(val: i32) -> Self { Self(val) } } impl Default for Priority { fn default() -> Self { PRIORITY_DEFAULT } } pub const PRIORITY_HIGH: Priority = Priority(ffi::G_PRIORITY_HIGH); pub const PRIORITY_DEFAULT: Priority = Priority(ffi::G_PRIORITY_DEFAULT); pub const PRIORITY_HIGH_IDLE: Priority = Priority(ffi::G_PRIORITY_HIGH_IDLE); pub const PRIORITY_DEFAULT_IDLE: Priority = Priority(ffi::G_PRIORITY_DEFAULT_IDLE); pub const PRIORITY_LOW: Priority = Priority(ffi::G_PRIORITY_LOW); /// Adds a closure to be called by the main loop the return `Source` is attached to when it's idle. /// /// `func` will be called repeatedly until it returns `Continue(false)`. #[doc(alias = "g_idle_source_new")] pub fn idle_source_new(name: Option<&str>, priority: Priority, func: F) -> Source where F: FnMut() -> Continue + Send + 'static, { unsafe { let source = ffi::g_idle_source_new(); ffi::g_source_set_callback( source, Some(trampoline::), into_raw(func), Some(destroy_closure::), ); ffi::g_source_set_priority(source, priority.into_glib()); if let Some(name) = name { ffi::g_source_set_name(source, name.to_glib_none().0); } from_glib_full(source) } } /// Adds a closure to be called by the main loop the returned `Source` is attached to at regular /// intervals with millisecond granularity. /// /// `func` will be called repeatedly every `interval` milliseconds until it /// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. Prefer `timeout_add_seconds` when millisecond /// precision is not necessary. #[doc(alias = "g_timeout_source_new")] pub fn timeout_source_new( interval: Duration, name: Option<&str>, priority: Priority, func: F, ) -> Source where F: FnMut() -> Continue + Send + 'static, { unsafe { let source = ffi::g_timeout_source_new(interval.as_millis() as _); ffi::g_source_set_callback( source, Some(trampoline::), into_raw(func), Some(destroy_closure::), ); ffi::g_source_set_priority(source, priority.into_glib()); if let Some(name) = name { ffi::g_source_set_name(source, name.to_glib_none().0); } from_glib_full(source) } } /// Adds a closure to be called by the main loop the returned `Source` is attached to at regular /// intervals with second granularity. /// /// `func` will be called repeatedly every `interval` seconds until it /// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. #[doc(alias = "g_timeout_source_new_seconds")] pub fn timeout_source_new_seconds( interval: u32, name: Option<&str>, priority: Priority, func: F, ) -> Source where F: FnMut() -> Continue + Send + 'static, { unsafe { let source = ffi::g_timeout_source_new_seconds(interval); ffi::g_source_set_callback( source, Some(trampoline::), into_raw(func), Some(destroy_closure::), ); ffi::g_source_set_priority(source, priority.into_glib()); if let Some(name) = name { ffi::g_source_set_name(source, name.to_glib_none().0); } from_glib_full(source) } } /// Adds a closure to be called by the main loop the returned `Source` is attached to when a child /// process exits. /// /// `func` will be called when `pid` exits #[doc(alias = "g_child_watch_source_new")] pub fn child_watch_source_new( pid: Pid, name: Option<&str>, priority: Priority, func: F, ) -> Source where F: FnMut(Pid, i32) + Send + 'static, { unsafe { let source = ffi::g_child_watch_source_new(pid.0); ffi::g_source_set_callback( source, Some(transmute::< _, unsafe extern "C" fn(ffi::gpointer) -> ffi::gboolean, >(trampoline_child_watch:: as *const ())), into_raw_child_watch(func), Some(destroy_closure_child_watch::), ); ffi::g_source_set_priority(source, priority.into_glib()); if let Some(name) = name { ffi::g_source_set_name(source, name.to_glib_none().0); } from_glib_full(source) } } #[cfg(any(unix, feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(unix)))] /// Adds a closure to be called by the main loop the returned `Source` is attached to whenever a /// UNIX signal is raised. /// /// `func` will be called repeatedly every time `signum` is raised until it /// returns `Continue(false)`. #[doc(alias = "g_unix_signal_source_new")] pub fn unix_signal_source_new( signum: i32, name: Option<&str>, priority: Priority, func: F, ) -> Source where F: FnMut() -> Continue + Send + 'static, { unsafe { let source = ffi::g_unix_signal_source_new(signum); ffi::g_source_set_callback( source, Some(trampoline::), into_raw(func), Some(destroy_closure::), ); ffi::g_source_set_priority(source, priority.into_glib()); if let Some(name) = name { ffi::g_source_set_name(source, name.to_glib_none().0); } from_glib_full(source) } } #[cfg(any(unix, feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(unix)))] /// Adds a closure to be called by the main loop the returned `Source` is attached to whenever a /// UNIX file descriptor reaches the given IO condition. /// /// `func` will be called repeatedly while the file descriptor matches the given IO condition /// until it returns `Continue(false)`. #[doc(alias = "g_unix_fd_source_new")] pub fn unix_fd_source_new( fd: RawFd, condition: IOCondition, name: Option<&str>, priority: Priority, func: F, ) -> Source where F: FnMut(RawFd, IOCondition) -> Continue + Send + 'static, { unsafe { let source = ffi::g_unix_fd_source_new(fd, condition.into_glib()); ffi::g_source_set_callback( source, Some(transmute::< _, unsafe extern "C" fn(ffi::gpointer) -> ffi::gboolean, >(trampoline_unix_fd:: as *const ())), into_raw_unix_fd(func), Some(destroy_closure_unix_fd::), ); ffi::g_source_set_priority(source, priority.into_glib()); if let Some(name) = name { ffi::g_source_set_name(source, name.to_glib_none().0); } from_glib_full(source) } } impl Source { #[doc(alias = "g_source_attach")] pub fn attach(&self, context: Option<&MainContext>) -> SourceId { unsafe { from_glib(ffi::g_source_attach( self.to_glib_none().0, context.to_glib_none().0, )) } } #[doc(alias = "g_source_remove")] pub fn remove(tag: SourceId) -> Result<(), crate::BoolError> { unsafe { result_from_gboolean!( ffi::g_source_remove(tag.as_raw()), "Failed to remove source" ) } } } glib-0.14.8/src/source_futures.rs000064400000000000000000000342410072674642500151010ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use futures_channel::{mpsc, oneshot}; use futures_core::future::Future; use futures_core::stream::Stream; use futures_core::task; use futures_core::task::Poll; use std::marker::Unpin; use std::pin; use std::pin::Pin; use std::time::Duration; use crate::Continue; use crate::MainContext; use crate::Priority; use crate::Source; /// Represents a `Future` around a `glib::Source`. The future will /// be resolved once the source has provided a value pub struct SourceFuture { create_source: Option, source: Option<(Source, oneshot::Receiver)>, } impl SourceFuture where F: FnOnce(oneshot::Sender) -> Source + 'static, { /// Create a new `SourceFuture` /// /// The provided closure should return a newly created `glib::Source` when called /// and pass the value provided by the source to the oneshot sender that is passed /// to the closure. pub fn new(create_source: F) -> SourceFuture { SourceFuture { create_source: Some(create_source), source: None, } } } impl Unpin for SourceFuture {} impl Future for SourceFuture where F: FnOnce(oneshot::Sender) -> Source + 'static, { type Output = T; fn poll(mut self: pin::Pin<&mut Self>, ctx: &mut task::Context) -> Poll { let SourceFuture { ref mut create_source, ref mut source, .. } = *self; if let Some(create_source) = create_source.take() { let main_context = MainContext::ref_thread_default(); assert!( main_context.is_owner(), "Spawning futures only allowed if the thread is owning the MainContext" ); // Channel for sending back the Source result to our future here. // // In theory, we could directly continue polling the // corresponding task from the Source callback, // however this would break at the very least // the g_main_current_source() API. let (send, recv) = oneshot::channel(); let s = create_source(send); s.attach(Some(&main_context)); *source = Some((s, recv)); } // At this point we must have a receiver let res = { let &mut (_, ref mut receiver) = source.as_mut().unwrap(); Pin::new(receiver).poll(ctx) }; #[allow(clippy::match_wild_err_arm)] match res { Poll::Ready(Err(_)) => panic!("Source sender was unexpectedly closed"), Poll::Ready(Ok(v)) => { // Get rid of the reference to the source, it triggered let _ = source.take(); Poll::Ready(v) } Poll::Pending => Poll::Pending, } } } impl Drop for SourceFuture { fn drop(&mut self) { // Get rid of the source, we don't care anymore if it still triggers if let Some((source, _)) = self.source.take() { source.destroy(); } } } /// Create a `Future` that will resolve after the given number of milliseconds. /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn timeout_future(value: Duration) -> Pin + Send + 'static>> { timeout_future_with_priority(crate::PRIORITY_DEFAULT, value) } /// Create a `Future` that will resolve after the given number of milliseconds. /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn timeout_future_with_priority( priority: Priority, value: Duration, ) -> Pin + Send + 'static>> { Box::pin(SourceFuture::new(move |send| { let mut send = Some(send); crate::timeout_source_new(value, None, priority, move || { let _ = send.take().unwrap().send(()); Continue(false) }) })) } /// Create a `Future` that will resolve after the given number of seconds. /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn timeout_future_seconds(value: u32) -> Pin + Send + 'static>> { timeout_future_seconds_with_priority(crate::PRIORITY_DEFAULT, value) } /// Create a `Future` that will resolve after the given number of seconds. /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn timeout_future_seconds_with_priority( priority: Priority, value: u32, ) -> Pin + Send + 'static>> { Box::pin(SourceFuture::new(move |send| { let mut send = Some(send); crate::timeout_source_new_seconds(value, None, priority, move || { let _ = send.take().unwrap().send(()); Continue(false) }) })) } /// Create a `Future` that will resolve once the child process with the given pid exits /// /// The `Future` will resolve to the pid of the child process and the exit code. /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn child_watch_future( pid: crate::Pid, ) -> Pin + Send + 'static>> { child_watch_future_with_priority(crate::PRIORITY_DEFAULT, pid) } /// Create a `Future` that will resolve once the child process with the given pid exits /// /// The `Future` will resolve to the pid of the child process and the exit code. /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn child_watch_future_with_priority( priority: Priority, pid: crate::Pid, ) -> Pin + Send + 'static>> { Box::pin(SourceFuture::new(move |send| { let mut send = Some(send); crate::child_watch_source_new(pid, None, priority, move |pid, code| { let _ = send.take().unwrap().send((pid, code)); }) })) } #[cfg(any(unix, feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(unix)))] /// Create a `Future` that will resolve once the given UNIX signal is raised /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn unix_signal_future(signum: i32) -> Pin + Send + 'static>> { unix_signal_future_with_priority(crate::PRIORITY_DEFAULT, signum) } #[cfg(any(unix, feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(unix)))] /// Create a `Future` that will resolve once the given UNIX signal is raised /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn unix_signal_future_with_priority( priority: Priority, signum: i32, ) -> Pin + Send + 'static>> { Box::pin(SourceFuture::new(move |send| { let mut send = Some(send); crate::unix_signal_source_new(signum, None, priority, move || { let _ = send.take().unwrap().send(()); Continue(false) }) })) } /// Represents a `Stream` around a `glib::Source`. The stream will /// be provide all values that are provided by the source pub struct SourceStream { create_source: Option, source: Option<(Source, mpsc::UnboundedReceiver)>, } impl Unpin for SourceStream {} impl SourceStream where F: FnOnce(mpsc::UnboundedSender) -> Source + 'static, { /// Create a new `SourceStream` /// /// The provided closure should return a newly created `glib::Source` when called /// and pass the values provided by the source to the sender that is passed /// to the closure. pub fn new(create_source: F) -> SourceStream { SourceStream { create_source: Some(create_source), source: None, } } } impl Stream for SourceStream where F: FnOnce(mpsc::UnboundedSender) -> Source + 'static, { type Item = T; fn poll_next(mut self: pin::Pin<&mut Self>, ctx: &mut task::Context) -> Poll> { let SourceStream { ref mut create_source, ref mut source, .. } = *self; if let Some(create_source) = create_source.take() { let main_context = MainContext::ref_thread_default(); assert!( main_context.is_owner(), "Spawning futures only allowed if the thread is owning the MainContext" ); // Channel for sending back the Source result to our future here. // // In theory we could directly continue polling the // corresponding task from the Source callback, // however this would break at the very least // the g_main_current_source() API. let (send, recv) = mpsc::unbounded(); let s = create_source(send); s.attach(Some(&main_context)); *source = Some((s, recv)); } // At this point we must have a receiver let res = { let &mut (_, ref mut receiver) = source.as_mut().unwrap(); Pin::new(receiver).poll_next(ctx) }; #[allow(clippy::match_wild_err_arm)] match res { Poll::Ready(v) => { if v.is_none() { // Get rid of the reference to the source, it triggered let _ = source.take(); } Poll::Ready(v) } Poll::Pending => Poll::Pending, } } } impl Drop for SourceStream { fn drop(&mut self) { // Get rid of the source, we don't care anymore if it still triggers if let Some((source, _)) = self.source.take() { source.destroy(); } } } /// Create a `Stream` that will provide a value every given number of milliseconds. /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn interval_stream(value: Duration) -> Pin + Send + 'static>> { interval_stream_with_priority(crate::PRIORITY_DEFAULT, value) } /// Create a `Stream` that will provide a value every given number of milliseconds. /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn interval_stream_with_priority( priority: Priority, value: Duration, ) -> Pin + Send + 'static>> { Box::pin(SourceStream::new(move |send| { crate::timeout_source_new(value, None, priority, move || { if send.unbounded_send(()).is_err() { Continue(false) } else { Continue(true) } }) })) } /// Create a `Stream` that will provide a value every given number of seconds. /// /// The `Stream` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn interval_stream_seconds(value: u32) -> Pin + Send + 'static>> { interval_stream_seconds_with_priority(crate::PRIORITY_DEFAULT, value) } /// Create a `Stream` that will provide a value every given number of seconds. /// /// The `Stream` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn interval_stream_seconds_with_priority( priority: Priority, value: u32, ) -> Pin + Send + 'static>> { Box::pin(SourceStream::new(move |send| { crate::timeout_source_new_seconds(value, None, priority, move || { if send.unbounded_send(()).is_err() { Continue(false) } else { Continue(true) } }) })) } #[cfg(any(unix, feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(unix)))] /// Create a `Stream` that will provide a value whenever the given UNIX signal is raised /// /// The `Stream` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn unix_signal_stream(signum: i32) -> Pin + Send + 'static>> { unix_signal_stream_with_priority(crate::PRIORITY_DEFAULT, signum) } #[cfg(any(unix, feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(unix)))] /// Create a `Stream` that will provide a value whenever the given UNIX signal is raised /// /// The `Stream` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn unix_signal_stream_with_priority( priority: Priority, signum: i32, ) -> Pin + Send + 'static>> { Box::pin(SourceStream::new(move |send| { crate::unix_signal_source_new(signum, None, priority, move || { if send.unbounded_send(()).is_err() { Continue(false) } else { Continue(true) } }) })) } #[cfg(test)] mod tests { use super::*; use futures_util::future::FutureExt; use futures_util::stream::StreamExt; use std::thread; use std::time::Duration; #[test] fn test_timeout() { let c = MainContext::new(); c.block_on(timeout_future(Duration::from_millis(20))); } #[test] fn test_timeout_send() { let c = MainContext::new(); let l = crate::MainLoop::new(Some(&c), false); let l_clone = l.clone(); c.spawn(timeout_future(Duration::from_millis(20)).then(move |()| { l_clone.quit(); futures_util::future::ready(()) })); l.run(); } #[test] fn test_interval() { let c = MainContext::new(); let mut count = 0; { let count = &mut count; c.block_on( interval_stream(Duration::from_millis(20)) .take(2) .for_each(|()| { *count += 1; futures_util::future::ready(()) }) .map(|_| ()), ); } assert_eq!(count, 2); } #[test] fn test_timeout_and_channel() { let c = MainContext::default(); let res = c.block_on(timeout_future(Duration::from_millis(20)).then(|()| { let (sender, receiver) = oneshot::channel(); thread::spawn(move || { sender.send(1).unwrap(); }); receiver.then(|i| futures_util::future::ready(i.unwrap())) })); assert_eq!(res, 1); } } glib-0.14.8/src/string.rs000064400000000000000000000142030072674642500133260ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::*; use std::borrow; use std::cmp; use std::convert; use std::fmt; use std::hash; use std::ops; use std::ptr; use std::slice; use std::str; wrapper! { /// A mutable text buffer that grows automatically. #[doc(alias = "GString")] pub struct String(Boxed); match fn { copy => |ptr| gobject_ffi::g_boxed_copy(ffi::g_gstring_get_type(), ptr as *mut _) as *mut ffi::GString, free => |ptr| gobject_ffi::g_boxed_free(ffi::g_gstring_get_type(), ptr as *mut _), type_ => || ffi::g_gstring_get_type(), } } unsafe impl Send for String {} unsafe impl Sync for String {} impl String { #[doc(alias = "g_string_new_len")] pub fn new>(data: T) -> String { let bytes = data.as_ref(); unsafe { from_glib_full(ffi::g_string_new_len( bytes.as_ptr() as *const _, bytes.len() as isize, )) } } #[doc(alias = "g_string_append_len")] pub fn append(&mut self, val: &str) -> &mut Self { unsafe { ffi::g_string_append_len( self.to_glib_none_mut().0, val.to_glib_none().0, val.len() as isize, ); } self } #[doc(alias = "g_string_insert_len")] pub fn insert(&mut self, pos: isize, val: &str) -> &mut Self { unsafe { ffi::g_string_insert_len( self.to_glib_none_mut().0, pos, val.to_glib_none().0, val.len() as isize, ); } self } #[doc(alias = "g_string_overwrite_len")] pub fn overwrite(&mut self, pos: usize, val: &str) -> &mut Self { unsafe { ffi::g_string_overwrite_len( self.to_glib_none_mut().0, pos, val.to_glib_none().0, val.len() as isize, ); } self } #[doc(alias = "g_string_prepend_len")] pub fn prepend(&mut self, val: &str) -> &mut Self { unsafe { ffi::g_string_prepend_len( self.to_glib_none_mut().0, val.to_glib_none().0, val.len() as isize, ); } self } #[doc(alias = "g_string_truncate")] pub fn truncate(&mut self, len: usize) -> &mut Self { unsafe { ffi::g_string_truncate(self.to_glib_none_mut().0, len); } self } /// Returns `&str` slice when contained data is valid UTF-8 string, or an error otherwise. pub fn to_str(&self) -> Result<&str, str::Utf8Error> { str::from_utf8(self.as_ref()) } /// Returns `Cow` containing UTF-8 data. Invalid UTF-8 sequences are replaced with /// replacement character. pub fn to_string_lossy(&self) -> borrow::Cow { std::string::String::from_utf8_lossy(self.as_ref()) } } impl Default for String { /// Creates a new empty string. fn default() -> Self { unsafe { from_glib_full(ffi::g_string_new(ptr::null())) } } } impl fmt::Debug for String { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(&self.to_string_lossy()) } } impl fmt::Display for String { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(&self.to_string_lossy()) } } impl PartialEq for String { #[doc(alias = "g_string_equal")] fn eq(&self, other: &Self) -> bool { unsafe { from_glib(ffi::g_string_equal( self.to_glib_none().0, other.to_glib_none().0, )) } } } impl Eq for String {} impl cmp::PartialOrd for String { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl cmp::Ord for String { fn cmp(&self, other: &Self) -> cmp::Ordering { self.as_ref().cmp(other.as_ref()) } } impl hash::Hash for String { fn hash(&self, state: &mut H) where H: hash::Hasher, { hash::Hash::hash_slice(self.as_ref(), state) } } impl convert::AsRef<[u8]> for String { fn as_ref(&self) -> &[u8] { let ptr: *const u8 = (*self.0).str as _; let len: usize = (*self.0).len; unsafe { slice::from_raw_parts(ptr, len) } } } impl ops::Deref for String { type Target = [u8]; fn deref(&self) -> &[u8] { let ptr: *const u8 = (*self.0).str as _; let len: usize = (*self.0).len; unsafe { slice::from_raw_parts(ptr, len) } } } #[cfg(test)] mod tests { #[test] fn append() { let mut s = crate::String::new(""); s.append("Hello").append(" ").append("there!"); assert_eq!(&*s, b"Hello there!"); } #[test] fn insert() { let mut s = crate::String::new("foobaz"); s.insert(3, "bar"); assert_eq!(&*s, b"foobarbaz"); } #[test] fn overwrite() { let mut s = crate::String::new("abc"); s.overwrite(2, "de"); assert_eq!(&*s, b"abde"); } #[test] fn prepend() { let mut s = crate::String::new("456"); s.prepend("123"); assert_eq!(&*s, b"123456"); } #[test] fn truncate() { let mut s = crate::String::new("12345"); s.truncate(10); assert_eq!(&*s, b"12345"); s.truncate(2); assert_eq!(&*s, b"12"); } #[test] fn default() { let s1: crate::String = Default::default(); assert_eq!(&*s1, b""); } #[test] fn display() { let s: crate::String = crate::String::new("This is a string."); assert_eq!(&format!("{}", s), "This is a string."); } #[test] fn eq() { let a1 = crate::String::new("a"); let a2 = crate::String::new("a"); let b = crate::String::new("b"); assert_eq!(a1, a2); assert_ne!(a1, b); assert_ne!(a2, b); } #[test] fn invalid_utf8() { let s = crate::String::new(b"Hello \xF0\x90\x80World"); assert!(s.to_str().is_err()); assert_eq!(s.to_string_lossy(), "Hello �World"); } } glib-0.14.8/src/subclass/basic.rs000064400000000000000000000036770072674642500147350ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! This module contains basic instance and class structs to be used for //! `GObject` subclasses that don't require any additional data in these //! structs and don't provide any new virtual methods. use super::prelude::*; use crate::object::ObjectType; use std::fmt; use std::ops; /// A basic instance struct that does not store any additional data. #[repr(C)] pub struct InstanceStruct { parent: ::GlibType, } impl fmt::Debug for InstanceStruct where ::GlibType: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("InstanceStruct") .field("parent", &self.parent) .finish() } } unsafe impl super::types::InstanceStruct for InstanceStruct { type Type = T; } /// A basic class struct that does not store any additional data /// or virtual methods. #[repr(C)] pub struct ClassStruct { parent_class: ::GlibClassType, } impl fmt::Debug for ClassStruct where ::GlibClassType: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("InstanceStruct") .field("parent_class", &self.parent_class) .finish() } } unsafe impl super::types::ClassStruct for ClassStruct { type Type = T; } impl ops::Deref for ClassStruct { type Target = crate::Class<::Type>; fn deref(&self) -> &Self::Target { unsafe { &*(self as *const _ as *const Self::Target) } } } impl ops::DerefMut for ClassStruct { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { &mut *(self as *mut _ as *mut Self::Target) } } } glib-0.14.8/src/subclass/boxed.rs000064400000000000000000000051270072674642500147450ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! Module for registering boxed types for Rust types. use crate::translate::*; use crate::StaticType; /// Trait for defining boxed types. /// /// Links together the type name with the type itself. /// /// See [`register_boxed_type`] for registering an implementation of this trait /// with the type system. /// /// [`register_boxed_type`]: fn.register_boxed_type.html pub trait BoxedType: StaticType + Clone + Sized + 'static { /// Boxed type name. /// /// This must be unique in the whole process. const NAME: &'static str; } /// Register a boxed `glib::Type` ID for `T`. /// /// This must be called only once and will panic on a second call. /// /// See [`GBoxed!`] for defining a function that ensures that /// this is only called once and returns the type id. /// /// [`GBoxed!`]: ../../derive.GBoxed.html pub fn register_boxed_type() -> crate::Type { unsafe extern "C" fn boxed_copy(v: ffi::gpointer) -> ffi::gpointer { let v = &*(v as *mut T); let copy = Box::new(v.clone()); Box::into_raw(copy) as ffi::gpointer } unsafe extern "C" fn boxed_free(v: ffi::gpointer) { let v = v as *mut T; let _ = Box::from_raw(v); } unsafe { use std::ffi::CString; let type_name = CString::new(T::NAME).unwrap(); if gobject_ffi::g_type_from_name(type_name.as_ptr()) != gobject_ffi::G_TYPE_INVALID { panic!( "Type {} has already been registered", type_name.to_str().unwrap() ); } from_glib(gobject_ffi::g_boxed_type_register_static( type_name.as_ptr(), Some(boxed_copy::), Some(boxed_free::), )) } } #[cfg(test)] mod test { // We rename the current crate as glib, since the macros in glib-macros // generate the glib namespace through the crate_ident_new utility, // and that returns `glib` (and not `crate`) when called inside the glib crate use crate as glib; use crate::value::ToValue; use crate::StaticType; #[derive(Clone, Debug, PartialEq, Eq, glib::GBoxed)] #[gboxed(type_name = "MyBoxed")] struct MyBoxed(String); #[test] fn test_register() { assert!(MyBoxed::static_type().is_valid()); } #[test] fn test_value() { assert!(MyBoxed::static_type().is_valid()); let b = MyBoxed(String::from("abc")); let v = b.to_value(); let b2 = v.get::<&MyBoxed>().unwrap(); assert_eq!(&b, b2); } } glib-0.14.8/src/subclass/interface.rs000064400000000000000000000151400072674642500156000ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use super::{InitializingType, Signal}; use crate::translate::*; use crate::{IsA, Object, ObjectExt, ParamSpec, Type}; use std::marker; use std::mem; /// Trait for a type list of prerequisite object types. pub trait PrerequisiteList { /// Returns the list of types for this list. fn types() -> Vec; } impl PrerequisiteList for () { fn types() -> Vec { vec![] } } impl PrerequisiteList for (T,) { fn types() -> Vec { vec![T::static_type().into_glib()] } } // Generates all the PrerequisiteList impls for prerequisite_lists of arbitrary sizes based on a list of type // parameters like A B C. It would generate the impl then for (A, B) and (A, B, C). macro_rules! prerequisite_list_trait( ($name1:ident, $name2: ident, $($name:ident),*) => ( prerequisite_list_trait!(__impl $name1, $name2; $($name),*); ); (__impl $($name:ident),+; $name1:ident, $($name2:ident),*) => ( prerequisite_list_trait_impl!($($name),+); prerequisite_list_trait!(__impl $($name),+ , $name1; $($name2),*); ); (__impl $($name:ident),+; $name1:ident) => ( prerequisite_list_trait_impl!($($name),+); prerequisite_list_trait_impl!($($name),+, $name1); ); ); // Generates the impl block for PrerequisiteList on prerequisite_lists or arbitrary sizes based on its // arguments. Takes a list of type parameters as parameters, e.g. A B C // and then implements the trait on (A, B, C). macro_rules! prerequisite_list_trait_impl( ($($name:ident),+) => ( impl<$($name: crate::ObjectType),+> PrerequisiteList for ( $($name),+ ) { fn types() -> Vec { vec![$($name::static_type().into_glib()),+] } } ); ); prerequisite_list_trait!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S); /// Type methods required for an [`ObjectInterface`] implementation. /// /// This is usually generated by the [`#[object_interface]`](crate::object_interface) attribute macro. pub unsafe trait ObjectInterfaceType { /// Returns the `glib::Type` ID of the interface. /// /// This will register the type with the type system on the first call. #[doc(alias = "get_type")] fn type_() -> Type; } /// The central trait for defining a `GObject` interface. /// /// Links together the type name, and the interface struct for type registration and allows hooking /// into various steps of the type registration and initialization. /// /// This must only be implemented on `#[repr(C)]` structs and have `gobject_ffi::GTypeInterface` as /// the first field. /// /// See [`register_interface`] for registering an implementation of this trait /// with the type system. /// /// [`register_interface`]: fn.register_interface.html pub unsafe trait ObjectInterface: ObjectInterfaceType + Sized + 'static { /// `GObject` type name. /// /// This must be unique in the whole process. const NAME: &'static str; /// Prerequisites for this interface. /// /// Any implementer of the interface must be a subclass of the prerequisites or implement them /// in case of interfaces. type Prerequisites: PrerequisiteList; /// Additional type initialization. /// /// This is called right after the type was registered and allows /// interfaces to do additional type-specific initialization. /// /// Optional fn type_init(_type_: &mut InitializingType) {} /// Interface initialization. /// /// This is called after `type_init` and before the first implementor /// of the interface is created. Interfaces can use this to do interface- /// specific initialization, e.g. for installing signals on the interface, /// and for setting default implementations of interface functions. /// /// Optional fn interface_init(&mut self) {} /// Properties installed for this interface. /// /// All implementors of the interface must provide these properties. fn properties() -> &'static [ParamSpec] { &[] } /// Signals installed for this interface. fn signals() -> &'static [Signal] { &[] } } pub trait ObjectInterfaceExt: ObjectInterface { /// Get interface from an instance. /// /// This will panic if `obj` does not implement the interface. fn from_instance>(obj: &T) -> &Self { assert!(obj.as_ref().type_().is_a(Self::type_())); unsafe { let klass = (*(obj.as_ptr() as *const gobject_ffi::GTypeInstance)).g_class; let interface = gobject_ffi::g_type_interface_peek(klass as *mut _, Self::type_().into_glib()); assert!(!interface.is_null()); &*(interface as *const Self) } } } impl ObjectInterfaceExt for T {} unsafe extern "C" fn interface_init( klass: ffi::gpointer, _klass_data: ffi::gpointer, ) { let iface = &mut *(klass as *mut T); let pspecs = ::properties(); for pspec in pspecs { gobject_ffi::g_object_interface_install_property( iface as *mut T as *mut _, pspec.to_glib_none().0, ); } let type_ = T::type_(); let signals = ::signals(); for signal in signals { signal.register(type_); } iface.interface_init(); } /// Register a `glib::Type` ID for `T`. /// /// This must be called only once and will panic on a second call. /// /// The [`object_interface!`] macro will create a `type_()` function around this, which will /// ensure that it's only ever called once. /// /// [`object_interface!`]: ../../macro.object_interface.html pub fn register_interface() -> Type { unsafe { use std::ffi::CString; let type_name = CString::new(T::NAME).unwrap(); assert_eq!( gobject_ffi::g_type_from_name(type_name.as_ptr()), gobject_ffi::G_TYPE_INVALID ); let type_ = gobject_ffi::g_type_register_static_simple( Type::INTERFACE.into_glib(), type_name.as_ptr(), mem::size_of::() as u32, Some(interface_init::), 0, None, 0, ); let prerequisites = T::Prerequisites::types(); for prerequisite in prerequisites { gobject_ffi::g_type_interface_add_prerequisite(type_, prerequisite); } let type_ = from_glib(type_); T::type_init(&mut InitializingType::(type_, marker::PhantomData)); type_ } } glib-0.14.8/src/subclass/mod.rs000064400000000000000000000241660072674642500144270ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #![allow(clippy::needless_doctest_main)] //! Module containing infrastructure for subclassing `GObject`s and registering boxed types. //! //! # Example for registering a `glib::Object` subclass //! //! The following code implements a subclass of `glib::Object` with a //! string-typed "name" property. //! //! ```rust //! use glib::prelude::*; //! use glib::subclass; //! use glib::subclass::prelude::*; //! use glib::{Variant, VariantType}; //! //! use std::cell::{Cell, RefCell}; //! //! #[derive(Debug, Eq, PartialEq, Clone, Copy, glib::GEnum)] //! #[repr(u32)] //! // type_name: GType name of the GEnum (mandatory) //! #[genum(type_name = "SimpleObjectAnimal")] //! enum Animal { //! Goat = 0, //! #[genum(name = "The Dog")] //! Dog = 1, //! // name: the name of the GEnumValue (optional), default to the enum name in CamelCase //! // nick: the nick of the GEnumValue (optional), default to the enum name in kebab-case //! #[genum(name = "The Cat", nick = "chat")] //! Cat = 2, //! } //! //! impl Default for Animal { //! fn default() -> Self { //! Animal::Goat //! } //! } //! //! // Note that the first `#[glib::gflags(...)]` is the proc-macro invocation, //! // while the plain `#[gflags(...)]` inside the braces are just custom attributes that //! // get read by the proc-macro, and they must be written exactly like that. //! //! #[glib::gflags("MyFlags")] //! enum MyFlags { //! #[gflags(name = "Flag A", nick = "nick-a")] //! A = 0b00000001, //! #[gflags(name = "Flag B")] //! B = 0b00000010, //! #[gflags(skip)] //! AB = Self::A.bits() | Self::B.bits(), //! C = 0b00000100, //! } //! //! impl Default for MyFlags { //! fn default() -> Self { //! MyFlags::A //! } //! } //! //! mod imp { //! use super::*; //! //! // This is the struct containing all state carried with //! // the new type. Generally this has to make use of //! // interior mutability. //! // If it implements the `Default` trait, then `Self::default()` //! // will be called every time a new instance is created. //! #[derive(Default)] //! pub struct SimpleObject { //! name: RefCell>, //! animal: Cell, //! flags: Cell, //! variant: RefCell>, //! } //! //! // ObjectSubclass is the trait that defines the new type and //! // contains all information needed by the GObject type system, //! // including the new type's name, parent type, etc. //! // If you do not want to implement `Default`, you can provide //! // a `new()` method. //! #[glib::object_subclass] //! impl ObjectSubclass for SimpleObject { //! // This type name must be unique per process. //! const NAME: &'static str = "SimpleObject"; //! //! // The parent type this one is inheriting from. //! type Type = super::SimpleObject; //! type ParentType = glib::Object; //! //! // Interfaces this type implements //! type Interfaces = (); //! } //! //! // Trait that is used to override virtual methods of glib::Object. //! impl ObjectImpl for SimpleObject { //! // Called once in the very beginning to list all properties of this class. //! fn properties() -> &'static [glib::ParamSpec] { //! use once_cell::sync::Lazy; //! static PROPERTIES: Lazy> = Lazy::new(|| { //! vec![ //! glib::ParamSpec::new_string( //! "name", //! "Name", //! "Name of this object", //! None, //! glib::ParamFlags::READWRITE, //! ), //! glib::ParamSpec::new_enum( //! "animal", //! "Animal", //! "Animal", //! Animal::static_type(), //! Animal::default() as i32, //! glib::ParamFlags::READWRITE, //! ), //! glib::ParamSpec::new_flags( //! "flags", //! "Flags", //! "Flags", //! MyFlags::static_type(), //! MyFlags::default().bits(), //! glib::ParamFlags::READWRITE, //! ), //! glib::ParamSpec::new_variant( //! "variant", //! "Variant", //! "Variant", //! glib::VariantTy::ANY, //! None, //! glib::ParamFlags::READWRITE, //! ), //! ] //! }); //! //! PROPERTIES.as_ref() //! } //! //! // Called whenever a property is set on this instance. The id //! // is the same as the index of the property in the PROPERTIES array. //! fn set_property(&self, _obj: &Self::Type, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) { //! match pspec.name() { //! "name" => { //! let name = value //! .get() //! .expect("type conformity checked by `Object::set_property`"); //! self.name.replace(name); //! }, //! "animal" => { //! let animal = value //! .get() //! .expect("type conformity checked by `Object::set_property`"); //! self.animal.replace(animal); //! }, //! "flags" => { //! let flags = value //! .get() //! .expect("type conformity checked by `Object::set_property`"); //! self.flags.replace(flags); //! }, //! "variant" => { //! let variant = value //! .get() //! .expect("type conformity checked by `Object::set_property`"); //! self.variant.replace(variant); //! }, //! _ => unimplemented!(), //! } //! } //! //! // Called whenever a property is retrieved from this instance. The id //! // is the same as the index of the property in the PROPERTIES array. //! fn property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { //! match pspec.name() { //! "name" => self.name.borrow().to_value(), //! "animal" => self.animal.get().to_value(), //! "flags" => self.flags.get().to_value(), //! "variant" => self.variant.borrow().to_value(), //! _ => unimplemented!(), //! } //! } //! //! // Called right after construction of the instance. //! fn constructed(&self, obj: &Self::Type) { //! // Chain up to the parent type's implementation of this virtual //! // method. //! self.parent_constructed(obj); //! //! // And here we could do our own initialization. //! } //! } //! } //! //! // Optionally, define a wrapper type to make it more ergonomic to use from Rust //! glib::wrapper! { //! pub struct SimpleObject(ObjectSubclass); //! } //! //! impl SimpleObject { //! // Create an object instance of the new type. //! pub fn new() -> Self { //! glib::Object::new(&[]).unwrap() //! } //! } //! //! pub fn main() { //! let obj = SimpleObject::new(); //! //! // Get the name property and change its value. //! assert_eq!(obj.property("name").unwrap().get::>(), Ok(None)); //! obj.set_property("name", &"test").unwrap(); //! assert_eq!( //! obj.property("name").unwrap().get::<&str>(), //! Ok("test") //! ); //! //! assert_eq!(obj.property("animal").unwrap().get::(), Ok(Animal::Goat)); //! obj.set_property("animal", &Animal::Cat).unwrap(); //! assert_eq!(obj.property("animal").unwrap().get::(), Ok(Animal::Cat)); //! //! assert_eq!(obj.property("flags").unwrap().get::(), Ok(MyFlags::A)); //! obj.set_property("flags", &MyFlags::B).unwrap(); //! assert_eq!(obj.property("flags").unwrap().get::(), Ok(MyFlags::B)); //! } //! ``` //! //! # Example for registering a boxed type for a Rust struct //! //! The following code boxed type for a tuple struct around `String` and uses it in combination //! with `glib::Value`. //! //! ```rust //! use glib::prelude::*; //! use glib::subclass; //! use glib::subclass::prelude::*; //! //! #[derive(Clone, Debug, PartialEq, Eq, glib::GBoxed)] //! #[gboxed(type_name = "MyBoxed")] //! struct MyBoxed(String); //! //! pub fn main() { //! assert!(MyBoxed::static_type().is_valid()); //! //! let b = MyBoxed(String::from("abc")); //! let v = b.to_value(); //! let b2 = v.get::<&MyBoxed>().unwrap(); //! assert_eq!(&b, b2); //! } //! ``` pub mod basic; #[macro_use] pub mod types; #[macro_use] pub mod interface; #[macro_use] pub mod object; #[macro_use] pub mod boxed; pub mod shared; pub mod signal; pub mod prelude { //! Prelude that re-exports all important traits from this crate. pub use super::boxed::BoxedType; pub use super::interface::{ObjectInterface, ObjectInterfaceExt, ObjectInterfaceType}; pub use super::object::{ObjectClassSubclassExt, ObjectImpl, ObjectImplExt}; pub use super::shared::{RefCounted, SharedType}; pub use super::types::{ ClassStruct, InstanceStruct, IsImplementable, IsSubclassable, ObjectSubclass, ObjectSubclassExt, ObjectSubclassType, }; } pub use self::boxed::register_boxed_type; pub use self::interface::register_interface; pub use self::signal::{ Signal, SignalClassHandlerToken, SignalId, SignalInvocationHint, SignalQuery, SignalType, }; pub use self::types::{register_type, InitializingObject, InitializingType, TypeData}; glib-0.14.8/src/subclass/object.rs000064400000000000000000000540520072674642500151130ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! Module that contains all types needed for creating a direct subclass of `GObject` //! or implementing virtual methods of it. use super::prelude::*; use super::Signal; use crate::translate::*; use crate::{Cast, Object, ObjectType, ParamSpec, Value}; use std::mem; use std::ptr; /// Trait for implementors of `glib::Object` subclasses. /// /// This allows overriding the virtual methods of `glib::Object`. pub trait ObjectImpl: ObjectSubclass + ObjectImplExt { /// Properties installed for this type. fn properties() -> &'static [ParamSpec] { &[] } /// Signals installed for this type. fn signals() -> &'static [Signal] { &[] } /// Property setter. /// /// This is called whenever the property of this specific subclass with the /// given index is set. The new value is passed as `glib::Value`. fn set_property(&self, _obj: &Self::Type, _id: usize, _value: &Value, _pspec: &ParamSpec) { unimplemented!() } /// Property getter. /// /// This is called whenever the property value of the specific subclass with the /// given index should be returned. #[doc(alias = "get_property")] fn property(&self, _obj: &Self::Type, _id: usize, _pspec: &ParamSpec) -> Value { unimplemented!() } /// Constructed. /// /// This is called once construction of the instance is finished. /// /// Should chain up to the parent class' implementation. fn constructed(&self, obj: &Self::Type) { self.parent_constructed(obj); } /// Disposes of the object. /// /// When `dispose()` ends, the object should not hold any reference to any other member object. /// The object is also expected to be able to answer client method invocations (with possibly an /// error code but no memory violation) until it is dropped. `dispose()` can be executed more /// than once. fn dispose(&self, _obj: &Self::Type) {} } #[doc(alias = "get_property")] unsafe extern "C" fn property( obj: *mut gobject_ffi::GObject, id: u32, value: *mut gobject_ffi::GValue, pspec: *mut gobject_ffi::GParamSpec, ) { let instance = &*(obj as *mut T::Instance); let imp = instance.impl_(); let v = imp.property( from_glib_borrow::<_, Object>(obj).unsafe_cast_ref(), id as usize, &from_glib_borrow(pspec), ); // We first unset the value we get passed in, in case it contained // any previous data. Then we directly overwrite it with our new // value, and pass ownership of the contained data to the C GValue // by forgetting it on the Rust side. // // Without this, by using the GValue API, we would have to create // a copy of the value when setting it on the destination just to // immediately free the original value afterwards. gobject_ffi::g_value_unset(value); let v = mem::ManuallyDrop::new(v); ptr::write(value, ptr::read(v.to_glib_none().0)); } unsafe extern "C" fn set_property( obj: *mut gobject_ffi::GObject, id: u32, value: *mut gobject_ffi::GValue, pspec: *mut gobject_ffi::GParamSpec, ) { let instance = &*(obj as *mut T::Instance); let imp = instance.impl_(); imp.set_property( from_glib_borrow::<_, Object>(obj).unsafe_cast_ref(), id as usize, &*(value as *mut Value), &from_glib_borrow(pspec), ); } unsafe extern "C" fn constructed(obj: *mut gobject_ffi::GObject) { let instance = &*(obj as *mut T::Instance); let imp = instance.impl_(); imp.constructed(from_glib_borrow::<_, Object>(obj).unsafe_cast_ref()); } unsafe extern "C" fn dispose(obj: *mut gobject_ffi::GObject) { let instance = &*(obj as *mut T::Instance); let imp = instance.impl_(); imp.dispose(from_glib_borrow::<_, Object>(obj).unsafe_cast_ref()); // Chain up to the parent's dispose. let data = T::type_data(); let parent_class = data.as_ref().parent_class() as *mut gobject_ffi::GObjectClass; if let Some(ref func) = (*parent_class).dispose { func(obj); } } /// Extension trait for `glib::Object`'s class struct. /// /// This contains various class methods and allows subclasses to override signal class handlers. pub unsafe trait ObjectClassSubclassExt: Sized + 'static { fn override_signal_class_handler(&mut self, name: &str, class_handler: F) where F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option + Send + Sync + 'static, { unsafe { super::types::signal_override_class_handler( name, *(self as *mut _ as *mut ffi::GType), class_handler, ); } } } unsafe impl ObjectClassSubclassExt for crate::Class {} unsafe impl IsSubclassable for Object { fn class_init(class: &mut crate::Class) { let klass = class.as_mut(); klass.set_property = Some(set_property::); klass.get_property = Some(property::); klass.constructed = Some(constructed::); klass.dispose = Some(dispose::); let pspecs = ::properties(); if !pspecs.is_empty() { unsafe { let mut pspecs_ptrs = Vec::with_capacity(pspecs.len() + 1); pspecs_ptrs.push(ptr::null_mut()); for pspec in pspecs { pspecs_ptrs.push(pspec.to_glib_none().0); } gobject_ffi::g_object_class_install_properties( klass, pspecs_ptrs.len() as u32, pspecs_ptrs.as_mut_ptr(), ); } } let type_ = T::type_(); let signals = ::signals(); for signal in signals { signal.register(type_); } } fn instance_init(_instance: &mut super::InitializingObject) {} } pub trait ObjectImplExt: ObjectSubclass { /// Chain up to the parent class' implementation of `glib::Object::constructed()`. fn parent_constructed(&self, obj: &Self::Type); /// Chain up to parent class signal handler. fn signal_chain_from_overridden( &self, token: &super::SignalClassHandlerToken, values: &[Value], ) -> Option; } impl ObjectImplExt for T { fn parent_constructed(&self, obj: &Self::Type) { unsafe { let data = T::type_data(); let parent_class = data.as_ref().parent_class() as *mut gobject_ffi::GObjectClass; if let Some(ref func) = (*parent_class).constructed { func(obj.unsafe_cast_ref::().to_glib_none().0); } } } fn signal_chain_from_overridden( &self, token: &super::SignalClassHandlerToken, values: &[Value], ) -> Option { unsafe { super::types::signal_chain_from_overridden( self.instance().as_ptr() as *mut _, token, values, ) } } } #[cfg(test)] mod test { use super::super::super::object::ObjectExt; use super::super::super::value::{ToValue, Value}; use super::*; // We rename the current crate as glib, since the macros in glib-macros // generate the glib namespace through the crate_ident_new utility, // and that returns `glib` (and not `crate`) when called inside the glib crate use crate as glib; use crate::StaticType; use std::cell::RefCell; mod imp { use super::*; // A dummy `Object` to test setting an `Object` property and returning an `Object` in signals #[derive(Default)] pub struct ChildObject; #[glib::object_subclass] impl ObjectSubclass for ChildObject { const NAME: &'static str = "ChildObject"; type Type = super::ChildObject; type ParentType = Object; } impl ObjectImpl for ChildObject {} #[derive(Default)] pub struct SimpleObject { name: RefCell>, construct_name: RefCell>, constructed: RefCell, } #[glib::object_subclass] impl ObjectSubclass for SimpleObject { const NAME: &'static str = "SimpleObject"; type Type = super::SimpleObject; type ParentType = Object; type Interfaces = (super::Dummy,); } impl ObjectImpl for SimpleObject { fn properties() -> &'static [ParamSpec] { use once_cell::sync::Lazy; static PROPERTIES: Lazy> = Lazy::new(|| { vec![ crate::ParamSpec::new_string( "name", "Name", "Name of this object", None, crate::ParamFlags::READWRITE, ), crate::ParamSpec::new_string( "construct-name", "Construct Name", "Construct Name of this object", None, crate::ParamFlags::READWRITE | crate::ParamFlags::CONSTRUCT_ONLY, ), crate::ParamSpec::new_boolean( "constructed", "Constructed", "True if the constructed() virtual method was called", false, crate::ParamFlags::READABLE, ), crate::ParamSpec::new_object( "child", "Child", "Child object", super::ChildObject::static_type(), crate::ParamFlags::READWRITE, ), ] }); PROPERTIES.as_ref() } fn signals() -> &'static [super::Signal] { use once_cell::sync::Lazy; static SIGNALS: Lazy> = Lazy::new(|| { vec![ super::Signal::builder( "name-changed", &[String::static_type().into()], crate::Type::UNIT.into(), ) .build(), super::Signal::builder( "change-name", &[String::static_type().into()], String::static_type().into(), ) .action() .class_handler(|_, args| { let obj = args[0] .get::() .expect("Failed to get Object from args[0]"); let new_name = args[1] .get::() .expect("Failed to get Object from args[1]"); let imp = SimpleObject::from_instance(&obj); let old_name = imp.name.borrow_mut().take(); *imp.name.borrow_mut() = Some(new_name); obj.emit_by_name("name-changed", &[&*imp.name.borrow()]) .expect("Failed to borrow name"); Some(old_name.to_value()) }) .build(), super::Signal::builder("create-string", &[], String::static_type().into()) .build(), super::Signal::builder( "create-child-object", &[], ChildObject::type_().into(), ) .build(), ] }); SIGNALS.as_ref() } fn set_property( &self, obj: &Self::Type, _id: usize, value: &Value, pspec: &crate::ParamSpec, ) { match pspec.name() { "name" => { let name = value .get() .expect("type conformity checked by 'Object::set_property'"); self.name.replace(name); obj.emit_by_name("name-changed", &[&*self.name.borrow()]) .expect("Failed to borrow name"); } "construct-name" => { let name = value .get() .expect("type conformity checked by 'Object::set_property'"); self.construct_name.replace(name); } "child" => { // not stored, only used to test `set_property` with `Objects` } _ => unimplemented!(), } } fn property(&self, _obj: &Self::Type, _id: usize, pspec: &crate::ParamSpec) -> Value { match pspec.name() { "name" => self.name.borrow().to_value(), "construct-name" => self.construct_name.borrow().to_value(), "constructed" => self.constructed.borrow().to_value(), _ => unimplemented!(), } } fn constructed(&self, obj: &Self::Type) { self.parent_constructed(obj); assert_eq!(obj, &self.instance()); assert_eq!(self as *const _, Self::from_instance(obj) as *const _); *self.constructed.borrow_mut() = true; } } #[derive(Clone, Copy)] #[repr(C)] pub struct DummyInterface { parent: gobject_ffi::GTypeInterface, } #[glib::object_interface] unsafe impl ObjectInterface for DummyInterface { const NAME: &'static str = "Dummy"; } } wrapper! { pub struct ChildObject(ObjectSubclass); } wrapper! { pub struct SimpleObject(ObjectSubclass); } wrapper! { pub struct Dummy(ObjectInterface); } unsafe impl IsImplementable for Dummy { fn interface_init(_iface: &mut crate::Interface) {} fn instance_init(_instance: &mut super::super::InitializingObject) {} } #[test] fn test_create() { let type_ = SimpleObject::static_type(); let obj = Object::with_type(type_, &[]).expect("Object::new failed"); assert!(obj.type_().is_a(Dummy::static_type())); assert!(obj .property("constructed") .expect("Failed to get 'constructed' property") .get::() .expect("Failed to get bool from 'constructed' property"),); let weak = obj.downgrade(); drop(obj); assert!(weak.upgrade().is_none()); } #[test] fn test_create_child_object() { let obj: ChildObject = Object::new(&[]).expect("Object::new failed"); let imp = imp::ChildObject::from_instance(&obj); assert_eq!(obj, imp.instance()); } #[test] fn test_set_properties() { let obj = Object::with_type( SimpleObject::static_type(), &[("construct-name", &"meh"), ("name", &"initial")], ) .expect("Object::new failed"); assert_eq!( obj.property("construct-name") .expect("Failed to get 'construct-name' property") .get::<&str>() .expect("Failed to get str from 'construct-name' property"), "meh" ); assert_eq!( obj.set_property("construct-name", &"test") .err() .expect("Failed to set 'construct-name' property") .to_string(), "property 'construct-name' of type 'SimpleObject' is not writable", ); assert_eq!( obj.property("construct-name") .expect("Failed to get 'construct-name' property") .get::<&str>() .expect("Failed to get str from 'construct-name' property"), "meh" ); assert_eq!( obj.property("name") .expect("Failed to get 'name' property") .get::<&str>() .expect("Failed to get str from 'name' property"), "initial" ); assert!(obj.set_property("name", &"test").is_ok()); assert_eq!( obj.property("name") .expect("Failed to get 'name' property") .get::<&str>() .expect("Failed to get str from 'name' property"), "test" ); assert_eq!( obj.set_property("test", &true) .err() .expect("set_property failed") .to_string(), "property 'test' of type 'SimpleObject' not found", ); assert_eq!( obj.set_property("constructed", &false) .err() .expect("Failed to set 'constructed' property") .to_string(), "property 'constructed' of type 'SimpleObject' is not writable", ); assert_eq!( obj.set_property("name", &false) .err() .expect("Failed to set 'name' property") .to_string(), "property 'name' of type 'SimpleObject' can't be set from the given type (expected: 'gchararray', got: 'gboolean')", ); let other_obj = Object::with_type(SimpleObject::static_type(), &[]).expect("Object::new failed"); assert_eq!( obj.set_property("child", &other_obj) .err() .expect("Failed to set 'child' property") .to_string(), "property 'child' of type 'SimpleObject' can't be set from the given object type (expected: 'ChildObject', got: 'SimpleObject')", ); let child = Object::with_type(ChildObject::static_type(), &[]).expect("Object::new failed"); assert!(obj.set_property("child", &child).is_ok()); } #[test] fn test_signals() { use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; let type_ = SimpleObject::static_type(); let obj = Object::with_type(type_, &[("name", &"old-name")]).expect("Object::new failed"); let name_changed_triggered = Arc::new(AtomicBool::new(false)); let name_changed_clone = name_changed_triggered.clone(); obj.connect("name-changed", false, move |args| { let _obj = args[0].get::().expect("Failed to get args[0]"); let name = args[1].get::<&str>().expect("Failed to get args[1]"); assert_eq!(name, "new-name"); name_changed_clone.store(true, Ordering::Relaxed); None }) .expect("Failed to connect on 'name-changed'"); assert_eq!( obj.property("name") .expect("Failed to get 'name' property") .get::<&str>() .expect("Failed to get str from 'name' property"), "old-name" ); assert!(!name_changed_triggered.load(Ordering::Relaxed)); assert_eq!( obj.emit_by_name("change-name", &[&"new-name"]) .expect("Failed to emit") .expect("Failed to get value from emit") .get::<&str>() .expect("Failed to get str from emit"), "old-name" ); assert!(name_changed_triggered.load(Ordering::Relaxed)); } #[test] fn test_signal_return_expected_type() { let obj = Object::with_type(SimpleObject::static_type(), &[]).expect("Object::new failed"); obj.connect("create-string", false, move |_args| { Some("return value".to_value()) }) .expect("Failed to connect on 'create-string'"); let signal_id = imp::SimpleObject::signals()[2].signal_id(); let value = obj .emit(signal_id, &[]) .expect("Failed to emit") .expect("Failed to get value from emit"); assert_eq!(value.get::<&str>(), Ok("return value")); } #[test] fn test_callback_validity() { use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; let type_ = SimpleObject::static_type(); let obj = Object::with_type(type_, &[("name", &"old-name")]).expect("Object::new failed"); let name_changed_triggered = Arc::new(AtomicBool::new(false)); let name_changed_clone = name_changed_triggered.clone(); obj.connect_notify(Some("name"), move |_, _| { name_changed_clone.store(true, Ordering::Relaxed); }); obj.notify("name"); assert!(name_changed_triggered.load(Ordering::Relaxed)); } // Note: can't test type mismatch in signals since panics accross FFI boundaries // are UB. See https://github.com/gtk-rs/glib/issues/518 #[test] fn test_signal_return_expected_object_type() { let obj = Object::with_type(SimpleObject::static_type(), &[]).expect("Object::new failed"); obj.connect("create-child-object", false, move |_args| { Some( Object::with_type(ChildObject::static_type(), &[]) .expect("Object::new failed") .to_value(), ) }) .expect("Failed to connect on 'create-child-object'"); let value = obj .emit_by_name("create-child-object", &[]) .expect("Failed to emit") .expect("Failed to get value from emit"); assert!(value.type_().is_a(ChildObject::static_type())); } } glib-0.14.8/src/subclass/shared.rs000064400000000000000000000161440072674642500151130ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! Module for registering shared types for Rust types. use crate::translate::*; use crate::StaticType; pub unsafe trait RefCounted: Clone + Sized + 'static { /// The inner type type InnerType; /// The function used to increment the inner type refcount unsafe fn ref_(this: *const Self::InnerType) -> *const Self::InnerType; /// Converts the RefCounted object to a raw pointer to InnerType unsafe fn into_raw(self) -> *const Self::InnerType; /// Converts a raw pointer to InnerType to a RefCounted object unsafe fn from_raw(this: *const Self::InnerType) -> Self; } unsafe impl RefCounted for std::sync::Arc where T: 'static, { type InnerType = T; unsafe fn ref_(this: *const Self::InnerType) -> *const Self::InnerType { std::sync::Arc::increment_strong_count(this); this } unsafe fn into_raw(self) -> *const Self::InnerType { std::sync::Arc::into_raw(self) } unsafe fn from_raw(this: *const Self::InnerType) -> Self { std::sync::Arc::from_raw(this) } } unsafe impl RefCounted for std::rc::Rc where T: 'static, { type InnerType = T; unsafe fn ref_(this: *const Self::InnerType) -> *const Self::InnerType { use std::mem::ManuallyDrop; let this_rc = ManuallyDrop::new(std::rc::Rc::from_raw(this)); std::rc::Rc::into_raw(ManuallyDrop::take(&mut this_rc.clone())) } unsafe fn into_raw(self) -> *const Self::InnerType { std::rc::Rc::into_raw(self) } unsafe fn from_raw(this: *const Self::InnerType) -> Self { std::rc::Rc::from_raw(this) } } /// Trait for defining shared types. /// /// Links together the type name with the type itself. /// /// See [`register_shared_type`] for registering an implementation of this trait /// with the type system. /// /// [`register_shared_type`]: fn.register_shared_type.html pub trait SharedType: StaticType + Clone + Sized + 'static { /// Shared type name. /// /// This must be unique in the whole process. const NAME: &'static str; /// The inner refcounted type type RefCountedType: RefCounted; /// Converts the SharedType into its inner RefCountedType fn into_refcounted(self) -> Self::RefCountedType; /// Constructs a SharedType from a RefCountedType fn from_refcounted(this: Self::RefCountedType) -> Self; } /// Register a boxed `glib::Type` ID for `T`. /// /// This must be called only once and will panic on a second call. /// /// See [`Shared!`] for defining a function that ensures that /// this is only called once and returns the type id. /// /// [`Shared!`]: ../../derive.Shared.html pub fn register_shared_type() -> crate::Type { unsafe { use std::ffi::CString; unsafe extern "C" fn shared_ref(v: ffi::gpointer) -> ffi::gpointer { T::RefCountedType::ref_(v as *const ::InnerType) as ffi::gpointer } unsafe extern "C" fn shared_unref(v: ffi::gpointer) { let _ = T::RefCountedType::from_raw( v as *const ::InnerType, ); } let type_name = CString::new(T::NAME).unwrap(); if gobject_ffi::g_type_from_name(type_name.as_ptr()) != gobject_ffi::G_TYPE_INVALID { panic!( "Type {} has already been registered", type_name.to_str().unwrap() ); } from_glib(gobject_ffi::g_boxed_type_register_static( type_name.as_ptr(), Some(shared_ref::), Some(shared_unref::), )) } } #[cfg(test)] mod test { use super::*; // We rename the current crate as glib, since the macros in glib-macros // generate the glib namespace through the crate_ident_new utility, // and that returns `glib` (and not `crate`) when called inside the glib crate use crate as glib; use crate::value::ToValue; #[derive(Clone, Debug, PartialEq, Eq)] struct MySharedInner { foo: String, } #[derive(Clone, Debug, PartialEq, Eq, glib::GSharedBoxed)] #[gshared_boxed(type_name = "MySharedArc")] struct MySharedArc(std::sync::Arc); #[derive(Clone, Debug, PartialEq, Eq, glib::GSharedBoxed)] #[gshared_boxed(type_name = "MySharedRc")] struct MySharedRc(std::rc::Rc); #[test] fn test_register() { assert_ne!(crate::Type::INVALID, MySharedArc::static_type()); assert_ne!(crate::Type::INVALID, MySharedRc::static_type()); } #[test] fn test_value_arc() { assert_ne!(crate::Type::INVALID, MySharedArc::static_type()); let b = MySharedArc::from_refcounted(std::sync::Arc::new(MySharedInner { foo: String::from("abc"), })); let v = b.to_value(); let b2 = v.get::().unwrap(); assert!(std::sync::Arc::ptr_eq(&b.0, &b2.0)); } #[test] fn test_value_rc() { assert_ne!(crate::Type::INVALID, MySharedRc::static_type()); let b = MySharedRc::from_refcounted(std::rc::Rc::new(MySharedInner { foo: String::from("abc"), })); let v = b.to_value(); let b2 = v.get::().unwrap(); assert!(std::rc::Rc::ptr_eq(&b.0, &b2.0)); } #[test] fn same_ffi_pointer_arc() { assert_ne!(crate::Type::INVALID, MySharedArc::static_type()); let b = MySharedArc::from_refcounted(std::sync::Arc::new(MySharedInner { foo: String::from("abc"), })); let inner_raw_ptr = std::sync::Arc::into_raw(b.clone().0); assert_eq!(std::sync::Arc::strong_count(&b.0), 2); let inner_raw_ptr_clone = unsafe { ::RefCountedType::ref_(inner_raw_ptr) }; assert_eq!(std::sync::Arc::strong_count(&b.0), 3); assert!(std::ptr::eq(inner_raw_ptr, inner_raw_ptr_clone)); let _ = unsafe { ::RefCountedType::from_raw(inner_raw_ptr) }; let _ = unsafe { ::RefCountedType::from_raw(inner_raw_ptr_clone) }; assert_eq!(std::sync::Arc::strong_count(&b.0), 1); } #[test] fn same_ffi_pointer_rc() { assert_ne!(crate::Type::INVALID, MySharedRc::static_type()); let b = MySharedRc::from_refcounted(std::rc::Rc::new(MySharedInner { foo: String::from("abc"), })); let inner_raw_ptr = std::rc::Rc::into_raw(b.clone().0); assert_eq!(std::rc::Rc::strong_count(&b.0), 2); let inner_raw_ptr_clone = unsafe { ::RefCountedType::ref_(inner_raw_ptr) }; assert_eq!(std::rc::Rc::strong_count(&b.0), 3); assert!(std::ptr::eq(inner_raw_ptr, inner_raw_ptr_clone)); let _ = unsafe { ::RefCountedType::from_raw(inner_raw_ptr) }; let _ = unsafe { ::RefCountedType::from_raw(inner_raw_ptr_clone) }; assert_eq!(std::rc::Rc::strong_count(&b.0), 1); } } glib-0.14.8/src/subclass/signal.rs000064400000000000000000000422210072674642500151150ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use smallvec::SmallVec; use crate::translate::*; use crate::utils::is_canonical_pspec_name; use crate::Closure; use crate::SignalFlags; use crate::Type; use crate::Value; use std::ptr; use std::sync::Mutex; use std::{fmt, num::NonZeroU32}; /// Builder for signals. #[allow(clippy::type_complexity)] pub struct SignalBuilder<'a> { name: &'a str, flags: SignalFlags, param_types: &'a [SignalType], return_type: SignalType, class_handler: Option< Box Option + Send + Sync + 'static>, >, accumulator: Option< Box bool + Send + Sync + 'static>, >, } /// Signal metadata. pub struct Signal { name: String, flags: SignalFlags, param_types: Vec, return_type: SignalType, registration: Mutex, } /// Token passed to signal class handlers. pub struct SignalClassHandlerToken(pub(super) *mut gobject_ffi::GTypeInstance); impl fmt::Debug for SignalClassHandlerToken { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.debug_tuple("SignalClassHandlerToken") .field(&unsafe { crate::Object::from_glib_borrow(self.0 as *mut gobject_ffi::GObject) }) .finish() } } /// Signal invocation hint passed to signal accumulators. #[repr(transparent)] pub struct SignalInvocationHint(gobject_ffi::GSignalInvocationHint); impl SignalInvocationHint { pub fn detail(&self) -> crate::Quark { unsafe { from_glib(self.0.detail) } } pub fn run_type(&self) -> SignalFlags { unsafe { from_glib(self.0.run_type) } } } impl fmt::Debug for SignalInvocationHint { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.debug_struct("SignalInvocationHint") .field("detail", &self.detail()) .field("run_type", &self.run_type()) .finish() } } /// In-depth information of a specific signal pub struct SignalQuery(gobject_ffi::GSignalQuery); impl SignalQuery { /// The name of the signal. pub fn signal_name<'a>(&self) -> &'a str { unsafe { let ptr = self.0.signal_name; std::ffi::CStr::from_ptr(ptr).to_str().unwrap() } } /// The ID of the signal. pub fn signal_id(&self) -> SignalId { unsafe { SignalId::from_glib(self.0.signal_id) } } /// The instance type this signal can be emitted for. pub fn type_(&self) -> Type { unsafe { from_glib(self.0.itype) } } /// The signal flags. pub fn flags(&self) -> SignalFlags { unsafe { from_glib(self.0.signal_flags) } } /// The return type for the user callback. pub fn return_type(&self) -> SignalType { unsafe { from_glib(self.0.return_type) } } /// The number of parameters the user callback takes. pub fn n_params(&self) -> u32 { self.0.n_params } /// The parameters for the user callback. pub fn param_types(&self) -> SmallVec<[SignalType; 10]> { unsafe { let types = self.0.param_types; FromGlibContainerAsVec::from_glib_none_num_as_vec(types, self.n_params() as usize) .into_iter() .collect::>() } } } impl fmt::Debug for SignalQuery { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.debug_struct("SignalQuery") .field("signal_name", &self.signal_name()) .field("type", &self.type_()) .field("flags", &self.flags()) .field("return_type", &self.return_type()) .field("param_types", &self.param_types()) .finish() } } /// Signal ID. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct SignalId(NonZeroU32); impl SignalId { /// Create a new Signal Identifier. /// /// # Safety /// /// The caller has to ensure it's a valid signal identifier. pub unsafe fn new(id: NonZeroU32) -> Self { Self(id) } #[doc(alias = "g_signal_parse_name")] pub fn parse_name(name: &str, type_: Type, force_detail: bool) -> Option<(Self, crate::Quark)> { let mut signal_id = std::mem::MaybeUninit::uninit(); let mut detail_quark = std::mem::MaybeUninit::uninit(); unsafe { let found: bool = from_glib(gobject_ffi::g_signal_parse_name( name.to_glib_none().0, type_.into_glib(), signal_id.as_mut_ptr(), detail_quark.as_mut_ptr(), force_detail.into_glib(), )); if found { Some(( from_glib(signal_id.assume_init()), crate::Quark::from_glib(detail_quark.assume_init()), )) } else { None } } } /// Find a SignalId by its `name`, and the `type` it connects to. #[doc(alias = "g_signal_lookup")] pub fn lookup(name: &str, type_: Type) -> Option { unsafe { let signal_id = gobject_ffi::g_signal_lookup(name.to_glib_none().0, type_.into_glib()); if signal_id == 0 { None } else { Some(Self::new(NonZeroU32::new_unchecked(signal_id))) } } } /// Queries more in-depth information about the current signal. #[doc(alias = "g_signal_query")] pub fn query(&self) -> SignalQuery { unsafe { let mut query_ptr = std::mem::MaybeUninit::uninit(); gobject_ffi::g_signal_query(self.into_glib(), query_ptr.as_mut_ptr()); let query = query_ptr.assume_init(); assert_ne!(query.signal_id, 0); SignalQuery(query) } } /// Find the signal name. #[doc(alias = "g_signal_name")] pub fn name<'a>(&self) -> &'a str { unsafe { let ptr = gobject_ffi::g_signal_name(self.into_glib()); std::ffi::CStr::from_ptr(ptr).to_str().unwrap() } } } #[doc(hidden)] impl FromGlib for SignalId { unsafe fn from_glib(signal_id: u32) -> Self { assert_ne!(signal_id, 0); Self::new(NonZeroU32::new_unchecked(signal_id)) } } #[doc(hidden)] impl IntoGlib for SignalId { type GlibType = u32; fn into_glib(self) -> u32 { self.0.into() } } #[derive(Copy, Clone, Hash)] pub struct SignalType(ffi::GType); impl SignalType { pub fn with_static_scope(type_: Type) -> Self { Self(type_.into_glib() | gobject_ffi::G_TYPE_FLAG_RESERVED_ID_BIT) } pub fn static_scope(&self) -> bool { (self.0 & gobject_ffi::G_TYPE_FLAG_RESERVED_ID_BIT) != 0 } pub fn type_(&self) -> Type { (*self).into() } } impl From for SignalType { fn from(type_: Type) -> Self { Self(type_.into_glib()) } } impl From for Type { fn from(type_: SignalType) -> Self { // Remove the extra-bit used for G_SIGNAL_TYPE_STATIC_SCOPE let type_ = type_.0 & (!gobject_ffi::G_TYPE_FLAG_RESERVED_ID_BIT); unsafe { from_glib(type_) } } } impl PartialEq for SignalType { fn eq(&self, other: &Type) -> bool { let type_: Type = (*self).into(); type_.eq(other) } } impl std::fmt::Debug for SignalType { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let type_: Type = (*self).into(); f.debug_struct("SignalType") .field("name", &type_.name()) .field("static_scope", &self.static_scope()) .finish() } } impl std::fmt::Display for SignalType { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let type_: Type = (*self).into(); f.debug_struct("SignalType") .field("name", &type_.name()) .field("static_scope", &self.static_scope()) .finish() } } #[doc(hidden)] impl FromGlib for SignalType { unsafe fn from_glib(type_: ffi::GType) -> Self { Self(type_) } } #[doc(hidden)] impl IntoGlib for SignalType { type GlibType = ffi::GType; fn into_glib(self) -> ffi::GType { self.0 } } impl FromGlibContainerAsVec for SignalType { unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GType, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for i in 0..num { res.push(from_glib(*ptr.add(i))); } res } unsafe fn from_glib_container_num_as_vec(_: *const ffi::GType, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } unsafe fn from_glib_full_num_as_vec(_: *const ffi::GType, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } } #[allow(clippy::type_complexity)] enum SignalRegistration { Unregistered { class_handler: Option< Box< dyn Fn(&SignalClassHandlerToken, &[Value]) -> Option + Send + Sync + 'static, >, >, accumulator: Option< Box bool + Send + Sync + 'static>, >, }, Registered { type_: Type, signal_id: SignalId, }, } impl<'a> SignalBuilder<'a> { /// Run the signal class handler in the first emission stage. pub fn run_first(mut self) -> Self { self.flags |= SignalFlags::RUN_FIRST; self } /// Run the signal class handler in the third emission stage. pub fn run_last(mut self) -> Self { self.flags |= SignalFlags::RUN_LAST; self } /// Run the signal class handler in the last emission stage. pub fn run_cleanup(mut self) -> Self { self.flags |= SignalFlags::RUN_CLEANUP; self } /// Signals being emitted for an object while currently being in emission for this very object /// will not be emitted recursively, but instead cause the first emission to be restarted. pub fn no_recurse(mut self) -> Self { self.flags |= SignalFlags::NO_RECURSE; self } /// This signal supports "::detail" appendices to the signal name upon handler connections and /// emissions. pub fn detailed(mut self) -> Self { self.flags |= SignalFlags::DETAILED; self } /// Action signals are signals that may freely be emitted on alive objects from user code. pub fn action(mut self) -> Self { self.flags |= SignalFlags::ACTION; self } /// No emissions hooks are supported for this signal. pub fn no_hooks(mut self) -> Self { self.flags |= SignalFlags::NO_HOOKS; self } /// Varargs signal emission will always collect the arguments, even if there are no signal /// handlers connected. pub fn must_collect(mut self) -> Self { self.flags |= SignalFlags::MUST_COLLECT; self } /// The signal is deprecated and will be removed in a future version. pub fn deprecated(mut self) -> Self { self.flags |= SignalFlags::DEPRECATED; self } /// Explicitly set all flags. /// /// This overrides previously set flags on this builder. pub fn flags(mut self, flags: SignalFlags) -> Self { self.flags = flags; self } /// Class handler for this signal. pub fn class_handler< F: Fn(&SignalClassHandlerToken, &[Value]) -> Option + Send + Sync + 'static, >( mut self, func: F, ) -> Self { self.class_handler = Some(Box::new(func)); self } /// Accumulator for the return values of the signal. /// /// This is called if multiple signal handlers are connected to the signal for accumulating the /// return values into a single value. pub fn accumulator< F: Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static, >( mut self, func: F, ) -> Self { self.accumulator = Some(Box::new(func)); self } /// Build the signal. /// /// This does not register the signal yet, which only happens as part of object type /// registration. pub fn build(self) -> Signal { let flags = if self.flags & (SignalFlags::RUN_FIRST | SignalFlags::RUN_LAST | SignalFlags::RUN_CLEANUP) == SignalFlags::empty() { self.flags | SignalFlags::RUN_LAST } else { self.flags }; Signal { name: String::from(self.name), flags, param_types: self.param_types.to_vec(), return_type: self.return_type, registration: Mutex::new(SignalRegistration::Unregistered { class_handler: self.class_handler, accumulator: self.accumulator, }), } } } impl Signal { /// Create a new builder for a signal. pub fn builder<'a>( name: &'a str, param_types: &'a [SignalType], return_type: SignalType, ) -> SignalBuilder<'a> { assert!( is_canonical_pspec_name(name), "{} is not a valid canonical signal name", name ); SignalBuilder { name, param_types, return_type, flags: SignalFlags::empty(), class_handler: None, accumulator: None, } } /// Name of the signal. pub fn name(&self) -> &str { &self.name } /// Flags of the signal. pub fn flags(&self) -> SignalFlags { self.flags } /// Parameter types of the signal. pub fn param_types(&self) -> &[SignalType] { &self.param_types } /// Return type of the signal. pub fn return_type(&self) -> SignalType { self.return_type } /// Signal ID. /// /// This will panic if called before the signal was registered. pub fn signal_id(&self) -> SignalId { match &*self.registration.lock().unwrap() { SignalRegistration::Unregistered { .. } => panic!("Signal not registered yet"), SignalRegistration::Registered { signal_id, .. } => *signal_id, } } /// Type this signal was registered for. /// /// This will panic if called before the signal was registered. pub fn type_(&self) -> Type { match &*self.registration.lock().unwrap() { SignalRegistration::Unregistered { .. } => panic!("Signal not registered yet"), SignalRegistration::Registered { type_, .. } => *type_, } } pub(super) fn register(&self, type_: Type) { let mut registration = self.registration.lock().unwrap(); let (class_handler, accumulator) = match &mut *registration { SignalRegistration::Unregistered { class_handler, accumulator, } => (class_handler.take(), accumulator.take()), SignalRegistration::Registered { .. } => unreachable!(), }; let param_types = self .param_types .iter() .map(|t| t.into_glib()) .collect::>(); let class_handler = class_handler.map(|class_handler| { Closure::new(move |values| unsafe { let instance = gobject_ffi::g_value_get_object(values[0].to_glib_none().0); class_handler(&SignalClassHandlerToken(instance as *mut _), values) }) }); unsafe extern "C" fn accumulator_trampoline( ihint: *mut gobject_ffi::GSignalInvocationHint, return_accu: *mut gobject_ffi::GValue, handler_return: *const gobject_ffi::GValue, data: ffi::gpointer, ) -> ffi::gboolean { let accumulator = &**(data as *const *const (dyn Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static)); accumulator( &SignalInvocationHint(*ihint), &mut *(return_accu as *mut Value), &*(handler_return as *const Value), ) .into_glib() } let (accumulator, accumulator_trampoline) = if let Some(accumulator) = accumulator { ( Box::into_raw(Box::new(accumulator)), Some:: _>(accumulator_trampoline), ) } else { (ptr::null_mut(), None) }; unsafe { let signal_id = gobject_ffi::g_signal_newv( self.name.to_glib_none().0, type_.into_glib(), self.flags.into_glib(), class_handler.to_glib_none().0, accumulator_trampoline, accumulator as ffi::gpointer, None, self.return_type.into_glib(), param_types.len() as u32, param_types.as_ptr() as *mut _, ); *registration = SignalRegistration::Registered { type_, signal_id: SignalId::from_glib(signal_id), }; } } } glib-0.14.8/src/subclass/types.rs000064400000000000000000000730550072674642500150150ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! Module that contains the basic infrastructure for subclassing `GObject`. use crate::object::{Cast, ObjectSubclassIs, ObjectType}; use crate::translate::*; use crate::{Closure, Object, StaticType, Type, Value}; use std::marker; use std::mem; use std::ptr; use std::{any::Any, collections::HashMap}; use super::SignalId; /// A newly registered `glib::Type` that is currently still being initialized. /// /// This allows running additional type-setup functions. #[derive(Debug, PartialEq, Eq)] pub struct InitializingType(pub(crate) Type, pub(crate) marker::PhantomData<*const T>); impl IntoGlib for InitializingType { type GlibType = ffi::GType; fn into_glib(self) -> ffi::GType { self.0.into_glib() } } /// Struct used for the instance private data of the GObject. struct PrivateStruct { imp: T, instance_data: Option>>, } /// Trait implemented by structs that implement a `GObject` C instance struct. /// /// The struct must be `#[repr(C)]` and have the parent type's instance struct /// as the first field. /// /// See [`basic::InstanceStruct`] for a basic implementation of this that can /// be used most of the time and should only not be used if additional fields are /// required in the instance struct. /// /// [`basic::InstanceStruct`]: ../basic/struct.InstanceStruct.html pub unsafe trait InstanceStruct: Sized + 'static { /// Corresponding object subclass type for this instance struct. type Type: ObjectSubclass; /// Returns the implementation for from this instance struct, that /// is the implementor of [`ObjectImpl`] or subtraits. /// /// [`ObjectImpl`]: ../object/trait.ObjectImpl.html #[doc(alias = "get_impl")] fn impl_(&self) -> &Self::Type { unsafe { let data = Self::Type::type_data(); let private_offset = data.as_ref().impl_offset(); let ptr: *const u8 = self as *const _ as *const u8; let imp_ptr = ptr.offset(private_offset); let imp = imp_ptr as *const Self::Type; &*imp } } /// Returns the class struct for this specific instance. #[doc(alias = "get_class")] fn class(&self) -> &::Class { unsafe { &**(self as *const _ as *const *const ::Class) } } /// Instance specific initialization. /// /// This is automatically called during instance initialization and must call `instance_init()` /// of the parent class. fn instance_init(&mut self) { unsafe { let obj = from_glib_borrow::<_, Object>(self as *mut _ as *mut gobject_ffi::GObject); let obj = Borrowed::new(obj.into_inner().unsafe_cast()); let mut obj = InitializingObject(obj); <::ParentType as IsSubclassable>::instance_init( &mut obj, ); } } } /// Trait implemented by structs that implement a `GObject` C class struct. /// /// The struct must be `#[repr(C)]` and have the parent type's class struct /// as the first field. /// /// See [`basic::ClassStruct`] for a basic implementation of this that can /// be used most of the time and should only not be used if additional fields are /// required in the class struct, e.g. for declaring new virtual methods. /// /// [`basic::ClassStruct`]: ../basic/struct.ClassStruct.html pub unsafe trait ClassStruct: Sized + 'static { /// Corresponding object subclass type for this class struct. type Type: ObjectSubclass; /// Override the vfuncs of all parent types. /// /// This is automatically called during type initialization. fn class_init(&mut self) { unsafe { let base = &mut *(self as *mut _ as *mut crate::Class<::ParentType>); <::ParentType as IsSubclassable>::class_init( base, ); } } } /// Trait for subclassable class structs. pub unsafe trait IsSubclassable: crate::object::IsClass { /// Override the virtual methods of this class for the given subclass and do other class /// initialization. /// /// This is automatically called during type initialization and must call `class_init()` of the /// parent class. fn class_init(class: &mut crate::Class); /// Instance specific initialization. /// /// This is automatically called during instance initialization and must call `instance_init()` /// of the parent class. fn instance_init(instance: &mut InitializingObject); } /// Trait for implementable interfaces. pub unsafe trait IsImplementable: crate::object::IsInterface where ::GlibClassType: Copy, { /// Override the virtual methods of this interface for the given subclass and do other /// interface initialization. /// /// This is automatically called during type initialization. fn interface_init(iface: &mut crate::Interface); /// Instance specific initialization. /// /// This is automatically called during instance initialization. fn instance_init(_instance: &mut InitializingObject); } unsafe extern "C" fn interface_init>( iface: ffi::gpointer, _iface_data: ffi::gpointer, ) where ::GlibClassType: Copy, { let iface = &mut *(iface as *mut crate::Interface); let mut data = T::type_data(); if data.as_ref().parent_ifaces.is_none() { data.as_mut().parent_ifaces = Some(HashMap::new()); } { let copy = Box::new(*iface.as_ref()); data.as_mut() .parent_ifaces .as_mut() .unwrap() .insert(A::static_type(), Box::into_raw(copy) as ffi::gpointer); } A::interface_init(iface); } /// Trait for a type list of interfaces. pub trait InterfaceList { /// Returns the list of types and corresponding interface infos for this list. fn iface_infos() -> Vec<(ffi::GType, gobject_ffi::GInterfaceInfo)>; /// Runs `instance_init` on each of the `IsImplementable` items. fn instance_init(_instance: &mut InitializingObject); } impl InterfaceList for () { fn iface_infos() -> Vec<(ffi::GType, gobject_ffi::GInterfaceInfo)> { vec![] } fn instance_init(_instance: &mut InitializingObject) {} } impl> InterfaceList for (A,) where ::GlibClassType: Copy, { fn iface_infos() -> Vec<(ffi::GType, gobject_ffi::GInterfaceInfo)> { vec![( A::static_type().into_glib(), gobject_ffi::GInterfaceInfo { interface_init: Some(interface_init::), interface_finalize: None, interface_data: ptr::null_mut(), }, )] } fn instance_init(instance: &mut InitializingObject) { A::instance_init(instance); } } // Generates all the InterfaceList impls for interface_lists of arbitrary sizes based on a list of type // parameters like A B C. It would generate the impl then for (A, B) and (A, B, C). macro_rules! interface_list_trait( ($name1:ident, $name2: ident, $($name:ident),*) => ( interface_list_trait!(__impl $name1, $name2; $($name),*); ); (__impl $($name:ident),+; $name1:ident, $($name2:ident),*) => ( interface_list_trait_impl!($($name),+); interface_list_trait!(__impl $($name),+ , $name1; $($name2),*); ); (__impl $($name:ident),+; $name1:ident) => ( interface_list_trait_impl!($($name),+); interface_list_trait_impl!($($name),+, $name1); ); ); // Generates the impl block for InterfaceList on interface_lists or arbitrary sizes based on its // arguments. Takes a list of type parameters as parameters, e.g. A B C // and then implements the trait on (A, B, C). macro_rules! interface_list_trait_impl( ($($name:ident),+) => ( impl),+> InterfaceList for ( $($name),+ ) where $(<$name as ObjectType>::GlibClassType: Copy),+ { fn iface_infos() -> Vec<(ffi::GType, gobject_ffi::GInterfaceInfo)> { vec![ $( ( $name::static_type().into_glib(), gobject_ffi::GInterfaceInfo { interface_init: Some(interface_init::), interface_finalize: None, interface_data: ptr::null_mut(), }, ) ),+ ] } fn instance_init(instance: &mut InitializingObject) { $( $name::instance_init(instance); )+ } } ); ); interface_list_trait!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S); /// Type-specific data that is filled in during type creation. // FIXME: Once trait bounds other than `Sized` on const fn parameters are stable // the content of `TypeData` can be made private, and we can add a `const fn new` // for initialization by the `object_subclass_internal!` macro. pub struct TypeData { #[doc(hidden)] pub type_: Type, #[doc(hidden)] pub parent_class: ffi::gpointer, #[doc(hidden)] pub parent_ifaces: Option>, #[doc(hidden)] pub class_data: Option>>, #[doc(hidden)] pub private_offset: isize, #[doc(hidden)] pub private_imp_offset: isize, } unsafe impl Send for TypeData {} unsafe impl Sync for TypeData {} impl TypeData { /// Returns the type ID. #[doc(alias = "get_type")] pub fn type_(&self) -> Type { self.type_ } /// Returns a pointer to the native parent class. /// /// This is used for chaining up to the parent class' implementation /// of virtual methods. #[doc(alias = "get_parent_class")] pub fn parent_class(&self) -> ffi::gpointer { debug_assert!(!self.parent_class.is_null()); self.parent_class } /// Returns a pointer to the native parent interface struct for interface `type_`. /// /// This is used for chaining up to the parent interface's implementation /// of virtual methods. /// /// # Panics /// /// This function panics if the type to which the `TypeData` belongs does not implement the /// given interface or was not registered yet. #[doc(alias = "get_parent_interface")] pub fn parent_interface(&self) -> ffi::gpointer { match self.parent_ifaces { None => unreachable!("No parent interfaces"), Some(ref parent_ifaces) => *parent_ifaces .get(&I::static_type()) .expect("Parent interface not found"), } } /// Returns a pointer to the class implementation specific data. /// /// This is used for class implementations to store additional data. #[doc(alias = "get_class_data")] pub fn class_data(&self, type_: Type) -> Option<&T> { match self.class_data { None => None, Some(ref data) => data.get(&type_).and_then(|ptr| ptr.downcast_ref()), } } /// Gets a mutable reference of the class implementation specific data. /// /// # Safety /// /// This can only be used while the type is being initialized. #[doc(alias = "get_class_data_mut")] pub unsafe fn class_data_mut( &mut self, type_: Type, ) -> Option<&mut T> { match self.class_data { None => None, Some(ref mut data) => data.get_mut(&type_).and_then(|v| v.downcast_mut()), } } /// Sets class specific implementation data. /// /// # Safety /// /// This can only be used while the type is being initialized. /// /// # Panics /// /// If the class_data already contains a data for the specified `type_`. pub unsafe fn set_class_data(&mut self, type_: Type, data: T) { if self.class_data.is_none() { self.class_data = Some(HashMap::new()); } if let Some(ref mut class_data) = self.class_data { if class_data.get(&type_).is_some() { panic!("The class_data already contains a key for {}", type_); } class_data.insert(type_, Box::new(data)); } } /// Returns the offset of the private implementation struct in bytes relative to the beginning /// of the instance struct. #[doc(alias = "get_impl_offset")] pub fn impl_offset(&self) -> isize { self.private_offset + self.private_imp_offset } } /// Type methods required for an [`ObjectSubclass`] implementation. /// /// This is usually generated by the [`#[object_subclass]`](crate::object_subclass) attribute macro. pub unsafe trait ObjectSubclassType { /// Storage for the type-specific data used during registration. fn type_data() -> ptr::NonNull; /// Returns the `glib::Type` ID of the subclass. /// /// This will register the type with the type system on the first call. #[doc(alias = "get_type")] fn type_() -> Type; } /// The central trait for subclassing a `GObject` type. /// /// Links together the type name, parent type and the instance and /// class structs for type registration and allows subclasses to /// hook into various steps of the type registration and initialization. /// /// See [`register_type`] for registering an implementation of this trait /// with the type system. /// /// [`register_type`]: fn.register_type.html pub trait ObjectSubclass: ObjectSubclassType + Sized + 'static { /// `GObject` type name. /// /// This must be unique in the whole process. const NAME: &'static str; /// If this subclass is an abstract class or not. /// /// By default, all subclasses are non-abstract types but setting this to `true` will create an /// abstract class instead. /// /// Abstract classes can't be instantiated and require a non-abstract subclass. /// /// Optional. const ABSTRACT: bool = false; /// Wrapper around this subclass defined with `wrapper!` type Type: ObjectType + ObjectSubclassIs + FromGlibPtrFull<*mut ::GlibType> + FromGlibPtrBorrow<*mut ::GlibType> + FromGlibPtrNone<*mut ::GlibType>; /// Parent Rust type to inherit from. type ParentType: IsSubclassable + FromGlibPtrFull<*mut ::GlibType> + FromGlibPtrBorrow<*mut ::GlibType> + FromGlibPtrNone<*mut ::GlibType>; /// List of interfaces implemented by this type. type Interfaces: InterfaceList; /// The C instance struct. /// /// See [`basic::InstanceStruct`] for an basic instance struct that should be /// used in most cases. /// /// [`basic::InstanceStruct`]: ../basic/struct.InstanceStruct.html // TODO: Should default to basic::InstanceStruct once associated // type defaults are stabilized https://github.com/rust-lang/rust/issues/29661 type Instance: InstanceStruct; /// The C class struct. /// /// See [`basic::ClassStruct`] for an basic instance struct that should be /// used in most cases. /// /// [`basic::ClassStruct`]: ../basic/struct.ClassStruct.html // TODO: Should default to basic::ClassStruct once associated // type defaults are stabilized https://github.com/rust-lang/rust/issues/29661 type Class: ClassStruct; /// Additional type initialization. /// /// This is called right after the type was registered and allows /// subclasses to do additional type-specific initialization, e.g. /// for implementing `GObject` interfaces. /// /// Optional fn type_init(_type_: &mut InitializingType) {} /// Class initialization. /// /// This is called after `type_init` and before the first instance /// of the subclass is created. Subclasses can use this to do class- /// specific initialization, e.g. for registering signals on the class /// or calling class methods. /// /// Optional fn class_init(_klass: &mut Self::Class) {} /// Constructor. /// /// This is called during object instantiation before further subclasses /// are initialized, and should return a new instance of the subclass /// private struct. /// /// Optional, either implement this or `with_class()`. fn new() -> Self { unimplemented!(); } /// Constructor. /// /// This is called during object instantiation before further subclasses /// are initialized, and should return a new instance of the subclass /// private struct. /// /// Different to `new()` above it also gets the class of this type passed /// to itself for providing additional context. /// /// Optional, either implement this or `new()`. fn with_class(_klass: &Self::Class) -> Self { Self::new() } /// Performs additional instance initialization. /// /// Called just after `with_class()`. At this point the initialization has not completed yet, so /// only a limited set of operations is safe (see `InitializingObject`). fn instance_init(_obj: &InitializingObject) {} } /// Extension methods for all `ObjectSubclass` impls. pub trait ObjectSubclassExt: ObjectSubclass { /// Returns the corresponding object instance. #[doc(alias = "get_instance")] fn instance(&self) -> Self::Type; /// Returns the implementation from an instance. fn from_instance(obj: &Self::Type) -> &Self; /// Returns a pointer to the instance implementation specific data. /// /// This is used for the subclassing infrastructure to store additional instance data. #[doc(alias = "get_instance_data")] fn instance_data(&self, type_: Type) -> Option<&U>; } impl ObjectSubclassExt for T { fn instance(&self) -> Self::Type { unsafe { let data = Self::type_data(); let type_ = data.as_ref().type_(); assert!(type_.is_valid()); let offset = -data.as_ref().impl_offset(); let ptr = self as *const Self as *const u8; let ptr = ptr.offset(offset); let ptr = ptr as *mut u8 as *mut ::GlibType; // The object might just be finalized, and in that case it's unsafe to access // it and use any API on it. This can only happen from inside the Drop impl // of Self. assert_ne!((*(ptr as *mut gobject_ffi::GObject)).ref_count, 0); // Don't steal floating reference here via from_glib_none() but // preserve it if needed by reffing manually. gobject_ffi::g_object_ref(ptr as *mut gobject_ffi::GObject); from_glib_full(ptr) } } fn from_instance(obj: &Self::Type) -> &Self { unsafe { let ptr = obj.as_ptr() as *const Self::Instance; (*ptr).impl_() } } /// Returns a pointer to the instance implementation specific data. /// /// This is used for the subclassing infrastructure to store additional instance data. fn instance_data(&self, type_: Type) -> Option<&U> { unsafe { let type_data = Self::type_data(); let self_type_ = type_data.as_ref().type_(); assert!(self_type_.is_valid()); let offset = -type_data.as_ref().private_imp_offset; let ptr = self as *const Self as *const u8; let ptr = ptr.offset(offset); let ptr = ptr as *const PrivateStruct; let priv_ = &*ptr; match priv_.instance_data { None => None, Some(ref data) => data.get(&type_).and_then(|ptr| ptr.downcast_ref()), } } } } /// An object that is currently being initialized. /// /// Binding crates should use traits for adding methods to this struct. Only methods explicitly safe /// to call during `instance_init()` should be added. pub struct InitializingObject(Borrowed); impl InitializingObject { /// Returns a reference to the object. /// /// # Safety /// /// The returned object has not been completely initialized at this point. Use of the object /// should be restricted to methods that are explicitly documented to be safe to call during /// `instance_init()`. pub unsafe fn as_ref(&self) -> &T::Type { &self.0 } /// Returns a pointer to the object. /// /// # Safety /// /// The returned object has not been completely initialized at this point. Use of the object /// should be restricted to methods that are explicitly documented to be safe to call during /// `instance_init()`. pub unsafe fn as_ptr(&self) -> *mut T::Type { self.0.as_ptr() as *const T::Type as *mut T::Type } /// Sets instance specific implementation data. /// /// # Panics /// /// If the instance_data already contains a data for the specified `type_`. pub fn set_instance_data(&mut self, type_: Type, data: U) { unsafe { let type_data = T::type_data(); let self_type_ = type_data.as_ref().type_(); assert!(self_type_.is_valid()); let offset = type_data.as_ref().private_offset; let ptr = self.0.as_ptr() as *mut u8; let ptr = ptr.offset(offset); let ptr = ptr as *mut PrivateStruct; let priv_ = &mut *ptr; if priv_.instance_data.is_none() { priv_.instance_data = Some(HashMap::new()); } if let Some(ref mut instance_data) = priv_.instance_data { if instance_data.get(&type_).is_some() { panic!("The class_data already contains a key for {}", type_); } instance_data.insert(type_, Box::new(data)); } } } } unsafe extern "C" fn class_init( klass: ffi::gpointer, _klass_data: ffi::gpointer, ) { let mut data = T::type_data(); // We have to update the private struct offset once the class is actually // being initialized. let mut private_offset = data.as_ref().private_offset as i32; gobject_ffi::g_type_class_adjust_private_offset(klass, &mut private_offset); (*data.as_mut()).private_offset = private_offset as isize; // Set trampolines for the basic GObject virtual methods. { let gobject_klass = &mut *(klass as *mut gobject_ffi::GObjectClass); gobject_klass.finalize = Some(finalize::); } // And finally peek the parent class struct (containing the parent class' // implementations of virtual methods for chaining up), and call the subclass' // class initialization function. { let klass = &mut *(klass as *mut T::Class); let parent_class = gobject_ffi::g_type_class_peek_parent(klass as *mut _ as ffi::gpointer) as *mut ::GlibClassType; assert!(!parent_class.is_null()); (*data.as_mut()).parent_class = parent_class as ffi::gpointer; klass.class_init(); T::class_init(klass); } } unsafe extern "C" fn instance_init( obj: *mut gobject_ffi::GTypeInstance, klass: ffi::gpointer, ) { // Get offset to the storage of our private struct, create it // and actually store it in that place. let mut data = T::type_data(); let private_offset = (*data.as_mut()).private_offset; let ptr = obj as *mut u8; let priv_ptr = ptr.offset(private_offset); let priv_storage = priv_ptr as *mut PrivateStruct; let klass = &*(klass as *const T::Class); let imp = T::with_class(klass); ptr::write( priv_storage, PrivateStruct { imp, instance_data: None, }, ); // Any additional instance initialization. T::Instance::instance_init(&mut *(obj as *mut _)); let obj = from_glib_borrow::<_, Object>(obj.cast()); let obj = Borrowed::new(obj.into_inner().unsafe_cast()); let mut obj = InitializingObject(obj); T::Interfaces::instance_init(&mut obj); T::instance_init(&obj); } unsafe extern "C" fn finalize(obj: *mut gobject_ffi::GObject) { // Retrieve the private struct and drop it for freeing all associated memory. let mut data = T::type_data(); let private_offset = (*data.as_mut()).private_offset; let ptr = obj as *mut u8; let priv_ptr = ptr.offset(private_offset); let priv_storage = &mut *(priv_ptr as *mut PrivateStruct); ptr::drop_in_place(&mut priv_storage.imp); if let Some(instance_data) = priv_storage.instance_data.take() { drop(instance_data); } // Chain up to the parent class' finalize implementation, if any. let parent_class = &*(data.as_ref().parent_class() as *const gobject_ffi::GObjectClass); if let Some(ref func) = parent_class.finalize { func(obj); } } /// Register a `glib::Type` ID for `T`. /// /// This must be called only once and will panic on a second call. /// /// The [`object_subclass!`] macro will create a `type_()` function around this, which will /// ensure that it's only ever called once. /// /// [`object_subclass!`]: ../../macro.object_subclass.html pub fn register_type() -> Type { // GLib aligns the type private data to two gsizes, so we can't safely store any type there that // requires a bigger alignment. if mem::align_of::() > 2 * mem::size_of::() { panic!( "Alignment {} of type not supported, bigger than {}", mem::align_of::(), 2 * mem::size_of::(), ); } unsafe { use std::ffi::CString; let type_name = CString::new(T::NAME).unwrap(); if gobject_ffi::g_type_from_name(type_name.as_ptr()) != gobject_ffi::G_TYPE_INVALID { panic!( "Type {} has already been registered", type_name.to_str().unwrap() ); } let type_ = from_glib(gobject_ffi::g_type_register_static_simple( ::static_type().into_glib(), type_name.as_ptr(), mem::size_of::() as u32, Some(class_init::), mem::size_of::() as u32, Some(instance_init::), if T::ABSTRACT { gobject_ffi::G_TYPE_FLAG_ABSTRACT } else { 0 }, )); let mut data = T::type_data(); (*data.as_mut()).type_ = type_; let private_offset = gobject_ffi::g_type_add_instance_private( type_.into_glib(), mem::size_of::>(), ); (*data.as_mut()).private_offset = private_offset as isize; // Get the offset from PrivateStruct to the imp field in it. This has to go through // some hoops because Rust doesn't have an offsetof operator yet. (*data.as_mut()).private_imp_offset = { // Must not be a dangling pointer so let's create some uninitialized memory let priv_ = std::mem::MaybeUninit::>::uninit(); let ptr = priv_.as_ptr(); // FIXME: Technically UB but we'd need std::ptr::raw_const for this let imp_ptr = &(*ptr).imp as *const _ as *const u8; let ptr = ptr as *const u8; imp_ptr as isize - ptr as isize }; let iface_types = T::Interfaces::iface_infos(); for (iface_type, iface_info) in iface_types { gobject_ffi::g_type_add_interface_static(type_.into_glib(), iface_type, &iface_info); } T::type_init(&mut InitializingType::(type_, marker::PhantomData)); type_ } } pub(crate) unsafe fn signal_override_class_handler( name: &str, type_: ffi::GType, class_handler: F, ) where F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option + Send + Sync + 'static, { let class_handler = Closure::new(move |values| { let instance = gobject_ffi::g_value_get_object(values[0].to_glib_none().0); class_handler(&super::SignalClassHandlerToken(instance as *mut _), values) }); if let Some((signal_id, _)) = SignalId::parse_name(name, from_glib(type_), false) { gobject_ffi::g_signal_override_class_closure( signal_id.into_glib(), type_, class_handler.to_glib_none().0, ); } else { panic!("Signal '{}' not found", name); } } pub(crate) unsafe fn signal_chain_from_overridden( instance: *mut gobject_ffi::GTypeInstance, token: &super::SignalClassHandlerToken, values: &[Value], ) -> Option { assert_eq!(instance, token.0); let mut result = Value::uninitialized(); gobject_ffi::g_signal_chain_from_overridden( values.as_ptr() as *mut Value as *mut gobject_ffi::GValue, result.to_glib_none_mut().0, ); Some(result).filter(|r| r.type_().is_valid() && r.type_() != Type::UNIT) } glib-0.14.8/src/thread_pool.rs000064400000000000000000000144210072674642500143220ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::*; use futures_channel::oneshot; use std::future::Future; use std::ptr; #[derive(Debug)] #[doc(alias = "GThreadPool")] pub struct ThreadPool(ptr::NonNull); unsafe impl Send for ThreadPool {} unsafe impl Sync for ThreadPool {} impl ThreadPool { #[doc(alias = "g_thread_pool_new")] pub fn new_shared(max_threads: Option) -> Result { unsafe { let mut err = ptr::null_mut(); let pool = ffi::g_thread_pool_new( Some(spawn_func), ptr::null_mut(), max_threads.map(|v| v as i32).unwrap_or(-1), ffi::GFALSE, &mut err, ); if pool.is_null() { Err(from_glib_full(err)) } else { Ok(ThreadPool(ptr::NonNull::new_unchecked(pool))) } } } #[doc(alias = "g_thread_pool_new")] pub fn new_exclusive(max_threads: u32) -> Result { unsafe { let mut err = ptr::null_mut(); let pool = ffi::g_thread_pool_new( Some(spawn_func), ptr::null_mut(), max_threads as i32, ffi::GTRUE, &mut err, ); if pool.is_null() { Err(from_glib_full(err)) } else { Ok(ThreadPool(ptr::NonNull::new_unchecked(pool))) } } } #[doc(alias = "g_thread_pool_push")] pub fn push(&self, func: F) -> Result<(), crate::Error> { unsafe { let func: Box = Box::new(func); let func = Box::new(func); let mut err = ptr::null_mut(); let func = Box::into_raw(func); let ret: bool = from_glib(ffi::g_thread_pool_push( self.0.as_ptr(), func as *mut _, &mut err, )); if ret { Ok(()) } else { let _ = Box::from_raw(func); Err(from_glib_full(err)) } } } pub fn push_future T + Send + 'static>( &self, func: F, ) -> Result + Send + Sync + 'static, crate::Error> { let (sender, receiver) = oneshot::channel(); self.push(move || { let _ = sender.send(func()); })?; Ok(async move { receiver.await.expect("Dropped before executing") }) } #[doc(alias = "g_thread_pool_set_max_threads")] pub fn set_max_threads(&self, max_threads: Option) -> Result<(), crate::Error> { unsafe { let mut err = ptr::null_mut(); let ret: bool = from_glib(ffi::g_thread_pool_set_max_threads( self.0.as_ptr(), max_threads.map(|v| v as i32).unwrap_or(-1), &mut err, )); if ret { Ok(()) } else { Err(from_glib_full(err)) } } } #[doc(alias = "g_thread_pool_get_max_threads")] #[doc(alias = "get_max_threads")] pub fn max_threads(&self) -> Option { unsafe { let max_threads = ffi::g_thread_pool_get_max_threads(self.0.as_ptr()); if max_threads == -1 { None } else { Some(max_threads as u32) } } } #[doc(alias = "g_thread_pool_get_num_threads")] #[doc(alias = "get_num_threads")] pub fn num_threads(&self) -> u32 { unsafe { ffi::g_thread_pool_get_num_threads(self.0.as_ptr()) } } #[doc(alias = "g_thread_pool_unprocessed")] #[doc(alias = "get_unprocessed")] pub fn unprocessed(&self) -> u32 { unsafe { ffi::g_thread_pool_unprocessed(self.0.as_ptr()) } } #[doc(alias = "g_thread_pool_set_max_unused_threads")] pub fn set_max_unused_threads(max_threads: Option) { unsafe { ffi::g_thread_pool_set_max_unused_threads(max_threads.map(|v| v as i32).unwrap_or(-1)) } } #[doc(alias = "g_thread_pool_get_max_unused_threads")] #[doc(alias = "get_max_unused_threads")] pub fn max_unused_threads() -> Option { unsafe { let max_unused_threads = ffi::g_thread_pool_get_max_unused_threads(); if max_unused_threads == -1 { None } else { Some(max_unused_threads as u32) } } } #[doc(alias = "g_thread_pool_get_num_unused_threads")] #[doc(alias = "get_num_unused_threads")] pub fn num_unused_threads() -> u32 { unsafe { ffi::g_thread_pool_get_num_unused_threads() } } #[doc(alias = "g_thread_pool_stop_unused_threads")] pub fn stop_unused_threads() { unsafe { ffi::g_thread_pool_stop_unused_threads(); } } #[doc(alias = "g_thread_pool_set_max_idle_time")] pub fn set_max_idle_time(max_idle_time: u32) { unsafe { ffi::g_thread_pool_set_max_idle_time(max_idle_time) } } #[doc(alias = "g_thread_pool_get_max_idle_time")] #[doc(alias = "get_max_idle_time")] pub fn max_idle_time() -> u32 { unsafe { ffi::g_thread_pool_get_max_idle_time() } } } impl Drop for ThreadPool { fn drop(&mut self) { unsafe { ffi::g_thread_pool_free(self.0.as_ptr(), ffi::GFALSE, ffi::GTRUE); } } } unsafe extern "C" fn spawn_func(func: ffi::gpointer, _data: ffi::gpointer) { let func: Box> = Box::from_raw(func as *mut _); func() } #[cfg(test)] mod tests { use super::*; #[test] fn test_push() { use std::sync::mpsc; let p = ThreadPool::new_exclusive(1).unwrap(); let (sender, receiver) = mpsc::channel(); p.push(move || { sender.send(true).unwrap(); }) .unwrap(); assert_eq!(receiver.recv(), Ok(true)); } #[test] fn test_push_future() { let c = crate::MainContext::new(); let p = ThreadPool::new_shared(None).unwrap(); let fut = p.push_future(|| true).unwrap(); let res = c.block_on(fut); assert!(res); } } glib-0.14.8/src/translate.rs000064400000000000000000002432250072674642500140250ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! Translation between GLib/GLib-based FFI types and their Rust counterparts. //! //! This module allows library bindings authors to decouple type translation //! logic and use unified idioms at FFI boundaries. It also implements //! translation of GLib core data types. //! //! `FromGlib`, `from_glib` and `IntoGlib` translate simple types like `bool`. //! //! ```ignore //! pub fn set_accept_focus(&self, accept_focus: bool) { //! unsafe { gdk::ffi::gdk_window_set_accept_focus(self.pointer, accept_focus.into_glib()) } //! } //! //! pub fn get_accept_focus(&self) -> bool { //! unsafe { from_glib(gdk::ffi::gdk_window_get_accept_focus(self.pointer)) } //! } //! ``` //! //! Implementing [`OptionIntoGlib`] on a Rust type `T` allows specifying a sentinel to indicate //! a `None` value and auto-implementing [`FromGlib`] for `Option`, which would not be //! possible in dependent crates due to the [orphan rule](https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type). //! In the example below, [`IntoGlib`] is auto-implemented for `Option`. //! //! ``` //! # use glib::translate::*; //! struct SpecialU32(u32); //! impl IntoGlib for SpecialU32 { //! type GlibType = libc::c_uint; //! fn into_glib(self) -> libc::c_uint { //! self.0 as libc::c_uint //! } //! } //! impl OptionIntoGlib for SpecialU32 { //! const GLIB_NONE: Self::GlibType = 0xFFFFFF; //! } //! ``` //! //! In order to auto-implement [`FromGlib`] for `Option`, proceed as follows: //! //! ``` //! # use glib::translate::*; //! # struct SpecialU32(u32); //! # impl IntoGlib for SpecialU32 { //! # type GlibType = libc::c_uint; //! # fn into_glib(self) -> libc::c_uint { //! # self.0 as libc::c_uint //! # } //! # } //! # impl OptionIntoGlib for SpecialU32 { //! # const GLIB_NONE: Self::GlibType = 0xFFFFFF; //! # } //! impl TryFromGlib for SpecialU32 { //! type Error = GlibNoneError; //! unsafe fn try_from_glib(val: libc::c_uint) -> Result { //! if val == SpecialU32::GLIB_NONE { //! return Err(GlibNoneError); //! } //! Ok(SpecialU32(val as u32)) //! } //! } //! ``` //! //! The [`TryFromGlib`] trait can also be implemented when the Glib type range is larger than the //! target Rust type's range. In the example below, the Rust type `U32` can be built from a signed //! [`libc::c_long`], which means that the negative range is not valid. //! //! ``` //! # use std::convert::TryFrom; //! # use std::num::TryFromIntError; //! # use glib::translate::*; //! struct U32(u32); //! impl TryFromGlib for U32 { //! type Error = TryFromIntError; //! unsafe fn try_from_glib(val: libc::c_long) -> Result { //! Ok(U32(u32::try_from(val)?)) //! } //! } //! ``` //! //! Finally, you can define [`TryFromGlib`] with both `None` and `Invalid` alternatives by setting //! the associated `type Error = GlibNoneOrInvalidError` (where `I` is the `Error` type //! when the value is invalid), which results in auto-implementing [`FromGlib`] for //! `Result, I>`. //! //! `ToGlibPtr`, `FromGlibPtrNone`, `FromGlibPtrFull` and `FromGlibPtrBorrow` work on `gpointer`s //! and ensure correct ownership of values //! according to [Glib ownership transfer rules](https://gi.readthedocs.io/en/latest/annotations/giannotations.html). //! //! `FromGlibPtrNone` and `FromGlibPtrFull` //! must be called on values obtained from C, //! according to their `transfer` annotations. //! They acquire non-gobject types, //! as well as turning floating references to strong ones, //! which are the only ones properly handled by the Rust bindings. //! //! For more information about floating references, please refer to the "Floating references" section //! of [the gobject reference](https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html). //! //! ```ignore //! fn get_title(&self) -> Option { //! unsafe { //! let title = gtk::ffi::gtk_window_get_title(self.pointer); //! from_glib_none(title) //! } //! } //! fn create_bool(value: gboolean) -> Variant { //! unsafe { //! let variant = ffi::g_variant_new_boolean(value); //! // g_variant_new_boolean has `transfer none` //! from_glib_none(variant) //! } //! } //! ``` //! //! Letting the foreign library borrow pointers from the Rust side often //! requires having a temporary variable of an intermediate type (e.g. `CString`). //! A `Stash` contains the temporary storage and a pointer into it that //! is valid for the lifetime of the `Stash`. As the lifetime of the `Stash` returned //! from `to_glib_none` is at least the enclosing statement, you can avoid explicitly //! binding the stash in most cases and just take the pointer out of it: //! //! ```ignore //! pub fn set_icon_name(&self, name: &str) { //! unsafe { //! gdk::ffi::gdk_window_set_icon_name(self.pointer, name.to_glib_none().0) //! } //! } //! ``` use libc::{c_char, size_t}; use std::char; use std::cmp::{Eq, Ordering, PartialEq}; use std::collections::HashMap; use std::error::Error; use std::ffi::{CStr, CString}; use std::ffi::{OsStr, OsString}; use std::fmt; use std::mem; #[cfg(not(windows))] use std::os::unix::prelude::*; use std::path::{Path, PathBuf}; use std::ptr; /// A pointer pub trait Ptr: Copy + 'static { fn is_null(&self) -> bool; fn from(ptr: *mut X) -> Self; fn to(self) -> *mut X; } impl Ptr for *const T { #[inline] fn is_null(&self) -> bool { (*self).is_null() } #[inline] fn from(ptr: *mut X) -> *const T { ptr as *const T } #[inline] fn to(self) -> *mut X { self as *mut X } } impl Ptr for *mut T { #[inline] fn is_null(&self) -> bool { (*self).is_null() } #[inline] fn from(ptr: *mut X) -> *mut T { ptr as *mut T } #[inline] fn to(self) -> *mut X { self as *mut X } } /// Overrides pointer mutability. /// /// Use when the C API should be specifying a const pointer but doesn't. pub fn mut_override(ptr: *const T) -> *mut T { ptr as *mut T } /// Overrides pointer constness. /// /// Use when the C API need const pointer, but function with `IsA` constraint, /// that usually don't have const pointer conversion. pub fn const_override(ptr: *mut T) -> *const T { ptr as *const T } /// A trait for creating an uninitialized value. Handy for receiving outparams. pub trait Uninitialized { /// Returns an uninitialized value. unsafe fn uninitialized() -> Self; } /// Returns an uninitialized value. #[inline] pub unsafe fn uninitialized() -> T { T::uninitialized() } /// Helper type that stores temporary values used for translation. /// /// `P` is the foreign type pointer and the first element of the tuple. /// /// `T` is the Rust type that is translated. /// /// The second element of the tuple is the temporary storage defined /// by the implementation of `ToGlibPtr

for T` /// /// Say you want to pass a `*mut GdkWindowAttr` to a foreign function. The `Stash` /// will own a `GdkWindowAttr` and a `CString` that `GdkWindowAttr::title` points into. /// /// ```ignore /// impl <'a> ToGlibPtr<'a, *mut ffi::GdkWindowAttr> for WindowAttr { /// type Storage = (Box, Stash<'a, *const c_char, Option>); /// /// fn to_glib_none(&'a self) -> Stash<*mut ffi::GdkWindowAttr, WindowAttr> { /// let title = self.title.to_glib_none(); /// /// let mut attrs = Box::new(ffi::GdkWindowAttr { /// title: title.0, /// // .... /// }); /// /// Stash(&mut *attrs, (attrs, title)) /// } /// } /// ``` pub struct Stash<'a, P: Copy, T: ?Sized + ToGlibPtr<'a, P>>( pub P, pub >::Storage, ); pub struct StashMut<'a, P: Copy, T: ?Sized>(pub P, pub >::Storage) where T: ToGlibPtrMut<'a, P>; /// Wrapper around values representing borrowed C memory. /// /// This is returned by `from_glib_borrow()` and ensures that the wrapped value /// is never dropped when going out of scope. /// /// Borrowed values must never be passed by value or mutable reference to safe Rust code and must /// not leave the C scope in which they are valid. #[derive(Debug)] pub struct Borrowed(mem::ManuallyDrop); impl Borrowed { /// Creates a new borrowed value. pub fn new(val: T) -> Self { Self(mem::ManuallyDrop::new(val)) } /// Extracts the contained value. /// /// # Safety /// /// The returned value must never be dropped and instead has to be passed to `mem::forget()` or /// be directly wrapped in `mem::ManuallyDrop` or another `Borrowed` wrapper. pub unsafe fn into_inner(self) -> T { mem::ManuallyDrop::into_inner(self.0) } } impl AsRef for Borrowed { fn as_ref(&self) -> &T { &*self.0 } } impl std::ops::Deref for Borrowed { type Target = T; fn deref(&self) -> &T { &*self.0 } } /// Translate a simple type. pub trait IntoGlib { type GlibType: Copy; fn into_glib(self) -> Self::GlibType; } impl IntoGlib for bool { type GlibType = ffi::gboolean; #[inline] fn into_glib(self) -> ffi::gboolean { if self { ffi::GTRUE } else { ffi::GFALSE } } } impl IntoGlib for char { type GlibType = u32; #[inline] fn into_glib(self) -> u32 { self as u32 } } impl IntoGlib for Option { type GlibType = u32; #[inline] fn into_glib(self) -> u32 { self.as_ref().map(|&c| c as u32).unwrap_or(0) } } impl IntoGlib for Ordering { type GlibType = i32; #[inline] fn into_glib(self) -> i32 { match self { Ordering::Less => -1, Ordering::Equal => 0, Ordering::Greater => 1, } } } impl IntoGlib for Result where G: Copy, O: IntoGlib + TryFromGlib, E: IntoGlib, { type GlibType = G; #[inline] fn into_glib(self) -> Self::GlibType { match self { Ok(ok) => ok.into_glib(), Err(err) => err.into_glib(), } } } /// A Rust type `T` for which `Option` translates to the same glib type as T. pub trait OptionIntoGlib: IntoGlib { const GLIB_NONE: Self::GlibType; } impl IntoGlib for Option { type GlibType = T::GlibType; #[inline] fn into_glib(self) -> Self::GlibType { match self { Some(t) => t.into_glib(), None => T::GLIB_NONE, } } } /// Provides the default pointer type to be used in some container conversions. /// /// It's `*mut c_char` for `String`, `*mut GtkButton` for `gtk::Button`, etc. pub trait GlibPtrDefault { type GlibType: Ptr; } impl<'a, T: ?Sized + GlibPtrDefault> GlibPtrDefault for &'a T { type GlibType = ::GlibType; } /// Translate to a pointer. pub trait ToGlibPtr<'a, P: Copy> { type Storage; /// Transfer: none. /// /// The pointer in the `Stash` is only valid for the lifetime of the `Stash`. fn to_glib_none(&'a self) -> Stash<'a, P, Self>; /// Transfer: container. /// /// We transfer the container ownership to the foreign library retaining /// the elements ownership. fn to_glib_container(&'a self) -> Stash<'a, P, Self> { unimplemented!(); } /// Transfer: full. /// /// We transfer the ownership to the foreign library. fn to_glib_full(&self) -> P { unimplemented!(); } } /// /// Translate to a pointer with a mutable borrow. pub trait ToGlibPtrMut<'a, P: Copy> { type Storage; /// Transfer: none. /// /// The pointer in the `Stash` is only valid for the lifetime of the `Stash`. #[allow(clippy::wrong_self_convention)] fn to_glib_none_mut(&'a mut self) -> StashMut; } impl<'a, P: Ptr, T: ToGlibPtr<'a, P>> ToGlibPtr<'a, P> for Option { type Storage = Option<>::Storage>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, P, Option> { self.as_ref() .map_or(Stash(Ptr::from::<()>(ptr::null_mut()), None), |s| { let s = s.to_glib_none(); Stash(s.0, Some(s.1)) }) } #[inline] fn to_glib_full(&self) -> P { self.as_ref() .map_or(Ptr::from::<()>(ptr::null_mut()), ToGlibPtr::to_glib_full) } } impl<'a, 'opt: 'a, P: Ptr, T: ToGlibPtrMut<'a, P>> ToGlibPtrMut<'a, P> for Option<&'opt mut T> { type Storage = Option<>::Storage>; #[inline] fn to_glib_none_mut(&'a mut self) -> StashMut<'a, P, Option<&'opt mut T>> { self.as_mut() .map_or(StashMut(Ptr::from::<()>(ptr::null_mut()), None), |s| { let s = s.to_glib_none_mut(); StashMut(s.0, Some(s.1)) }) } } impl<'a, P: Ptr, T: ?Sized + ToGlibPtr<'a, P>> ToGlibPtr<'a, P> for &'a T { type Storage = >::Storage; #[inline] fn to_glib_none(&'a self) -> Stash<'a, P, Self> { let s = (*self).to_glib_none(); Stash(s.0, s.1) } #[inline] fn to_glib_full(&self) -> P { (*self).to_glib_full() } } impl<'a> ToGlibPtr<'a, *const c_char> for str { type Storage = CString; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> { let tmp = CString::new(self).expect("str::ToGlibPtr<*const c_char>: unexpected '\0' character"); Stash(tmp.as_ptr(), tmp) } #[inline] fn to_glib_full(&self) -> *const c_char { unsafe { ffi::g_strndup(self.as_ptr() as *const c_char, self.len() as size_t) as *const c_char } } } impl<'a> ToGlibPtr<'a, *mut c_char> for str { type Storage = CString; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> { let tmp = CString::new(self).expect("str::ToGlibPtr<*mut c_char>: unexpected '\0' character"); Stash(tmp.as_ptr() as *mut c_char, tmp) } #[inline] fn to_glib_full(&self) -> *mut c_char { unsafe { ffi::g_strndup(self.as_ptr() as *mut c_char, self.len() as size_t) } } } impl<'a> ToGlibPtr<'a, *const c_char> for String { type Storage = CString; #[inline] fn to_glib_none(&self) -> Stash<'a, *const c_char, String> { let tmp = CString::new(&self[..]) .expect("String::ToGlibPtr<*const c_char>: unexpected '\0' character"); Stash(tmp.as_ptr(), tmp) } #[inline] fn to_glib_full(&self) -> *const c_char { unsafe { ffi::g_strndup(self.as_ptr() as *const c_char, self.len() as size_t) as *const c_char } } } impl<'a> ToGlibPtr<'a, *mut c_char> for String { type Storage = CString; #[inline] fn to_glib_none(&self) -> Stash<'a, *mut c_char, String> { let tmp = CString::new(&self[..]) .expect("String::ToGlibPtr<*mut c_char>: unexpected '\0' character"); Stash(tmp.as_ptr() as *mut c_char, tmp) } #[inline] fn to_glib_full(&self) -> *mut c_char { unsafe { ffi::g_strndup(self.as_ptr() as *const c_char, self.len() as size_t) as *mut c_char } } } impl GlibPtrDefault for str { type GlibType = *mut c_char; } impl GlibPtrDefault for String { type GlibType = *mut c_char; } #[cfg(not(windows))] fn path_to_c(path: &Path) -> CString { // GLib paths on UNIX are always in the local encoding, just like in Rust // // Paths on UNIX must not contain NUL bytes, in which case the conversion // to a CString would fail. The only thing we can do then is to panic, as passing // NULL or the empty string to GLib would cause undefined behaviour. CString::new(path.as_os_str().as_bytes()).expect("Invalid path with NUL bytes") } #[cfg(windows)] fn path_to_c(path: &Path) -> CString { // GLib paths are always UTF-8 strings on Windows, while in Rust they are // WTF-8. As such, we need to convert to a UTF-8 string. This conversion can // fail, see https://simonsapin.github.io/wtf-8/#converting-wtf-8-utf-8 // // It's not clear what we're supposed to do if it fails: the path is not // representable in UTF-8 and thus can't possibly be passed to GLib. // Passing NULL or the empty string to GLib can lead to undefined behaviour, so // the only safe option seems to be to simply panic here. let path_str = path .to_str() .expect("Path can't be represented as UTF-8") .to_owned(); // On Windows, paths can have \\?\ prepended for long-path support. See // MSDN documentation about CreateFile // // We have to get rid of this and let GLib take care of all these // weirdnesses later if path_str.starts_with("\\\\?\\") { CString::new(path_str[4..].as_bytes()) } else { CString::new(path_str.as_bytes()) } .expect("Invalid path with NUL bytes") } #[cfg(not(windows))] fn os_str_to_c(s: &OsStr) -> CString { // GLib OS string (environment strings) on UNIX are always in the local encoding, // just like in Rust // // OS string on UNIX must not contain NUL bytes, in which case the conversion // to a CString would fail. The only thing we can do then is to panic, as passing // NULL or the empty string to GLib would cause undefined behaviour. CString::new(s.as_bytes()).expect("Invalid OS String with NUL bytes") } #[cfg(windows)] fn os_str_to_c(s: &OsStr) -> CString { // GLib OS string (environment strings) are always UTF-8 strings on Windows, // while in Rust they are WTF-8. As such, we need to convert to a UTF-8 string. // This conversion can fail, see https://simonsapin.github.io/wtf-8/#converting-wtf-8-utf-8 // // It's not clear what we're supposed to do if it fails: the OS string is not // representable in UTF-8 and thus can't possibly be passed to GLib. // Passing NULL or the empty string to GLib can lead to undefined behaviour, so // the only safe option seems to be to simply panic here. let os_str = s .to_str() .expect("OS String can't be represented as UTF-8") .to_owned(); CString::new(os_str.as_bytes()).expect("Invalid OS string with NUL bytes") } impl<'a> ToGlibPtr<'a, *const c_char> for Path { type Storage = CString; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> { let tmp = path_to_c(self); Stash(tmp.as_ptr(), tmp) } } impl<'a> ToGlibPtr<'a, *mut c_char> for Path { type Storage = CString; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> { let tmp = path_to_c(self); Stash(tmp.as_ptr() as *mut c_char, tmp) } } impl<'a> ToGlibPtr<'a, *const c_char> for PathBuf { type Storage = CString; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> { let tmp = path_to_c(self); Stash(tmp.as_ptr(), tmp) } } impl<'a> ToGlibPtr<'a, *mut c_char> for PathBuf { type Storage = CString; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> { let tmp = path_to_c(self); Stash(tmp.as_ptr() as *mut c_char, tmp) } } impl GlibPtrDefault for Path { type GlibType = *mut c_char; } impl GlibPtrDefault for PathBuf { type GlibType = *mut c_char; } impl<'a> ToGlibPtr<'a, *const c_char> for OsStr { type Storage = CString; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> { let tmp = os_str_to_c(self); Stash(tmp.as_ptr(), tmp) } } impl<'a> ToGlibPtr<'a, *mut c_char> for OsStr { type Storage = CString; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> { let tmp = os_str_to_c(self); Stash(tmp.as_ptr() as *mut c_char, tmp) } } impl<'a> ToGlibPtr<'a, *const c_char> for OsString { type Storage = CString; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> { let tmp = os_str_to_c(self); Stash(tmp.as_ptr(), tmp) } } impl<'a> ToGlibPtr<'a, *mut c_char> for OsString { type Storage = CString; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> { let tmp = os_str_to_c(self); Stash(tmp.as_ptr() as *mut c_char, tmp) } } impl GlibPtrDefault for OsStr { type GlibType = *mut c_char; } impl GlibPtrDefault for OsString { type GlibType = *mut c_char; } pub trait ToGlibContainerFromSlice<'a, P> where Self: Sized, { type Storage; #[allow(clippy::wrong_self_convention)] fn to_glib_none_from_slice(t: &'a [Self]) -> (P, Self::Storage); #[allow(clippy::wrong_self_convention)] fn to_glib_container_from_slice(t: &'a [Self]) -> (P, Self::Storage); #[allow(clippy::wrong_self_convention)] fn to_glib_full_from_slice(t: &[Self]) -> P; } macro_rules! impl_to_glib_container_from_slice_fundamental { ($name:ty) => { impl<'a> ToGlibContainerFromSlice<'a, *mut $name> for $name { type Storage = &'a [$name]; fn to_glib_none_from_slice(t: &'a [$name]) -> (*mut $name, &'a [$name]) { (t.as_ptr() as *mut $name, t) } fn to_glib_container_from_slice(t: &'a [$name]) -> (*mut $name, &'a [$name]) { (ToGlibContainerFromSlice::to_glib_full_from_slice(t), t) } fn to_glib_full_from_slice(t: &[$name]) -> *mut $name { if t.len() == 0 { return ptr::null_mut(); } unsafe { let res = ffi::g_malloc(mem::size_of::<$name>() * t.len()) as *mut $name; ptr::copy_nonoverlapping(t.as_ptr(), res, t.len()); res } } } }; } impl_to_glib_container_from_slice_fundamental!(u8); impl_to_glib_container_from_slice_fundamental!(i8); impl_to_glib_container_from_slice_fundamental!(u16); impl_to_glib_container_from_slice_fundamental!(i16); impl_to_glib_container_from_slice_fundamental!(u32); impl_to_glib_container_from_slice_fundamental!(i32); impl_to_glib_container_from_slice_fundamental!(u64); impl_to_glib_container_from_slice_fundamental!(i64); impl_to_glib_container_from_slice_fundamental!(f32); impl_to_glib_container_from_slice_fundamental!(f64); macro_rules! impl_to_glib_container_from_slice_string { ($name:ty, $ffi_name:ty) => { impl<'a> ToGlibContainerFromSlice<'a, *mut $ffi_name> for $name { type Storage = (Vec>, Option>); fn to_glib_none_from_slice(t: &'a [$name]) -> (*mut $ffi_name, Self::Storage) { let v: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect(); let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect(); v_ptr.push(ptr::null_mut() as $ffi_name); (v_ptr.as_ptr() as *mut $ffi_name, (v, Some(v_ptr))) } fn to_glib_container_from_slice(t: &'a [$name]) -> (*mut $ffi_name, Self::Storage) { let v: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect(); let v_ptr = unsafe { let v_ptr = ffi::g_malloc0(mem::size_of::<$ffi_name>() * (t.len() + 1)) as *mut $ffi_name; for (i, s) in v.iter().enumerate() { ptr::write(v_ptr.add(i), s.0); } v_ptr }; (v_ptr, (v, None)) } fn to_glib_full_from_slice(t: &[$name]) -> *mut $ffi_name { unsafe { let v_ptr = ffi::g_malloc0(mem::size_of::<$ffi_name>() * (t.len() + 1)) as *mut $ffi_name; for (i, s) in t.iter().enumerate() { ptr::write(v_ptr.add(i), s.to_glib_full()); } v_ptr } } } impl<'a> ToGlibContainerFromSlice<'a, *const $ffi_name> for $name { type Storage = (Vec>, Option>); fn to_glib_none_from_slice(t: &'a [$name]) -> (*const $ffi_name, Self::Storage) { let v: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect(); let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect(); v_ptr.push(ptr::null_mut() as $ffi_name); (v_ptr.as_ptr() as *const $ffi_name, (v, Some(v_ptr))) } fn to_glib_container_from_slice(t: &'a [$name]) -> (*const $ffi_name, Self::Storage) { let v: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect(); let v_ptr = unsafe { let v_ptr = ffi::g_malloc0(mem::size_of::<$ffi_name>() * (t.len() + 1)) as *mut $ffi_name; for (i, s) in v.iter().enumerate() { ptr::write(v_ptr.add(i), s.0); } v_ptr as *const $ffi_name }; (v_ptr, (v, None)) } fn to_glib_full_from_slice(t: &[$name]) -> *const $ffi_name { unsafe { let v_ptr = ffi::g_malloc0(mem::size_of::<$ffi_name>() * (t.len() + 1)) as *mut $ffi_name; for (i, s) in t.iter().enumerate() { ptr::write(v_ptr.add(i), s.to_glib_full()); } v_ptr as *const $ffi_name } } } }; } impl_to_glib_container_from_slice_string!(&'a str, *mut c_char); impl_to_glib_container_from_slice_string!(&'a str, *const c_char); impl_to_glib_container_from_slice_string!(String, *mut c_char); impl_to_glib_container_from_slice_string!(String, *const c_char); impl_to_glib_container_from_slice_string!(&'a Path, *mut c_char); impl_to_glib_container_from_slice_string!(&'a Path, *const c_char); impl_to_glib_container_from_slice_string!(PathBuf, *mut c_char); impl_to_glib_container_from_slice_string!(PathBuf, *const c_char); impl_to_glib_container_from_slice_string!(&'a OsStr, *mut c_char); impl_to_glib_container_from_slice_string!(&'a OsStr, *const c_char); impl_to_glib_container_from_slice_string!(OsString, *mut c_char); impl_to_glib_container_from_slice_string!(OsString, *const c_char); impl_to_glib_container_from_slice_string!(crate::GString, *mut c_char); impl_to_glib_container_from_slice_string!(crate::GString, *const c_char); impl<'a, T> ToGlibContainerFromSlice<'a, *mut ffi::GList> for T where T: GlibPtrDefault + ToGlibPtr<'a, ::GlibType>, { type Storage = ( Option, Vec::GlibType, T>>, ); #[inline] fn to_glib_none_from_slice(t: &'a [T]) -> (*mut ffi::GList, Self::Storage) { let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect(); let mut list: *mut ffi::GList = ptr::null_mut(); unsafe { for stash in &stash_vec { list = ffi::g_list_prepend(list, Ptr::to(stash.0)); } } (list, (Some(List(list)), stash_vec)) } #[inline] fn to_glib_container_from_slice(t: &'a [T]) -> (*mut ffi::GList, Self::Storage) { let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect(); let mut list: *mut ffi::GList = ptr::null_mut(); unsafe { for stash in &stash_vec { list = ffi::g_list_prepend(list, Ptr::to(stash.0)); } } (list, (None, stash_vec)) } #[inline] fn to_glib_full_from_slice(t: &[T]) -> *mut ffi::GList { let mut list: *mut ffi::GList = ptr::null_mut(); unsafe { for ptr in t.iter().rev().map(ToGlibPtr::to_glib_full) { list = ffi::g_list_prepend(list, Ptr::to(ptr)); } } list } } impl<'a, T> ToGlibContainerFromSlice<'a, *const ffi::GList> for T where T: GlibPtrDefault + ToGlibPtr<'a, ::GlibType>, { type Storage = ( Option, Vec::GlibType, T>>, ); #[inline] fn to_glib_none_from_slice(t: &'a [T]) -> (*const ffi::GList, Self::Storage) { let (list, stash) = ToGlibContainerFromSlice::<*mut ffi::GList>::to_glib_none_from_slice(t); (list as *const ffi::GList, stash) } #[inline] fn to_glib_container_from_slice(_t: &'a [T]) -> (*const ffi::GList, Self::Storage) { unimplemented!() } #[inline] fn to_glib_full_from_slice(_t: &[T]) -> *const ffi::GList { unimplemented!() } } #[doc(alias = "GList")] pub struct List(*mut ffi::GList); impl Drop for List { fn drop(&mut self) { unsafe { ffi::g_list_free(self.0) } } } impl<'a, T> ToGlibContainerFromSlice<'a, *mut ffi::GSList> for &'a T where T: GlibPtrDefault + ToGlibPtr<'a, ::GlibType>, { type Storage = ( Option, Vec::GlibType, &'a T>>, ); #[inline] fn to_glib_none_from_slice(t: &'a [&'a T]) -> (*mut ffi::GSList, Self::Storage) { let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect(); let mut list: *mut ffi::GSList = ptr::null_mut(); unsafe { for stash in &stash_vec { list = ffi::g_slist_prepend(list, Ptr::to(stash.0)); } } (list, (Some(SList(list)), stash_vec)) } #[inline] fn to_glib_container_from_slice(t: &'a [&'a T]) -> (*mut ffi::GSList, Self::Storage) { let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect(); let mut list: *mut ffi::GSList = ptr::null_mut(); unsafe { for stash in &stash_vec { list = ffi::g_slist_prepend(list, Ptr::to(stash.0)); } } (list, (None, stash_vec)) } #[inline] fn to_glib_full_from_slice(t: &[&'a T]) -> *mut ffi::GSList { let mut list: *mut ffi::GSList = ptr::null_mut(); unsafe { for ptr in t.iter().rev().map(ToGlibPtr::to_glib_full) { list = ffi::g_slist_prepend(list, Ptr::to(ptr)); } } list } } impl<'a, T> ToGlibContainerFromSlice<'a, *const ffi::GSList> for &'a T where T: GlibPtrDefault + ToGlibPtr<'a, ::GlibType>, { type Storage = ( Option, Vec::GlibType, &'a T>>, ); #[inline] fn to_glib_none_from_slice(t: &'a [&'a T]) -> (*const ffi::GSList, Self::Storage) { let (list, stash) = ToGlibContainerFromSlice::<*mut ffi::GSList>::to_glib_none_from_slice(t); (list as *const ffi::GSList, stash) } #[inline] fn to_glib_container_from_slice(_t: &'a [&'a T]) -> (*const ffi::GSList, Self::Storage) { unimplemented!() } #[inline] fn to_glib_full_from_slice(_t: &[&'a T]) -> *const ffi::GSList { unimplemented!() } } #[doc(alias = "GSList")] pub struct SList(*mut ffi::GSList); impl Drop for SList { fn drop(&mut self) { unsafe { ffi::g_slist_free(self.0) } } } impl<'a, P: Ptr, T: ToGlibContainerFromSlice<'a, P>> ToGlibPtr<'a, P> for [T] { type Storage = T::Storage; #[inline] fn to_glib_none(&'a self) -> Stash<'a, P, Self> { let result = ToGlibContainerFromSlice::to_glib_none_from_slice(self); Stash(result.0, result.1) } #[inline] fn to_glib_container(&'a self) -> Stash<'a, P, Self> { let result = ToGlibContainerFromSlice::to_glib_container_from_slice(self); Stash(result.0, result.1) } #[inline] fn to_glib_full(&self) -> P { ToGlibContainerFromSlice::to_glib_full_from_slice(self) } } #[allow(clippy::implicit_hasher)] impl<'a> ToGlibPtr<'a, *mut ffi::GHashTable> for HashMap { type Storage = HashTable; #[inline] fn to_glib_none(&self) -> Stash<'a, *mut ffi::GHashTable, Self> { let ptr = self.to_glib_full(); Stash(ptr, HashTable(ptr)) } #[inline] fn to_glib_full(&self) -> *mut ffi::GHashTable { unsafe { let ptr = ffi::g_hash_table_new_full( Some(ffi::g_str_hash), Some(ffi::g_str_equal), Some(ffi::g_free), Some(ffi::g_free), ); for (k, v) in self { let k: *mut c_char = k.to_glib_full(); let v: *mut c_char = v.to_glib_full(); ffi::g_hash_table_insert(ptr, k as *mut _, v as *mut _); } ptr } } } #[doc(alias = "GHashTable")] pub struct HashTable(*mut ffi::GHashTable); impl Drop for HashTable { fn drop(&mut self) { unsafe { ffi::g_hash_table_unref(self.0) } } } #[doc(alias = "GPtrArray")] pub struct PtrArray(*mut ffi::GPtrArray); impl Drop for PtrArray { fn drop(&mut self) { unsafe { ffi::g_ptr_array_unref(self.0); } } } impl<'a, T> ToGlibContainerFromSlice<'a, *mut ffi::GPtrArray> for T where T: GlibPtrDefault + ToGlibPtr<'a, ::GlibType>, { type Storage = ( Option, Vec::GlibType, T>>, ); #[inline] fn to_glib_none_from_slice(t: &'a [T]) -> (*mut ffi::GPtrArray, Self::Storage) { let stash_vec: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect(); let arr = unsafe { ffi::g_ptr_array_sized_new(t.len() as _) }; unsafe { for stash in &stash_vec { ffi::g_ptr_array_add(arr, Ptr::to(stash.0)); } } (arr, (Some(PtrArray(arr)), stash_vec)) } #[inline] fn to_glib_container_from_slice(t: &'a [T]) -> (*mut ffi::GPtrArray, Self::Storage) { let stash_vec: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect(); let arr = unsafe { ffi::g_ptr_array_sized_new(t.len() as _) }; unsafe { for stash in &stash_vec { ffi::g_ptr_array_add(arr, Ptr::to(stash.0)); } } (arr, (None, stash_vec)) } #[inline] fn to_glib_full_from_slice(t: &[T]) -> *mut ffi::GPtrArray { let arr = unsafe { ffi::g_ptr_array_sized_new(t.len() as _) }; unsafe { for ptr in t.iter().map(ToGlibPtr::to_glib_full) { ffi::g_ptr_array_add(arr, Ptr::to(ptr)); } } arr } } impl<'a, T> ToGlibContainerFromSlice<'a, *const ffi::GPtrArray> for T where T: GlibPtrDefault + ToGlibPtr<'a, ::GlibType>, { type Storage = ( Option, Vec::GlibType, T>>, ); #[inline] fn to_glib_none_from_slice(t: &'a [T]) -> (*const ffi::GPtrArray, Self::Storage) { let (arr, stash) = ToGlibContainerFromSlice::<*mut ffi::GPtrArray>::to_glib_none_from_slice(t); (arr as *const ffi::GPtrArray, stash) } #[inline] fn to_glib_container_from_slice(_t: &'a [T]) -> (*const ffi::GPtrArray, Self::Storage) { unimplemented!() } #[inline] fn to_glib_full_from_slice(_t: &[T]) -> *const ffi::GPtrArray { unimplemented!() } } /// Translate a simple type. pub trait FromGlib: Sized { unsafe fn from_glib(val: G) -> Self; } /// Translate a simple type. #[inline] pub unsafe fn from_glib>(val: G) -> T { FromGlib::from_glib(val) } impl FromGlib for bool { #[inline] unsafe fn from_glib(val: ffi::gboolean) -> Self { val != ffi::GFALSE } } impl FromGlib for Ordering { #[inline] unsafe fn from_glib(val: i32) -> Self { val.cmp(&0) } } /// Translate from a Glib type which can result in an undefined and/or invalid value. pub trait TryFromGlib: Sized { type Error; unsafe fn try_from_glib(val: G) -> Result; } /// Translate from a Glib type which can result in an undefined and/or invalid value. #[inline] pub unsafe fn try_from_glib>( val: G, ) -> Result>::Error> { TryFromGlib::try_from_glib(val) } /// Error type for [`TryFromGlib`] when the Glib value is None. #[derive(Debug, PartialEq, Eq)] pub struct GlibNoneError; impl fmt::Display for GlibNoneError { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "glib value is None") } } impl std::error::Error for GlibNoneError {} impl> FromGlib for Option { #[inline] unsafe fn from_glib(val: G) -> Self { T::try_from_glib(val).ok() } } /// Error type for [`TryFromGlib`] when the Glib value can be None or invalid. #[derive(Debug, Eq, PartialEq)] pub enum GlibNoneOrInvalidError { Invalid(I), None, } impl GlibNoneOrInvalidError { /// Builds the `None` variant. pub fn none() -> Self { Self::None } /// Returns `true` if `self` is the `None` variant. pub fn is_none(&self) -> bool { matches!(self, Self::None) } /// Returns `true` if `self` is the `Invalid` variant. pub fn is_invalid(&self) -> bool { matches!(self, Self::Invalid(_)) } } impl From for GlibNoneOrInvalidError { fn from(invalid: I) -> Self { Self::Invalid(invalid) } } impl fmt::Display for GlibNoneOrInvalidError { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Invalid(err) => { write!(fmt, "glib value is invalid: ")?; fmt::Display::fmt(err, fmt) } Self::None => write!(fmt, "glib value is None"), } } } impl Error for GlibNoneOrInvalidError {} impl>> FromGlib for Result, I> { #[inline] unsafe fn from_glib(val: G) -> Self { match T::try_from_glib(val) { Ok(value) => Ok(Some(value)), Err(GlibNoneOrInvalidError::None) => Ok(None), Err(GlibNoneOrInvalidError::Invalid(err)) => Err(err), } } } /// Translate from a pointer type which is annotated with `transfer none`. /// The resulting value is referenced at least once, by the bindings. /// /// This is suitable for floating references, which become strong references. /// It is also suitable for acquiring non-gobject values, like `gchar*`. /// /// /// # Safety /// /// The implementation of this trait should acquire a reference to the value /// in a way appropriate to the type, /// e.g. by increasing the reference count or copying. /// Values obtained using this trait must be properly released on `drop()` /// by the implementing type. /// /// For more information, refer to module level documentation. pub trait FromGlibPtrNone: Sized { /// # Safety /// /// See trait level [notes on safety](#safety_points) unsafe fn from_glib_none(ptr: P) -> Self; } /// Translate from a pointer type which is annotated with `transfer full`. /// This transfers the ownership of the value to the Rust side. /// /// Because ownership can only be transferred if something is already referenced, /// this is unsuitable for floating references. /// /// /// # Safety /// /// The implementation of this trait should not alter the reference count /// or make copies of the underlying value. /// Values obtained using this trait must be properly released on `drop()` /// by the implementing type. /// /// For more information, refer to module level documentation. pub trait FromGlibPtrFull: Sized { /// # Safety /// /// See trait level [notes on safety](#safety_points) unsafe fn from_glib_full(ptr: P) -> Self; } /// Translate from a pointer type by borrowing, without affecting the refcount. /// /// The purpose of this trait is to access values inside callbacks /// without changing their reference status. /// The obtained borrow must not be accessed outside of the scope of the callback, /// and called procedures must not store any references to the underlying data. /// Safe Rust code must never obtain a mutable Rust reference. /// /// /// # Safety /// /// The implementation of this trait as well as the returned type /// must satisfy the same constraints together. /// They must not take ownership of the underlying value, copy it, /// and should not change its reference count. /// If it does, it must properly release obtained references. /// /// The returned value, when dropped, /// must leave the underlying value in the same state /// as before from_glib_borrow was called: /// - it must not be dropped, /// - it must be the same type of reference, e.g. still floating. /// /// For more information, refer to module level documentation. pub trait FromGlibPtrBorrow: Sized { /// # Safety /// /// See trait level [notes on safety](#safety_points) unsafe fn from_glib_borrow(_ptr: P) -> Borrowed { unimplemented!(); } } /// Translate from a pointer type, transfer: none. /// /// See [`FromGlibPtrNone`](trait.FromGlibPtrNone.html). #[inline] pub unsafe fn from_glib_none>(ptr: P) -> T { FromGlibPtrNone::from_glib_none(ptr) } /// Translate from a pointer type, transfer: full (assume ownership). /// /// See [`FromGlibPtrFull`](trait.FromGlibPtrFull.html). #[inline] pub unsafe fn from_glib_full>(ptr: P) -> T { FromGlibPtrFull::from_glib_full(ptr) } /// Translate from a pointer type, borrowing the pointer. /// /// See [`FromGlibPtrBorrow`](trait.FromGlibPtrBorrow.html). #[inline] pub unsafe fn from_glib_borrow>(ptr: P) -> Borrowed { FromGlibPtrBorrow::from_glib_borrow(ptr) } impl> FromGlibPtrNone

for Option { #[inline] unsafe fn from_glib_none(ptr: P) -> Option { if ptr.is_null() { None } else { Some(from_glib_none(ptr)) } } } impl> FromGlibPtrBorrow

for Option { #[inline] unsafe fn from_glib_borrow(ptr: P) -> Borrowed> { if ptr.is_null() { Borrowed::new(None) } else { let val = T::from_glib_borrow(ptr); Borrowed::new(Some(val.into_inner())) } } } impl> FromGlibPtrFull

for Option { #[inline] unsafe fn from_glib_full(ptr: P) -> Option { if ptr.is_null() { None } else { Some(from_glib_full(ptr)) } } } impl FromGlibPtrNone<*const c_char> for String { #[inline] unsafe fn from_glib_none(ptr: *const c_char) -> Self { assert!(!ptr.is_null()); Self::from_utf8_lossy(CStr::from_ptr(ptr).to_bytes()).into_owned() } } // TODO: Deprecate this impl FromGlibPtrFull<*const c_char> for String { #[inline] unsafe fn from_glib_full(ptr: *const c_char) -> Self { let res = from_glib_none(ptr); ffi::g_free(ptr as *mut _); res } } // TODO: Deprecate this impl FromGlibPtrNone<*mut c_char> for String { #[inline] unsafe fn from_glib_none(ptr: *mut c_char) -> Self { assert!(!ptr.is_null()); Self::from_utf8_lossy(CStr::from_ptr(ptr).to_bytes()).into_owned() } } // TODO: Deprecate this impl FromGlibPtrFull<*mut c_char> for String { #[inline] unsafe fn from_glib_full(ptr: *mut c_char) -> Self { let res = from_glib_none(ptr); ffi::g_free(ptr as *mut _); res } } #[cfg(not(windows))] unsafe fn c_to_path_buf(ptr: *const c_char) -> PathBuf { assert!(!ptr.is_null()); // GLib paths on UNIX are always in the local encoding, which can be // UTF-8 or anything else really, but is always a NUL-terminated string // and must not contain any other NUL bytes OsString::from_vec(CStr::from_ptr(ptr).to_bytes().to_vec()).into() } #[cfg(windows)] unsafe fn c_to_path_buf(ptr: *const c_char) -> PathBuf { assert!(!ptr.is_null()); // GLib paths on Windows are always UTF-8, as such we can convert to a String // first and then go to a PathBuf from there. Unless there is a bug // in the C library, the conversion from UTF-8 can never fail so we can // safely panic here if that ever happens String::from_utf8(CStr::from_ptr(ptr).to_bytes().into()) .expect("Invalid, non-UTF8 path") .into() } #[cfg(not(windows))] unsafe fn c_to_os_string(ptr: *const c_char) -> OsString { assert!(!ptr.is_null()); // GLib OS string (environment strings) on UNIX are always in the local encoding, // which can be UTF-8 or anything else really, but is always a NUL-terminated string // and must not contain any other NUL bytes OsString::from_vec(CStr::from_ptr(ptr).to_bytes().to_vec()) } #[cfg(windows)] unsafe fn c_to_os_string(ptr: *const c_char) -> OsString { assert!(!ptr.is_null()); // GLib OS string (environment strings) on Windows are always UTF-8, // as such we can convert to a String // first and then go to a OsString from there. Unless there is a bug // in the C library, the conversion from UTF-8 can never fail so we can // safely panic here if that ever happens String::from_utf8(CStr::from_ptr(ptr).to_bytes().into()) .expect("Invalid, non-UTF8 path") .into() } impl FromGlibPtrNone<*const c_char> for PathBuf { #[inline] unsafe fn from_glib_none(ptr: *const c_char) -> Self { assert!(!ptr.is_null()); c_to_path_buf(ptr) } } impl FromGlibPtrFull<*const c_char> for PathBuf { #[inline] unsafe fn from_glib_full(ptr: *const c_char) -> Self { let res = from_glib_none(ptr); ffi::g_free(ptr as *mut _); res } } impl FromGlibPtrNone<*mut c_char> for PathBuf { #[inline] unsafe fn from_glib_none(ptr: *mut c_char) -> Self { assert!(!ptr.is_null()); c_to_path_buf(ptr) } } impl FromGlibPtrFull<*mut c_char> for PathBuf { #[inline] unsafe fn from_glib_full(ptr: *mut c_char) -> Self { let res = from_glib_none(ptr); ffi::g_free(ptr as *mut _); res } } impl FromGlibPtrNone<*const c_char> for OsString { #[inline] unsafe fn from_glib_none(ptr: *const c_char) -> Self { assert!(!ptr.is_null()); c_to_os_string(ptr) } } impl FromGlibPtrFull<*const c_char> for OsString { #[inline] unsafe fn from_glib_full(ptr: *const c_char) -> Self { let res = from_glib_none(ptr); ffi::g_free(ptr as *mut _); res } } impl FromGlibPtrNone<*mut c_char> for OsString { #[inline] unsafe fn from_glib_none(ptr: *mut c_char) -> Self { assert!(!ptr.is_null()); c_to_os_string(ptr) } } impl FromGlibPtrFull<*mut c_char> for OsString { #[inline] unsafe fn from_glib_full(ptr: *mut c_char) -> Self { let res = from_glib_none(ptr); ffi::g_free(ptr as *mut _); res } } /// Translate from a container. pub trait FromGlibContainer: Sized { /// Transfer: none. /// /// `num` is the advised number of elements. unsafe fn from_glib_none_num(ptr: P, num: usize) -> Self; /// Transfer: container. /// /// `num` is the advised number of elements. unsafe fn from_glib_container_num(ptr: P, num: usize) -> Self; /// Transfer: full. /// /// `num` is the advised number of elements. unsafe fn from_glib_full_num(ptr: P, num: usize) -> Self; } /// Translate from a container of pointers. pub trait FromGlibPtrContainer: FromGlibContainer + Sized { /// Transfer: none. unsafe fn from_glib_none(ptr: PP) -> Self; /// Transfer: container. unsafe fn from_glib_container(ptr: PP) -> Self; /// Transfer: full. unsafe fn from_glib_full(ptr: PP) -> Self; } pub unsafe fn c_ptr_array_len(mut ptr: *const P) -> usize { let mut len = 0; if !ptr.is_null() { while !(*ptr).is_null() { len += 1; ptr = ptr.offset(1); } } len } pub trait FromGlibContainerAsVec where Self: Sized, { unsafe fn from_glib_none_num_as_vec(ptr: P, num: usize) -> Vec; unsafe fn from_glib_container_num_as_vec(ptr: P, num: usize) -> Vec; unsafe fn from_glib_full_num_as_vec(ptr: P, num: usize) -> Vec; } pub trait FromGlibPtrArrayContainerAsVec: FromGlibContainerAsVec where Self: Sized, { unsafe fn from_glib_none_as_vec(ptr: PP) -> Vec; unsafe fn from_glib_container_as_vec(ptr: PP) -> Vec; unsafe fn from_glib_full_as_vec(ptr: PP) -> Vec; } impl FromGlibContainerAsVec for bool { unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::gboolean, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for i in 0..num { res.push(from_glib(ptr::read(ptr.add(i)))); } res } unsafe fn from_glib_container_num_as_vec(_: *const ffi::gboolean, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } unsafe fn from_glib_full_num_as_vec(_: *const ffi::gboolean, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } } impl FromGlibContainerAsVec for bool { unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::gboolean, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num) } unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::gboolean, num: usize) -> Vec { let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut ffi::gboolean, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num) } } macro_rules! impl_from_glib_container_as_vec_fundamental { ($name:ty) => { impl FromGlibContainerAsVec<$name, *const $name> for $name { unsafe fn from_glib_none_num_as_vec(ptr: *const $name, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for i in 0..num { res.push(ptr::read(ptr.add(i))); } res } unsafe fn from_glib_container_num_as_vec(_: *const $name, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } unsafe fn from_glib_full_num_as_vec(_: *const $name, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } } impl FromGlibContainerAsVec<$name, *mut $name> for $name { unsafe fn from_glib_none_num_as_vec(ptr: *mut $name, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num) } unsafe fn from_glib_container_num_as_vec(ptr: *mut $name, num: usize) -> Vec { let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut $name, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num) } } }; } impl_from_glib_container_as_vec_fundamental!(u8); impl_from_glib_container_as_vec_fundamental!(i8); impl_from_glib_container_as_vec_fundamental!(u16); impl_from_glib_container_as_vec_fundamental!(i16); impl_from_glib_container_as_vec_fundamental!(u32); impl_from_glib_container_as_vec_fundamental!(i32); impl_from_glib_container_as_vec_fundamental!(u64); impl_from_glib_container_as_vec_fundamental!(i64); impl_from_glib_container_as_vec_fundamental!(f32); impl_from_glib_container_as_vec_fundamental!(f64); macro_rules! impl_from_glib_container_as_vec_string { ($name:ty, $ffi_name:ty) => { impl FromGlibContainerAsVec<$ffi_name, *const $ffi_name> for $name { unsafe fn from_glib_none_num_as_vec(ptr: *const $ffi_name, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for i in 0..num { res.push(from_glib_none(ptr::read(ptr.add(i)) as $ffi_name)); } res } unsafe fn from_glib_container_num_as_vec(_: *const $ffi_name, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } unsafe fn from_glib_full_num_as_vec(_: *const $ffi_name, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } } impl FromGlibContainerAsVec<$ffi_name, *mut $ffi_name> for $name { unsafe fn from_glib_none_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num) } unsafe fn from_glib_container_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec { let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for i in 0..num { res.push(from_glib_full(ptr::read(ptr.add(i)))); } ffi::g_free(ptr as *mut _); res } } impl FromGlibPtrArrayContainerAsVec<$ffi_name, *mut $ffi_name> for $name { unsafe fn from_glib_none_as_vec(ptr: *mut $ffi_name) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr)) } unsafe fn from_glib_container_as_vec(ptr: *mut $ffi_name) -> Vec { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, c_ptr_array_len(ptr)) } unsafe fn from_glib_full_as_vec(ptr: *mut $ffi_name) -> Vec { FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr)) } } impl FromGlibPtrArrayContainerAsVec<$ffi_name, *const $ffi_name> for $name { unsafe fn from_glib_none_as_vec(ptr: *const $ffi_name) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr)) } unsafe fn from_glib_container_as_vec(ptr: *const $ffi_name) -> Vec { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, c_ptr_array_len(ptr)) } unsafe fn from_glib_full_as_vec(ptr: *const $ffi_name) -> Vec { FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr)) } } }; } // TODO: Deprecate this impl_from_glib_container_as_vec_string!(String, *const c_char); impl_from_glib_container_as_vec_string!(String, *mut c_char); impl_from_glib_container_as_vec_string!(PathBuf, *const c_char); impl_from_glib_container_as_vec_string!(PathBuf, *mut c_char); impl_from_glib_container_as_vec_string!(OsString, *const c_char); impl_from_glib_container_as_vec_string!(OsString, *mut c_char); impl> FromGlibContainer for Vec { unsafe fn from_glib_none_num(ptr: PP, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num) } unsafe fn from_glib_container_num(ptr: PP, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num) } unsafe fn from_glib_full_num(ptr: PP, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, num) } } impl> FromGlibPtrContainer for Vec { unsafe fn from_glib_none(ptr: PP) -> Vec { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr) } unsafe fn from_glib_container(ptr: PP) -> Vec { FromGlibPtrArrayContainerAsVec::from_glib_container_as_vec(ptr) } unsafe fn from_glib_full(ptr: PP) -> Vec { FromGlibPtrArrayContainerAsVec::from_glib_full_as_vec(ptr) } } impl FromGlibContainerAsVec<::GlibType, *mut ffi::GSList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_num_as_vec(mut ptr: *mut ffi::GSList, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for _ in 0..num { if ptr.is_null() { break; } let item_ptr: ::GlibType = Ptr::from((*ptr).data); if !item_ptr.is_null() { res.push(from_glib_none(item_ptr)); } ptr = (*ptr).next; } res } unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GSList, num: usize) -> Vec { let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); ffi::g_slist_free(ptr); res } unsafe fn from_glib_full_num_as_vec(mut ptr: *mut ffi::GSList, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let orig_ptr = ptr; let mut res = Vec::with_capacity(num); for _ in 0..num { if ptr.is_null() { break; } let item_ptr: ::GlibType = Ptr::from((*ptr).data); if !item_ptr.is_null() { res.push(from_glib_full(item_ptr)); } ptr = (*ptr).next; } ffi::g_slist_free(orig_ptr); res } } impl FromGlibPtrArrayContainerAsVec<::GlibType, *mut ffi::GSList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_as_vec(mut ptr: *mut ffi::GSList) -> Vec { let mut res = Vec::new(); while !ptr.is_null() { let item_ptr: ::GlibType = Ptr::from((*ptr).data); if !item_ptr.is_null() { res.push(from_glib_none(item_ptr)); } ptr = (*ptr).next; } res } unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GSList) -> Vec { let res = FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr); ffi::g_slist_free(ptr); res } unsafe fn from_glib_full_as_vec(mut ptr: *mut ffi::GSList) -> Vec { let orig_ptr = ptr; let mut res = Vec::new(); while !ptr.is_null() { let item_ptr: ::GlibType = Ptr::from((*ptr).data); if !item_ptr.is_null() { res.push(from_glib_full(item_ptr)); } ptr = (*ptr).next; } ffi::g_slist_free(orig_ptr); res } } impl FromGlibContainerAsVec<::GlibType, *mut ffi::GList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_num_as_vec(mut ptr: *mut ffi::GList, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for _ in 0..num { if ptr.is_null() { break; } let item_ptr: ::GlibType = Ptr::from((*ptr).data); if !item_ptr.is_null() { res.push(from_glib_none(item_ptr)); } ptr = (*ptr).next; } res } unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GList, num: usize) -> Vec { let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); ffi::g_list_free(ptr); res } unsafe fn from_glib_full_num_as_vec(mut ptr: *mut ffi::GList, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let orig_ptr = ptr; let mut res = Vec::with_capacity(num); for _ in 0..num { if ptr.is_null() { break; } let item_ptr: ::GlibType = Ptr::from((*ptr).data); if !item_ptr.is_null() { res.push(from_glib_full(item_ptr)); } ptr = (*ptr).next; } ffi::g_list_free(orig_ptr); res } } impl FromGlibPtrArrayContainerAsVec<::GlibType, *mut ffi::GList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_as_vec(mut ptr: *mut ffi::GList) -> Vec { let mut res = Vec::new(); while !ptr.is_null() { let item_ptr: ::GlibType = Ptr::from((*ptr).data); if !item_ptr.is_null() { res.push(from_glib_none(item_ptr)); } ptr = (*ptr).next; } res } unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GList) -> Vec { let res = FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr); ffi::g_list_free(ptr); res } unsafe fn from_glib_full_as_vec(mut ptr: *mut ffi::GList) -> Vec { let orig_ptr = ptr; let mut res = Vec::new(); while !ptr.is_null() { let item_ptr: ::GlibType = Ptr::from((*ptr).data); if !item_ptr.is_null() { res.push(from_glib_full(item_ptr)); } ptr = (*ptr).next; } ffi::g_list_free(orig_ptr); res } } impl FromGlibContainerAsVec<::GlibType, *const ffi::GList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GList, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(mut_override(ptr), num) } unsafe fn from_glib_container_num_as_vec(_: *const ffi::GList, _: usize) -> Vec { // Can't really free a *const unimplemented!() } unsafe fn from_glib_full_num_as_vec(_: *const ffi::GList, _: usize) -> Vec { // Can't really free a *const unimplemented!() } } impl FromGlibPtrArrayContainerAsVec<::GlibType, *const ffi::GList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_as_vec(ptr: *const ffi::GList) -> Vec { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(mut_override(ptr)) } unsafe fn from_glib_container_as_vec(_: *const ffi::GList) -> Vec { // Can't really free a *const unimplemented!() } unsafe fn from_glib_full_as_vec(_: *const ffi::GList) -> Vec { // Can't really free a *const unimplemented!() } } impl FromGlibContainerAsVec<::GlibType, *const ffi::GSList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GSList, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(mut_override(ptr), num) } unsafe fn from_glib_container_num_as_vec(_: *const ffi::GSList, _: usize) -> Vec { // Can't really free a *const unimplemented!() } unsafe fn from_glib_full_num_as_vec(_: *const ffi::GSList, _: usize) -> Vec { // Can't really free a *const unimplemented!() } } impl FromGlibPtrArrayContainerAsVec<::GlibType, *const ffi::GSList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_as_vec(ptr: *const ffi::GSList) -> Vec { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(mut_override(ptr)) } unsafe fn from_glib_container_as_vec(_: *const ffi::GSList) -> Vec { // Can't really free a *const unimplemented!() } unsafe fn from_glib_full_as_vec(_: *const ffi::GSList) -> Vec { // Can't really free a *const unimplemented!() } } #[allow(clippy::implicit_hasher)] impl FromGlibContainer<*const c_char, *mut ffi::GHashTable> for HashMap { unsafe fn from_glib_none_num(ptr: *mut ffi::GHashTable, _: usize) -> Self { FromGlibPtrContainer::from_glib_none(ptr) } unsafe fn from_glib_container_num(ptr: *mut ffi::GHashTable, _: usize) -> Self { FromGlibPtrContainer::from_glib_full(ptr) } unsafe fn from_glib_full_num(ptr: *mut ffi::GHashTable, _: usize) -> Self { FromGlibPtrContainer::from_glib_full(ptr) } } #[allow(clippy::implicit_hasher)] impl FromGlibPtrContainer<*const c_char, *mut ffi::GHashTable> for HashMap { unsafe fn from_glib_none(ptr: *mut ffi::GHashTable) -> Self { unsafe extern "C" fn read_string_hash_table( key: ffi::gpointer, value: ffi::gpointer, hash_map: ffi::gpointer, ) { let key: String = from_glib_none(key as *const c_char); let value: String = from_glib_none(value as *const c_char); let hash_map: &mut HashMap = &mut *(hash_map as *mut HashMap); hash_map.insert(key, value); } let mut map = HashMap::new(); ffi::g_hash_table_foreach( ptr, Some(read_string_hash_table), &mut map as *mut HashMap as *mut _, ); map } unsafe fn from_glib_container(ptr: *mut ffi::GHashTable) -> Self { FromGlibPtrContainer::from_glib_full(ptr) } unsafe fn from_glib_full(ptr: *mut ffi::GHashTable) -> Self { let map = FromGlibPtrContainer::from_glib_none(ptr); ffi::g_hash_table_unref(ptr); map } } impl FromGlibContainerAsVec<::GlibType, *mut ffi::GPtrArray> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::GPtrArray, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let pdata = (*ptr).pdata; assert!((*ptr).len as usize >= num); let mut res = Vec::with_capacity(num); for i in 0..num { let item_ptr: ::GlibType = Ptr::from(ptr::read(pdata.add(i))); if !item_ptr.is_null() { res.push(from_glib_none(item_ptr)); } } res } unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GPtrArray, num: usize) -> Vec { let res = FromGlibContainer::from_glib_none_num(ptr, num); if !ptr.is_null() { ffi::g_ptr_array_unref(ptr); } res } unsafe fn from_glib_full_num_as_vec(ptr: *mut ffi::GPtrArray, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let pdata = (*ptr).pdata; assert!((*ptr).len as usize >= num); let mut res = Vec::with_capacity(num); for i in 0..num { let item_ptr: ::GlibType = Ptr::from(ptr::read(pdata.add(i))); if !item_ptr.is_null() { res.push(from_glib_none(item_ptr)); } } ffi::g_ptr_array_unref(ptr); res } } impl FromGlibPtrArrayContainerAsVec<::GlibType, *mut ffi::GPtrArray> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_as_vec(ptr: *mut ffi::GPtrArray) -> Vec { let num = (*ptr).len as usize; FromGlibContainer::from_glib_none_num(ptr, num) } unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GPtrArray) -> Vec { let num = (*ptr).len as usize; FromGlibContainer::from_glib_container_num(ptr, num) } unsafe fn from_glib_full_as_vec(ptr: *mut ffi::GPtrArray) -> Vec { let num = (*ptr).len as usize; FromGlibContainer::from_glib_full_num(ptr, num) } } impl FromGlibContainerAsVec<::GlibType, *const ffi::GPtrArray> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GPtrArray, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(mut_override(ptr), num) } unsafe fn from_glib_container_num_as_vec(_: *const ffi::GPtrArray, _: usize) -> Vec { // Can't really free a *const unimplemented!() } unsafe fn from_glib_full_num_as_vec(_: *const ffi::GPtrArray, _: usize) -> Vec { // Can't really free a *const unimplemented!() } } impl FromGlibPtrArrayContainerAsVec<::GlibType, *const ffi::GPtrArray> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_as_vec(ptr: *const ffi::GPtrArray) -> Vec { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(mut_override(ptr)) } unsafe fn from_glib_container_as_vec(_: *const ffi::GPtrArray) -> Vec { // Can't really free a *const unimplemented!() } unsafe fn from_glib_full_as_vec(_: *const ffi::GPtrArray) -> Vec { // Can't really free a *const unimplemented!() } } #[cfg(test)] mod tests { use std::fs; use tempfile::tempdir; use super::*; use crate::GString; use std::collections::HashMap; #[test] fn boolean() { assert_eq!(true.into_glib(), ffi::GTRUE); assert_eq!(false.into_glib(), ffi::GFALSE); assert!(unsafe { bool::from_glib(ffi::GTRUE) }); assert!(!unsafe { bool::from_glib(ffi::GFALSE) }); assert!(unsafe { bool::from_glib(42) }); } #[test] fn ordering() { assert_eq!(Ordering::Less.into_glib(), -1); assert_eq!(Ordering::Equal.into_glib(), 0); assert_eq!(Ordering::Greater.into_glib(), 1); assert_eq!(Ordering::Less, unsafe { Ordering::from_glib(-42) }); assert_eq!(Ordering::Less, unsafe { Ordering::from_glib(-1) }); assert_eq!(Ordering::Equal, unsafe { Ordering::from_glib(0) }); assert_eq!(Ordering::Greater, unsafe { Ordering::from_glib(1) }); assert_eq!(Ordering::Greater, unsafe { Ordering::from_glib(42) }); } #[test] fn string() { let s = "ABC"; let owned = "ABC".to_string(); let cstring = CString::new("ABC").unwrap(); let stash = s.to_glib_none(); assert_eq!(unsafe { CStr::from_ptr(stash.0) }, cstring.as_c_str()); let stash = owned.to_glib_none(); assert_eq!(unsafe { CStr::from_ptr(stash.0) }, cstring.as_c_str()); let ptr: *mut c_char = s.to_glib_full(); assert_eq!(unsafe { CStr::from_ptr(ptr) }, cstring.as_c_str()); unsafe { ffi::g_free(ptr as *mut _); } let ptr: *mut c_char = owned.to_glib_full(); assert_eq!(unsafe { CStr::from_ptr(ptr) }, cstring.as_c_str()); assert_eq!(s, unsafe { String::from_glib_none(ptr) }); assert_eq!(owned, unsafe { String::from_glib_full(ptr) }); } #[test] fn string_hash_map() { let mut map = HashMap::new(); map.insert("A".into(), "1".into()); map.insert("B".into(), "2".into()); map.insert("C".into(), "3".into()); let ptr: *mut ffi::GHashTable = map.to_glib_full(); let map = unsafe { HashMap::from_glib_full(ptr) }; assert_eq!(map.get("A"), Some(&"1".into())); assert_eq!(map.get("B"), Some(&"2".into())); assert_eq!(map.get("C"), Some(&"3".into())); } #[test] fn string_array() { let v = vec!["A".to_string(), "B".to_string(), "C".to_string()]; let stash = v.to_glib_none(); let ptr: *mut *mut c_char = stash.0; let ptr_copy = unsafe { ffi::g_strdupv(ptr) }; let actual: Vec = unsafe { FromGlibPtrContainer::from_glib_full(ptr_copy) }; assert_eq!(v, actual); } #[test] fn gstring_array() { let v = vec!["A".to_string(), "B".to_string(), "C".to_string()]; let stash = v.to_glib_none(); let ptr: *mut *mut c_char = stash.0; let ptr_copy = unsafe { ffi::g_strdupv(ptr) }; let actual: Vec = unsafe { FromGlibPtrContainer::from_glib_full(ptr_copy) }; assert_eq!(v, actual); } #[test] fn ptr_array() { let strings = &["A", "B", "C"]; let (ptr, _stash) = ToGlibContainerFromSlice::<*mut ffi::GPtrArray>::to_glib_none_from_slice(strings); let v: Vec = unsafe { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr) }; assert_eq!(&v, strings); } #[test] #[cfg(not(target_os = "macos"))] fn test_paths() { let tmp_dir = tempdir().unwrap(); // Test if passing paths to GLib and getting them back // gives us useful results let dir_1 = tmp_dir.path().join("abcd"); fs::create_dir(&dir_1).unwrap(); assert_eq!(crate::path_get_basename(&dir_1), Path::new("abcd")); assert_eq!( crate::path_get_basename(dir_1.canonicalize().unwrap()), Path::new("abcd") ); // This currently fails on Windows because C:\\Users\\runneradmin // gets shortened to C:\\Users\\RUNNER~1 #[cfg(not(windows))] assert_eq!( crate::path_get_dirname(dir_1.canonicalize().unwrap()), tmp_dir.path() ); assert!(crate::file_test( &dir_1, crate::FileTest::EXISTS | crate::FileTest::IS_DIR )); assert!(crate::file_test( &dir_1.canonicalize().unwrap(), crate::FileTest::EXISTS | crate::FileTest::IS_DIR )); // And test with some non-ASCII characters let dir_2 = tmp_dir.as_ref().join("øäöü"); fs::create_dir(&dir_2).unwrap(); assert_eq!(crate::path_get_basename(&dir_2), Path::new("øäöü")); assert_eq!( crate::path_get_basename(dir_2.canonicalize().unwrap()), Path::new("øäöü") ); // This currently fails on Windows because C:\\Users\\runneradmin // gets shortened to C:\\Users\\RUNNER~1 #[cfg(not(windows))] assert_eq!( crate::path_get_dirname(dir_2.canonicalize().unwrap()), tmp_dir.path() ); assert!(crate::file_test( &dir_2, crate::FileTest::EXISTS | crate::FileTest::IS_DIR )); assert!(crate::file_test( &dir_2.canonicalize().unwrap(), crate::FileTest::EXISTS | crate::FileTest::IS_DIR )); } #[test] #[cfg(target_os = "macos")] fn test_paths() { let t_dir = tempdir().unwrap(); let tmp_dir = t_dir.path().canonicalize().unwrap(); // Test if passing paths to GLib and getting them back // gives us useful results let dir_1 = tmp_dir.join("abcd"); fs::create_dir(&dir_1).unwrap(); assert_eq!(crate::path_get_basename(&dir_1), Path::from("abcd")); assert_eq!( crate::path_get_basename(dir_1.canonicalize().unwrap()), Path::from("abcd") ); assert_eq!( crate::path_get_dirname(dir_1.canonicalize().unwrap()), tmp_dir ); assert!(crate::file_test( &dir_1, crate::FileTest::EXISTS | crate::FileTest::IS_DIR )); assert!(crate::file_test( &dir_1.canonicalize().unwrap(), crate::FileTest::EXISTS | crate::FileTest::IS_DIR )); } #[test] fn none_value() { const CLONG_NONE: libc::c_long = -1; #[derive(Debug, PartialEq, Eq)] struct SpecialU32(u32); impl IntoGlib for SpecialU32 { type GlibType = libc::c_uint; fn into_glib(self) -> libc::c_uint { self.0 as libc::c_uint } } impl OptionIntoGlib for SpecialU32 { const GLIB_NONE: Self::GlibType = CLONG_NONE as libc::c_uint; } assert_eq!(SpecialU32(0).into_glib(), 0); assert_eq!(SpecialU32(42).into_glib(), 42); assert_eq!(Some(SpecialU32(0)).into_glib(), 0); assert_eq!(Some(SpecialU32(42)).into_glib(), 42); assert_eq!( Option::None::.into_glib(), SpecialU32::GLIB_NONE ); impl TryFromGlib for SpecialU32 { type Error = GlibNoneError; unsafe fn try_from_glib(val: libc::c_uint) -> Result { if val == SpecialU32::GLIB_NONE { return Err(GlibNoneError); } Ok(SpecialU32(val as u32)) } } assert_eq!(unsafe { SpecialU32::try_from_glib(0) }, Ok(SpecialU32(0))); assert_eq!(unsafe { SpecialU32::try_from_glib(42) }, Ok(SpecialU32(42))); assert_eq!( unsafe { SpecialU32::try_from_glib(SpecialU32::GLIB_NONE) }, Err(GlibNoneError) ); assert_eq!( unsafe { Option::::from_glib(0) }, Some(SpecialU32(0)) ); assert_eq!( unsafe { Option::::from_glib(42) }, Some(SpecialU32(42)) ); assert!(unsafe { Option::::from_glib(SpecialU32::GLIB_NONE) }.is_none()); } #[test] fn invalid_value() { use std::convert::TryFrom; use std::num::TryFromIntError; #[derive(Debug, PartialEq, Eq)] struct U32(u32); impl TryFromGlib for U32 { type Error = TryFromIntError; unsafe fn try_from_glib(val: libc::c_long) -> Result { Ok(U32(u32::try_from(val)?)) } } assert_eq!(unsafe { U32::try_from_glib(0) }, Ok(U32(0))); assert_eq!(unsafe { U32::try_from_glib(42) }, Ok(U32(42))); assert!(unsafe { U32::try_from_glib(-1) }.is_err()); assert!(unsafe { U32::try_from_glib(-42) }.is_err()); } #[test] fn none_or_invalid_value() { use std::convert::TryFrom; use std::num::TryFromIntError; #[derive(Debug, PartialEq, Eq)] struct SpecialU32(u32); impl IntoGlib for SpecialU32 { type GlibType = libc::c_long; fn into_glib(self) -> libc::c_long { self.0 as libc::c_long } } impl OptionIntoGlib for SpecialU32 { const GLIB_NONE: Self::GlibType = -1; } assert_eq!(SpecialU32(0).into_glib(), 0); assert_eq!(SpecialU32(42).into_glib(), 42); assert_eq!(Some(SpecialU32(42)).into_glib(), 42); assert_eq!( Option::None::.into_glib(), SpecialU32::GLIB_NONE ); impl TryFromGlib for SpecialU32 { type Error = GlibNoneOrInvalidError; unsafe fn try_from_glib( val: libc::c_long, ) -> Result> { if val == SpecialU32::GLIB_NONE { return Err(GlibNoneOrInvalidError::None); } Ok(SpecialU32(u32::try_from(val)?)) } } assert_eq!(unsafe { SpecialU32::try_from_glib(0) }, Ok(SpecialU32(0))); assert_eq!(unsafe { SpecialU32::try_from_glib(42) }, Ok(SpecialU32(42))); assert!(unsafe { SpecialU32::try_from_glib(SpecialU32::GLIB_NONE) } .unwrap_err() .is_none()); assert!(unsafe { SpecialU32::try_from_glib(-42) } .unwrap_err() .is_invalid()); assert_eq!( unsafe { Result::, _>::from_glib(0) }, Ok(Some(SpecialU32(0))) ); assert_eq!( unsafe { Result::, _>::from_glib(42) }, Ok(Some(SpecialU32(42))) ); assert_eq!( unsafe { Result::, _>::from_glib(SpecialU32::GLIB_NONE) }, Ok(None) ); assert!(unsafe { Result::, _>::from_glib(-42) }.is_err()); } } glib-0.14.8/src/types.rs000064400000000000000000000342310072674642500131670ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! Runtime type information. use crate::translate::{ from_glib, FromGlib, FromGlibContainerAsVec, IntoGlib, ToGlibContainerFromSlice, ToGlibPtr, ToGlibPtrMut, }; use std::fmt; use std::mem; use std::ptr; /// A GLib or GLib-based library type #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GType")] pub struct Type(ffi::GType); impl Type { /// An invalid `Type` used as error return value in some functions pub const INVALID: Self = Self(gobject_ffi::G_TYPE_INVALID); /// The fundamental type corresponding to the unit type `()` pub const UNIT: Self = Self(gobject_ffi::G_TYPE_NONE); /// The fundamental type corresponding to `i8` pub const I8: Self = Self(gobject_ffi::G_TYPE_CHAR); /// The fundamental type corresponding to `u8` pub const U8: Self = Self(gobject_ffi::G_TYPE_UCHAR); /// The fundamental type corresponding to `bool` pub const BOOL: Self = Self(gobject_ffi::G_TYPE_BOOLEAN); /// The fundamental type corresponding to `i32` pub const I32: Self = Self(gobject_ffi::G_TYPE_INT); /// The fundamental type corresponding to `u32` pub const U32: Self = Self(gobject_ffi::G_TYPE_UINT); /// The fundamental type corresponding to C `long` pub const I_LONG: Self = Self(gobject_ffi::G_TYPE_LONG); /// The fundamental type corresponding to C `unsigned long` pub const U_LONG: Self = Self(gobject_ffi::G_TYPE_ULONG); /// The fundamental type corresponding to `i64` pub const I64: Self = Self(gobject_ffi::G_TYPE_INT64); /// The fundamental type corresponding to `u64` pub const U64: Self = Self(gobject_ffi::G_TYPE_UINT64); /// The fundamental type corresponding to `f32` pub const F32: Self = Self(gobject_ffi::G_TYPE_FLOAT); /// The fundamental type corresponding to `f64` pub const F64: Self = Self(gobject_ffi::G_TYPE_DOUBLE); /// The fundamental type corresponding to `String` pub const STRING: Self = Self(gobject_ffi::G_TYPE_STRING); /// The fundamental type corresponding to a pointer pub const POINTER: Self = Self(gobject_ffi::G_TYPE_POINTER); /// The fundamental type of GVariant pub const VARIANT: Self = Self(gobject_ffi::G_TYPE_VARIANT); /// The fundamental type from which all interfaces are derived pub const INTERFACE: Self = Self(gobject_ffi::G_TYPE_INTERFACE); /// The fundamental type from which all enumeration types are derived pub const ENUM: Self = Self(gobject_ffi::G_TYPE_ENUM); /// The fundamental type from which all flags types are derived pub const FLAGS: Self = Self(gobject_ffi::G_TYPE_FLAGS); /// The fundamental type from which all boxed types are derived pub const BOXED: Self = Self(gobject_ffi::G_TYPE_BOXED); /// The fundamental type from which all `GParamSpec` types are derived pub const PARAM_SPEC: Self = Self(gobject_ffi::G_TYPE_PARAM); /// The fundamental type from which all objects are derived pub const OBJECT: Self = Self(gobject_ffi::G_TYPE_OBJECT); #[doc(alias = "g_type_name")] pub fn name<'a>(self) -> &'a str { match self.into_glib() { gobject_ffi::G_TYPE_INVALID => "", x => unsafe { let ptr = gobject_ffi::g_type_name(x); std::ffi::CStr::from_ptr(ptr).to_str().unwrap() }, } } #[doc(alias = "g_type_qname")] pub fn qname(self) -> crate::Quark { match self.into_glib() { gobject_ffi::G_TYPE_INVALID => crate::Quark::from_string(""), x => unsafe { from_glib(gobject_ffi::g_type_qname(x)) }, } } #[doc(alias = "g_type_is_a")] pub fn is_a(self, other: Self) -> bool { unsafe { from_glib(gobject_ffi::g_type_is_a( self.into_glib(), other.into_glib(), )) } } #[doc(alias = "g_type_parent")] pub fn parent(self) -> Option { unsafe { let parent: Self = from_glib(gobject_ffi::g_type_parent(self.into_glib())); Some(parent).filter(|t| t.is_valid()) } } #[doc(alias = "g_type_children")] pub fn children(self) -> Vec { unsafe { let mut n_children = 0u32; let children = gobject_ffi::g_type_children(self.into_glib(), &mut n_children); FromGlibContainerAsVec::from_glib_full_num_as_vec(children, n_children as usize) } } #[doc(alias = "g_type_interfaces")] pub fn interfaces(self) -> Vec { unsafe { let mut n_interfaces = 0u32; let interfaces = gobject_ffi::g_type_interfaces(self.into_glib(), &mut n_interfaces); FromGlibContainerAsVec::from_glib_full_num_as_vec(interfaces, n_interfaces as usize) } } #[doc(alias = "g_type_interface_prerequisites")] pub fn interface_prerequisites(self) -> Vec { match self { t if !t.is_a(Self::INTERFACE) => vec![], _ => unsafe { let mut n_prereqs = 0u32; let prereqs = gobject_ffi::g_type_interface_prerequisites(self.into_glib(), &mut n_prereqs); FromGlibContainerAsVec::from_glib_full_num_as_vec(prereqs, n_prereqs as usize) }, } } #[doc(alias = "g_type_from_name")] pub fn from_name<'a, P: Into<&'a str>>(name: P) -> Option { unsafe { let type_: Self = from_glib(gobject_ffi::g_type_from_name(name.into().to_glib_none().0)); Some(type_).filter(|t| t.is_valid()) } } /// Checks that the type is not [`INVALID`](Self::INVALID) #[inline] pub fn is_valid(self) -> bool { self != Self::INVALID } } impl fmt::Debug for Type { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.name()) } } impl fmt::Display for Type { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.name()) } } /// Types that are supported by GLib dynamic typing. pub trait StaticType { /// Returns the type identifier of `Self`. fn static_type() -> Type; } impl StaticType for Type { #[doc(alias = "g_gtype_get_type")] fn static_type() -> Type { unsafe { from_glib(gobject_ffi::g_gtype_get_type()) } } } #[doc(hidden)] impl crate::value::ValueType for Type { type Type = Type; } #[doc(hidden)] unsafe impl<'a> crate::value::FromValue<'a> for Type { type Checker = crate::value::GenericValueTypeChecker; unsafe fn from_value(value: &'a crate::Value) -> Self { from_glib(gobject_ffi::g_value_get_gtype(value.to_glib_none().0)) } } #[doc(hidden)] impl crate::value::ToValue for Type { fn to_value(&self) -> crate::Value { unsafe { let mut value = crate::Value::from_type(Type::static_type()); gobject_ffi::g_value_set_gtype(value.to_glib_none_mut().0, self.into_glib()); value } } fn value_type(&self) -> crate::Type { Type::static_type() } } impl<'a, T: ?Sized + StaticType> StaticType for &'a T { fn static_type() -> Type { T::static_type() } } impl<'a, T: ?Sized + StaticType> StaticType for &'a mut T { fn static_type() -> Type { T::static_type() } } macro_rules! builtin { ($name:ty, $val:ident) => { impl StaticType for $name { fn static_type() -> Type { Type::$val } } }; } #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ILong(pub libc::c_long); impl std::ops::Deref for ILong { type Target = libc::c_long; fn deref(&self) -> &Self::Target { &self.0 } } impl std::ops::DerefMut for ILong { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl From for ILong { fn from(v: libc::c_long) -> ILong { ILong(v) } } impl From for libc::c_long { fn from(v: ILong) -> libc::c_long { v.0 } } impl PartialEq for ILong { fn eq(&self, other: &libc::c_long) -> bool { &self.0 == other } } impl PartialEq for libc::c_long { fn eq(&self, other: &ILong) -> bool { self == &other.0 } } impl PartialOrd for ILong { fn partial_cmp(&self, other: &libc::c_long) -> Option { self.0.partial_cmp(other) } } impl PartialOrd for libc::c_long { fn partial_cmp(&self, other: &ILong) -> Option { self.partial_cmp(&other.0) } } #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ULong(pub libc::c_ulong); impl std::ops::Deref for ULong { type Target = libc::c_ulong; fn deref(&self) -> &Self::Target { &self.0 } } impl std::ops::DerefMut for ULong { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl From for ULong { fn from(v: libc::c_ulong) -> ULong { ULong(v) } } impl From for libc::c_ulong { fn from(v: ULong) -> libc::c_ulong { v.0 } } impl PartialEq for ULong { fn eq(&self, other: &libc::c_ulong) -> bool { &self.0 == other } } impl PartialEq for libc::c_ulong { fn eq(&self, other: &ULong) -> bool { self == &other.0 } } impl PartialOrd for ULong { fn partial_cmp(&self, other: &libc::c_ulong) -> Option { self.0.partial_cmp(other) } } impl PartialOrd for libc::c_ulong { fn partial_cmp(&self, other: &ULong) -> Option { self.partial_cmp(&other.0) } } builtin!(bool, BOOL); builtin!(i8, I8); builtin!(u8, U8); builtin!(i32, I32); builtin!(u32, U32); builtin!(i64, I64); builtin!(u64, U64); builtin!(ILong, I_LONG); builtin!(ULong, U_LONG); builtin!(f32, F32); builtin!(f64, F64); builtin!(str, STRING); builtin!(String, STRING); impl<'a> StaticType for [&'a str] { fn static_type() -> Type { unsafe { from_glib(ffi::g_strv_get_type()) } } } impl StaticType for Vec { fn static_type() -> Type { unsafe { from_glib(ffi::g_strv_get_type()) } } } impl StaticType for () { fn static_type() -> Type { Type::UNIT } } #[inline] pub unsafe fn instance_of(ptr: ffi::gconstpointer) -> bool { from_glib(gobject_ffi::g_type_check_instance_is_a( ptr as *mut _, ::static_type().into_glib(), )) } impl FromGlib for Type { #[inline] unsafe fn from_glib(val: ffi::GType) -> Self { Self(val) } } impl IntoGlib for Type { type GlibType = ffi::GType; #[inline] fn into_glib(self) -> ffi::GType { self.0 } } impl<'a> ToGlibContainerFromSlice<'a, *mut ffi::GType> for Type { type Storage = Option>; fn to_glib_none_from_slice(t: &'a [Type]) -> (*mut ffi::GType, Self::Storage) { let mut vec = t.iter().map(|t| t.into_glib()).collect::>(); (vec.as_mut_ptr(), Some(vec)) } fn to_glib_container_from_slice(t: &'a [Type]) -> (*mut ffi::GType, Self::Storage) { (Self::to_glib_full_from_slice(t), None) } fn to_glib_full_from_slice(t: &[Type]) -> *mut ffi::GType { if t.is_empty() { return ptr::null_mut(); } unsafe { let res = ffi::g_malloc0(mem::size_of::() * (t.len() + 1)) as *mut ffi::GType; for (i, v) in t.iter().enumerate() { *res.add(i) = v.into_glib(); } res } } } impl FromGlibContainerAsVec for Type { unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GType, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for i in 0..num { res.push(from_glib(*ptr.add(i))); } res } unsafe fn from_glib_container_num_as_vec(_: *const ffi::GType, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } unsafe fn from_glib_full_num_as_vec(_: *const ffi::GType, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } } impl FromGlibContainerAsVec for Type { unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::GType, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num) } unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GType, num: usize) -> Vec { let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut ffi::GType, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num) } } #[cfg(test)] mod tests { use super::*; use crate::InitiallyUnowned; use std::collections::{BTreeSet, HashSet}; #[test] fn invalid() { let invalid = Type::INVALID; assert_eq!(invalid.name(), ""); assert_eq!(invalid.qname(), crate::Quark::from_string("")); assert!(invalid.is_a(Type::INVALID)); assert!(!invalid.is_a(Type::STRING)); assert_eq!(invalid.parent(), None); assert_eq!(invalid.children(), vec![]); assert_eq!(invalid.interfaces(), vec![]); assert_eq!(invalid.interface_prerequisites(), vec![]); assert!(!invalid.is_valid()); dbg!(&invalid); } #[test] fn hash() { // Get this first so the type is registered let iu_type = InitiallyUnowned::static_type(); let set = Type::OBJECT.children().into_iter().collect::>(); assert!(set.contains(&iu_type)); } #[test] fn ord() { // Get this first so the type is registered let iu_type = InitiallyUnowned::static_type(); assert!(Type::OBJECT < iu_type); let set = Type::OBJECT.children().into_iter().collect::>(); assert!(set.contains(&iu_type)); } } glib-0.14.8/src/unicollate.rs000064400000000000000000000050700072674642500141610ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::*; /// A `CollationKey` allows ordering strings using the linguistically correct rules for the current locale. #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct CollationKey(String); impl> From for CollationKey { /// Converts a string into a `CollationKey` that can be compared with other /// collation keys produced by the same function using `std::cmp::Ordering::cmp()`. #[doc(alias = "g_utf8_collate_key")] fn from(s: T) -> Self { let key = unsafe { from_glib_full(ffi::g_utf8_collate_key(s.as_ref().to_glib_none().0, -1)) }; Self(key) } } /// A `FilenameCollationKey` allows ordering file names using the linguistically correct rules for the current locale. /// Compared to `CollationKey`, filename collation keys take into consideration dots and other characters /// commonly found in file names. #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct FilenameCollationKey(String); impl> From for FilenameCollationKey { /// Converts a string into a `FilenameCollationKey` that can be compared with other /// collation keys produced by the same function using `std::cmp::Ordering::cmp()`. #[doc(alias = "g_utf8_collate_key_for_filename")] fn from(s: T) -> Self { let key = unsafe { from_glib_full(ffi::g_utf8_collate_key_for_filename( s.as_ref().to_glib_none().0, -1, )) }; Self(key) } } #[cfg(test)] mod tests { use super::*; #[test] fn collate() { let mut unsorted = vec![ String::from("bcd"), String::from("cde"), String::from("abc"), ]; let sorted = vec![ String::from("abc"), String::from("bcd"), String::from("cde"), ]; unsorted.sort_by(|s1, s2| CollationKey::from(&s1).cmp(&CollationKey::from(&s2))); assert_eq!(unsorted, sorted); } #[test] fn collate_filenames() { let mut unsorted = vec![ String::from("bcd.a"), String::from("cde.b"), String::from("abc.c"), ]; let sorted = vec![ String::from("abc.c"), String::from("bcd.a"), String::from("cde.b"), ]; unsorted.sort_by(|s1, s2| { FilenameCollationKey::from(&s1).cmp(&FilenameCollationKey::from(&s2)) }); assert_eq!(unsorted, sorted); } } glib-0.14.8/src/utils.rs000064400000000000000000000234120072674642500131620ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::error::BoolError; use crate::gstring::GString; use crate::translate::*; use crate::Error; use std::ffi::{OsStr, OsString}; use std::path::{Path, PathBuf}; use std::ptr; /// Same as [`get_prgname()`]. /// /// [`get_prgname()`]: fn.get_prgname.html #[doc(alias = "get_program_name")] pub fn program_name() -> Option { prgname() } #[doc(alias = "g_get_prgname")] #[doc(alias = "get_prgname")] pub fn prgname() -> Option { unsafe { from_glib_none(ffi::g_get_prgname()) } } /// Same as [`set_prgname()`]. /// /// [`set_prgname()`]: fn.set_prgname.html pub fn set_program_name(name: Option<&str>) { set_prgname(name) } #[doc(alias = "g_set_prgname")] pub fn set_prgname(name: Option<&str>) { unsafe { ffi::g_set_prgname(name.to_glib_none().0) } } #[doc(alias = "g_getenv")] pub fn getenv>(variable_name: K) -> Option { #[cfg(not(windows))] use ffi::g_getenv; #[cfg(windows)] use ffi::g_getenv_utf8 as g_getenv; unsafe { from_glib_none(g_getenv(variable_name.as_ref().to_glib_none().0)) } } #[doc(alias = "g_setenv")] pub fn setenv, V: AsRef>( variable_name: K, value: V, overwrite: bool, ) -> Result<(), BoolError> { #[cfg(not(windows))] use ffi::g_setenv; #[cfg(windows)] use ffi::g_setenv_utf8 as g_setenv; unsafe { result_from_gboolean!( g_setenv( variable_name.as_ref().to_glib_none().0, value.as_ref().to_glib_none().0, overwrite.into_glib(), ), "Failed to set environment variable" ) } } #[doc(alias = "g_unsetenv")] pub fn unsetenv>(variable_name: K) { #[cfg(not(windows))] use ffi::g_unsetenv; #[cfg(windows)] use ffi::g_unsetenv_utf8 as g_unsetenv; unsafe { g_unsetenv(variable_name.as_ref().to_glib_none().0) } } #[doc(alias = "g_environ_getenv")] pub fn environ_getenv>(envp: &[OsString], variable: K) -> Option { unsafe { from_glib_none(ffi::g_environ_getenv( envp.to_glib_none().0, variable.as_ref().to_glib_none().0, )) } } #[doc(alias = "g_get_user_name")] #[doc(alias = "get_user_name")] pub fn user_name() -> OsString { #[cfg(not(all(windows, target_arch = "x86")))] use ffi::g_get_user_name; #[cfg(all(windows, target_arch = "x86"))] use ffi::g_get_user_name_utf8 as g_get_user_name; unsafe { from_glib_none(g_get_user_name()) } } #[doc(alias = "g_get_real_name")] #[doc(alias = "get_real_name")] pub fn real_name() -> OsString { #[cfg(not(all(windows, target_arch = "x86")))] use ffi::g_get_real_name; #[cfg(all(windows, target_arch = "x86"))] use ffi::g_get_real_name_utf8 as g_get_real_name; unsafe { from_glib_none(g_get_real_name()) } } #[doc(alias = "g_get_current_dir")] #[doc(alias = "get_current_dir")] pub fn current_dir() -> Option { #[cfg(not(windows))] use ffi::g_get_current_dir; #[cfg(windows)] use ffi::g_get_current_dir_utf8 as g_get_current_dir; unsafe { from_glib_full(g_get_current_dir()) } } #[doc(alias = "g_filename_to_uri")] pub fn filename_to_uri>( filename: P, hostname: Option<&str>, ) -> Result { #[cfg(not(windows))] use ffi::g_filename_to_uri; #[cfg(windows)] use ffi::g_filename_to_uri_utf8 as g_filename_to_uri; let hostname = hostname.to_glib_none(); unsafe { let mut error = std::ptr::null_mut(); let ret = g_filename_to_uri(filename.as_ref().to_glib_none().0, hostname.0, &mut error); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_filename_from_uri")] pub fn filename_from_uri(uri: &str) -> Result<(std::path::PathBuf, Option), Error> { #[cfg(not(windows))] use ffi::g_filename_from_uri; #[cfg(windows)] use ffi::g_filename_from_uri_utf8 as g_filename_from_uri; unsafe { let mut hostname = ptr::null_mut(); let mut error = ptr::null_mut(); let ret = g_filename_from_uri(uri.to_glib_none().0, &mut hostname, &mut error); if error.is_null() { Ok((from_glib_full(ret), from_glib_full(hostname))) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_find_program_in_path")] pub fn find_program_in_path>(program: P) -> Option { #[cfg(not(all(windows, target_arch = "x86")))] use ffi::g_find_program_in_path; #[cfg(all(windows, target_arch = "x86"))] use ffi::g_find_program_in_path_utf8 as g_find_program_in_path; unsafe { from_glib_full(g_find_program_in_path(program.as_ref().to_glib_none().0)) } } #[doc(alias = "g_get_home_dir")] #[doc(alias = "get_home_dir")] pub fn home_dir() -> std::path::PathBuf { #[cfg(not(all(windows, target_arch = "x86")))] use ffi::g_get_home_dir; #[cfg(all(windows, target_arch = "x86"))] use ffi::g_get_home_dir_utf8 as g_get_home_dir; unsafe { from_glib_none(g_get_home_dir()) } } #[doc(alias = "g_get_tmp_dir")] #[doc(alias = "get_tmp_dir")] pub fn tmp_dir() -> std::path::PathBuf { #[cfg(not(all(windows, target_arch = "x86")))] use ffi::g_get_tmp_dir; #[cfg(all(windows, target_arch = "x86"))] use ffi::g_get_tmp_dir_utf8 as g_get_tmp_dir; unsafe { from_glib_none(g_get_tmp_dir()) } } #[doc(alias = "g_mkstemp")] pub fn mkstemp>(tmpl: P) -> i32 { #[cfg(not(windows))] use ffi::g_mkstemp; #[cfg(windows)] use ffi::g_mkstemp_utf8 as g_mkstemp; unsafe { g_mkstemp(tmpl.as_ref().to_glib_none().0) } } pub fn is_canonical_pspec_name(name: &str) -> bool { name.as_bytes().iter().enumerate().all(|(i, c)| { i != 0 && (*c >= b'0' && *c <= b'9' || *c == b'-') || (*c >= b'A' && *c <= b'Z') || (*c >= b'a' && *c <= b'z') }) } #[doc(alias = "g_uri_escape_string")] pub fn uri_escape_string( unescaped: &str, reserved_chars_allowed: Option<&str>, allow_utf8: bool, ) -> crate::GString { unsafe { from_glib_full(ffi::g_uri_escape_string( unescaped.to_glib_none().0, reserved_chars_allowed.to_glib_none().0, allow_utf8.into_glib(), )) } } #[doc(alias = "g_uri_unescape_string")] pub fn uri_unescape_string( escaped_string: &str, illegal_characters: Option<&str>, ) -> Option { unsafe { from_glib_full(ffi::g_uri_unescape_string( escaped_string.to_glib_none().0, illegal_characters.to_glib_none().0, )) } } #[doc(alias = "g_uri_parse_scheme")] pub fn uri_parse_scheme(uri: &str) -> Option { unsafe { from_glib_full(ffi::g_uri_parse_scheme(uri.to_glib_none().0)) } } #[doc(alias = "g_uri_unescape_segment")] pub fn uri_unescape_segment( escaped_string: Option<&str>, escaped_string_end: Option<&str>, illegal_characters: Option<&str>, ) -> Option { unsafe { from_glib_full(ffi::g_uri_unescape_segment( escaped_string.to_glib_none().0, escaped_string_end.to_glib_none().0, illegal_characters.to_glib_none().0, )) } } #[cfg(test)] mod tests { use std::env; use std::sync::Mutex; //Mutex to prevent run environment tests parallel static LOCK: once_cell::sync::Lazy> = once_cell::sync::Lazy::new(|| Mutex::new(())); const VAR_NAME: &str = "function_environment_test"; fn check_getenv(val: &str) { let _data = LOCK.lock().unwrap(); env::set_var(VAR_NAME, val); assert_eq!(env::var_os(VAR_NAME), Some(val.into())); assert_eq!(crate::getenv(VAR_NAME), Some(val.into())); let environ = crate::environ(); assert_eq!(crate::environ_getenv(&environ, VAR_NAME), Some(val.into())); } fn check_setenv(val: &str) { let _data = LOCK.lock().unwrap(); crate::setenv(VAR_NAME, val, true).unwrap(); assert_eq!(env::var_os(VAR_NAME), Some(val.into())); } #[test] fn getenv() { check_getenv("Test"); check_getenv("Тест"); // "Test" in Russian } #[test] fn setenv() { check_setenv("Test"); check_setenv("Тест"); // "Test" in Russian } #[test] fn test_filename_from_uri() { use crate::GString; use std::path::PathBuf; let uri: GString = "file:///foo/bar.txt".into(); if let Ok((filename, hostname)) = crate::filename_from_uri(&uri) { assert_eq!(filename, PathBuf::from(r"/foo/bar.txt")); assert_eq!(hostname, None); } else { unreachable!(); } let uri: GString = "file://host/foo/bar.txt".into(); if let Ok((filename, hostname)) = crate::filename_from_uri(&uri) { assert_eq!(filename, PathBuf::from(r"/foo/bar.txt")); assert_eq!(hostname, Some(GString::from("host"))); } else { unreachable!(); } } #[test] fn test_uri_parsing() { use crate::GString; assert_eq!( crate::uri_parse_scheme("foo://bar"), Some(GString::from("foo")) ); assert_eq!(crate::uri_parse_scheme("foo"), None); let escaped = crate::uri_escape_string("&foo", None, true); assert_eq!(escaped, GString::from("%26foo")); let unescaped = crate::uri_unescape_string(escaped.as_str(), None); assert_eq!(unescaped, Some(GString::from("&foo"))); assert_eq!( crate::uri_unescape_segment(Some("/foo"), None, None), Some(GString::from("/foo")) ); assert_eq!(crate::uri_unescape_segment(Some("/foo%"), None, None), None); } } glib-0.14.8/src/value.rs000064400000000000000000001117460072674642500131460ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! `Value` binding and helper traits. //! //! The type of a [`Value`](struct.Value.html) is dynamic in that it generally //! isn't known at compile time but once created a `Value` can't change its //! type. //! //! [`SendValue`](struct.SendValue.html) is a version of [`Value`](struct.Value.html) //! that can only store types that implement `Send` and as such implements `Send` itself. It //! dereferences to `Value` so it can be used everywhere `Value` references are accepted. //! //! Supported types are `bool`, `i8`, `u8`, `i32`, `u32`, `i64`, `u64`, `f32`, //! `f64`, `String` and objects (`T: IsA`). //! //! # Examples //! //! ``` //! use glib::prelude::*; // or `use gtk::prelude::*;` //! use glib::Value; //! //! // Value implement From<&i32>, From<&str> and From>. //! // Another option is the `ToValue` trait. //! let mut num = 10.to_value(); //! let mut hello = Value::from("Hello!"); //! let none: Option<&str> = None; //! let str_none = none.to_value(); //! //! // `is` tests the type of the value. //! assert!(num.is::()); //! assert!(hello.is::()); //! //! // `get` tries to get an optional value of the specified type //! // and returns an `Err` if the type doesn't match. //! assert_eq!(num.get(), Ok(10)); //! assert!(num.get::().is_err()); //! assert_eq!(hello.get(), Ok(String::from("Hello!"))); //! assert_eq!(hello.get::(), Ok(String::from("Hello!"))); //! assert_eq!(str_none.get::>(), Ok(None)); //! ``` use libc::{c_char, c_void}; use std::error; use std::ffi::CStr; use std::fmt; use std::mem; use std::ops::Deref; use std::ptr; use crate::gstring::GString; use crate::translate::*; use crate::types::{StaticType, Type}; /// A type that can be stored in `Value`s. pub trait ValueType: ToValue + FromValue<'static> + 'static { /// Type to get the `Type` from. /// /// This exists only for handling optional types. // FIXME: Should default to Self once associated type defaults are stabilized // https://github.com/rust-lang/rust/issues/29661 type Type: StaticType; } /// A type that can be stored in `Value`s and is optional. /// /// These are types were storing an `Option` is valid. Examples are `String` and all object types. pub trait ValueTypeOptional: ValueType + ToValueOptional + FromValueOptional<'static> + StaticType { } impl ValueType for Option where T: FromValue<'static, Checker = C> + ValueTypeOptional + StaticType + 'static, C: ValueTypeChecker, { type Type = T::Type; } /// Trait for `Value` type checkers. pub unsafe trait ValueTypeChecker { type Error: std::error::Error + Send + Sized + 'static; fn check(value: &Value) -> Result<(), Self::Error>; } /// An error returned from the [`get`](struct.Value.html#method.get) function /// on a [`Value`](struct.Value.html) for non-optional types an `Option`. #[derive(Clone, PartialEq, Eq, Debug)] pub struct ValueTypeMismatchError { actual: Type, requested: Type, } impl ValueTypeMismatchError { pub fn new(actual: Type, requested: Type) -> Self { Self { actual, requested } } } impl ValueTypeMismatchError { pub fn actual_type(&self) -> Type { self.actual } pub fn requested_type(&self) -> Type { self.requested } } impl fmt::Display for ValueTypeMismatchError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "Value type mismatch. Actual {:?}, requested {:?}", self.actual_type(), self.requested_type(), ) } } impl error::Error for ValueTypeMismatchError {} /// Generic `Value` type checker for types. pub struct GenericValueTypeChecker(std::marker::PhantomData); unsafe impl ValueTypeChecker for GenericValueTypeChecker { type Error = ValueTypeMismatchError; #[doc(alias = "g_type_check_value_holds")] fn check(value: &Value) -> Result<(), Self::Error> { unsafe { if gobject_ffi::g_type_check_value_holds(&value.0, T::static_type().into_glib()) == ffi::GFALSE { Err(ValueTypeMismatchError::new( Type::from_glib(value.0.g_type), T::static_type(), )) } else { Ok(()) } } } } /// An error returned from the [`get`](struct.Value.html#method.get) /// function on a [`Value`](struct.Value.html) for optional types. #[derive(Clone, PartialEq, Eq, Debug)] pub enum ValueTypeMismatchOrNoneError { WrongValueType(ValueTypeMismatchError), UnexpectedNone, } impl fmt::Display for ValueTypeMismatchOrNoneError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::WrongValueType(err) => err.fmt(f), Self::UnexpectedNone => write!(f, "Unexpected None",), } } } impl error::Error for ValueTypeMismatchOrNoneError {} impl From for ValueTypeMismatchOrNoneError { fn from(err: ValueTypeMismatchError) -> Self { Self::WrongValueType(err) } } /// Generic `Value` type checker for optional types. pub struct GenericValueTypeOrNoneChecker(std::marker::PhantomData); unsafe impl ValueTypeChecker for GenericValueTypeOrNoneChecker { type Error = ValueTypeMismatchOrNoneError; fn check(value: &Value) -> Result<(), Self::Error> { GenericValueTypeChecker::::check(value)?; unsafe { // Values are always zero-initialized so even if pointers are only 32 bits then the // whole 64 bit value will be 0 for NULL pointers. if value.0.data[0].v_uint64 == 0 { return Err(Self::Error::UnexpectedNone); } } Ok(()) } } /// Trait to retrieve the contained value from a `Value`. /// /// Usually this would not be used directly but from the [`get`](struct.Value.html#method.get) /// function on a [`Value`](struct.Value.html) pub unsafe trait FromValue<'a>: Sized { /// Value type checker. type Checker: ValueTypeChecker; /// Get the contained value from a `Value`. /// /// # Safety /// `Self::Checker::check()` must be called first and must not fail. unsafe fn from_value(value: &'a Value) -> Self; } /// Trait for types that implement `FromValue` and are Optional. /// /// This trait is auto-implemented for the appropriate types and is sealed. pub trait FromValueOptional<'a>: private::FromValueOptionalSealed<'a> {} impl<'a, T, C> FromValueOptional<'a> for T where T: FromValue<'a, Checker = C>, C: ValueTypeChecker, { } mod private { pub trait FromValueOptionalSealed<'a> {} impl<'a, T, C> FromValueOptionalSealed<'a> for T where T: super::FromValue<'a, Checker = C>, C: super::ValueTypeChecker, { } } /// Blanket implementation for all optional types. unsafe impl<'a, T, C> FromValue<'a> for Option where T: FromValue<'a, Checker = C> + StaticType, C: ValueTypeChecker, { type Checker = GenericValueTypeChecker; unsafe fn from_value(value: &'a Value) -> Self { if let Err(ValueTypeMismatchOrNoneError::UnexpectedNone) = T::Checker::check(value) { None } else { Some(T::from_value(value)) } } } /// Trait to convert a value to a `Value`. /// /// Similar to other common conversion traits, the following invariants are guaranteed: /// /// - **Invertibility**: `x.to_value().get().unwrap() == x`. In words, [`FromValue`] is the inverse of `ToValue`. /// - **Idempotence**: `x.to_value() == x.to_value().to_value()`. /// In words, applying `ToValue` multiple times yields the same result as applying it once. /// Idempotence also applies the other way around: `value.get::()` is a no-op. /// /// There is also the possibility to wrap values within values, see [`BoxedValue`]. All (un-)boxing needs to be done /// manually, and will be preserved under the conversion methods. /// /// The conversion methods may cause values to be cloned, which may result in reference counter changes or heap allocations depending /// on the source and target type. pub trait ToValue { /// Convert a value to a `Value`. fn to_value(&self) -> Value; /// Returns the type identifer of `self`. /// /// This is the type of the value to be returned by `to_value`. fn value_type(&self) -> Type; } /// Blanket implementation for all references. impl ToValue for &T { fn to_value(&self) -> Value { T::to_value(*self) } fn value_type(&self) -> Type { T::static_type() } } /// Trait to convert an `Option` to a `Value` for optional types. pub trait ToValueOptional { /// Convert an `Option` to a `Value`. #[allow(clippy::wrong_self_convention)] fn to_value_optional(s: Option<&Self>) -> Value; } /// Blanket implementation for all optional types. impl ToValue for Option { fn to_value(&self) -> Value { T::to_value_optional(self.as_ref()) } fn value_type(&self) -> Type { T::static_type() } } impl StaticType for Option { fn static_type() -> Type { T::static_type() } } impl ToValueOptional for &T { fn to_value_optional(s: Option<&Self>) -> Value { ::to_value_optional(s.as_ref().map(|s| **s)) } } /// A generic value capable of carrying various types. /// /// Once created the type of the value can't be changed. /// /// Some types (e.g. `String` and objects) support `None` values while others /// (e.g. numeric types) don't. /// /// `Value` does not implement the `Send` trait, but [`SendValue`](struct.SendValue.html) can be /// used instead. /// /// See the [module documentation](index.html) for more details. // TODO: Should use impl !Send for Value {} once stable #[repr(transparent)] #[doc(alias = "GValue")] pub struct Value(pub(crate) gobject_ffi::GValue); impl Value { /// Creates a new `Value` that is initialized with `type_` pub fn from_type(type_: Type) -> Self { unsafe { assert_eq!( gobject_ffi::g_type_check_is_value_type(type_.into_glib()), ffi::GTRUE ); let mut value = Value::uninitialized(); gobject_ffi::g_value_init(value.to_glib_none_mut().0, type_.into_glib()); value } } /// Creates a new `Value` that is initialized for a given `ValueType`. pub fn for_value_type() -> Self { Value::from_type(T::Type::static_type()) } /// Tries to get a value of type `T`. /// /// Returns `Ok` if the type is correct. pub fn get<'a, T>(&'a self) -> Result::Checker as ValueTypeChecker>::Error> where T: FromValue<'a>, { unsafe { T::Checker::check(self)?; Ok(T::from_value(self)) } } /// Returns `true` if the type of the value corresponds to `T` /// or is a sub-type of `T`. #[inline] pub fn is(&self) -> bool { self.type_().is_a(T::static_type()) } /// Returns the type of the value. pub fn type_(&self) -> Type { unsafe { from_glib(self.0.g_type) } } /// Returns whether `Value`s of type `src` can be transformed to type `dst`. #[doc(alias = "g_value_type_transformable")] pub fn type_transformable(src: Type, dst: Type) -> bool { unsafe { from_glib(gobject_ffi::g_value_type_transformable( src.into_glib(), dst.into_glib(), )) } } /// Tries to transform the value into a value of the target type #[doc(alias = "g_value_transform")] pub fn transform(&self) -> Result { unsafe { let mut dest = Value::for_value_type::(); if from_glib(gobject_ffi::g_value_transform( self.to_glib_none().0, dest.to_glib_none_mut().0, )) { Ok(dest) } else { Err(crate::bool_error!( "Can't transform value of type '{}' into '{}'", self.type_(), T::Type::static_type() )) } } } /// Consumes `Value` and returns the corresponding `GValue`. pub fn into_raw(self) -> gobject_ffi::GValue { unsafe { let s = mem::ManuallyDrop::new(self); ptr::read(&s.0) } } pub fn try_into_send_value(self) -> Result { if self.type_().is_a(T::static_type()) { Ok(SendValue(self)) } else { Err(self) } } fn content_debug_string(&self) -> GString { unsafe { from_glib_full(gobject_ffi::g_strdup_value_contents(self.to_glib_none().0)) } } } impl Clone for Value { fn clone(&self) -> Self { unsafe { let mut ret = Value::from_type(from_glib(self.0.g_type)); gobject_ffi::g_value_copy(self.to_glib_none().0, ret.to_glib_none_mut().0); ret } } } impl Drop for Value { fn drop(&mut self) { // Before GLib 2.48, unsetting a zeroed GValue would give critical warnings // https://bugzilla.gnome.org/show_bug.cgi?id=755766 if self.type_().is_valid() { unsafe { gobject_ffi::g_value_unset(self.to_glib_none_mut().0) } } } } impl fmt::Debug for Value { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "({}) {}", self.type_(), self.content_debug_string()) } } impl<'a, T: ?Sized + ToValue> From<&'a T> for Value { #[inline] fn from(value: &'a T) -> Self { value.to_value() } } impl From for Value { fn from(value: SendValue) -> Self { value.0 } } impl Uninitialized for Value { unsafe fn uninitialized() -> Value { mem::zeroed() } } impl ToValue for Value { fn to_value(&self) -> Value { self.clone() } fn value_type(&self) -> Type { self.type_() } } impl<'a> ToValue for &'a Value { fn to_value(&self) -> Value { (*self).clone() } fn value_type(&self) -> Type { self.type_() } } pub struct NopChecker; unsafe impl ValueTypeChecker for NopChecker { type Error = std::convert::Infallible; fn check(_value: &Value) -> Result<(), Self::Error> { Ok(()) } } unsafe impl<'a> FromValue<'a> for Value { type Checker = NopChecker; unsafe fn from_value(value: &'a Value) -> Self { value.clone() } } unsafe impl<'a> FromValue<'a> for &'a Value { type Checker = NopChecker; unsafe fn from_value(value: &'a Value) -> Self { value } } impl ToValue for SendValue { fn to_value(&self) -> Value { self.0.clone() } fn value_type(&self) -> Type { self.type_() } } impl<'a> ToValue for &'a SendValue { fn to_value(&self) -> Value { self.0.clone() } fn value_type(&self) -> Type { self.type_() } } impl StaticType for BoxedValue { fn static_type() -> Type { unsafe { from_glib(gobject_ffi::g_value_get_type()) } } } #[doc(hidden)] impl<'a> ToGlibPtr<'a, *const gobject_ffi::GValue> for Value { type Storage = &'a Value; fn to_glib_none(&'a self) -> Stash<'a, *const gobject_ffi::GValue, Self> { Stash(&self.0, self) } } #[doc(hidden)] impl<'a> ToGlibPtrMut<'a, *mut gobject_ffi::GValue> for Value { type Storage = &'a mut Value; fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut gobject_ffi::GValue, Self> { StashMut(&mut self.0, self) } } #[doc(hidden)] impl<'a> ToGlibPtr<'a, *mut gobject_ffi::GValue> for &'a [&'a dyn ToValue] { type Storage = ValueArray; fn to_glib_none(&'a self) -> Stash<'a, *mut gobject_ffi::GValue, Self> { let mut values: Vec = self.iter().map(|v| v.to_value().into_raw()).collect(); Stash(values.as_mut_ptr(), ValueArray(values)) } } #[doc(hidden)] impl<'a> ToGlibContainerFromSlice<'a, *mut gobject_ffi::GValue> for &'a Value { type Storage = &'a [&'a Value]; fn to_glib_none_from_slice(t: &'a [&'a Value]) -> (*mut gobject_ffi::GValue, &'a [&'a Value]) { (t.as_ptr() as *mut gobject_ffi::GValue, t) } fn to_glib_container_from_slice( t: &'a [&'a Value], ) -> (*mut gobject_ffi::GValue, &'a [&'a Value]) { if t.is_empty() { return (ptr::null_mut(), t); } unsafe { let res = ffi::g_malloc(mem::size_of::() * t.len()) as *mut gobject_ffi::GValue; ptr::copy_nonoverlapping(t.as_ptr() as *const gobject_ffi::GValue, res, t.len()); (res, t) } } fn to_glib_full_from_slice(t: &[&'a Value]) -> *mut gobject_ffi::GValue { if t.is_empty() { return ptr::null_mut(); } unsafe { let res = ffi::g_malloc0(mem::size_of::() * t.len()) as *mut gobject_ffi::GValue; for (i, v) in t.iter().enumerate() { gobject_ffi::g_value_init(res.add(i), v.type_().into_glib()); gobject_ffi::g_value_copy(v.to_glib_none().0, res.add(i)); } res } } } #[doc(hidden)] impl<'a> ToGlibContainerFromSlice<'a, *const gobject_ffi::GValue> for &'a Value { type Storage = &'a [&'a Value]; fn to_glib_none_from_slice( t: &'a [&'a Value], ) -> (*const gobject_ffi::GValue, &'a [&'a Value]) { let (ptr, storage) = ToGlibContainerFromSlice::<'a, *mut gobject_ffi::GValue>::to_glib_none_from_slice(t); (ptr as *const _, storage) } fn to_glib_container_from_slice( _: &'a [&'a Value], ) -> (*const gobject_ffi::GValue, &'a [&'a Value]) { unimplemented!() } fn to_glib_full_from_slice(_: &[&'a Value]) -> *const gobject_ffi::GValue { unimplemented!() } } macro_rules! from_glib { ($name:ident, $wrap:expr) => { impl FromGlibPtrNone<*const gobject_ffi::GValue> for $name { unsafe fn from_glib_none(ptr: *const gobject_ffi::GValue) -> Self { let mut ret = Value::from_type(from_glib((*ptr).g_type)); gobject_ffi::g_value_copy(ptr, ret.to_glib_none_mut().0); $wrap(ret) } } impl FromGlibPtrNone<*mut gobject_ffi::GValue> for $name { unsafe fn from_glib_none(ptr: *mut gobject_ffi::GValue) -> Self { from_glib_none(ptr as *const _) } } impl FromGlibPtrFull<*mut gobject_ffi::GValue> for $name { unsafe fn from_glib_full(ptr: *mut gobject_ffi::GValue) -> Self { let mut ret = Value::uninitialized(); ptr::swap(&mut ret.0, ptr); ffi::g_free(ptr as *mut c_void); $wrap(ret) } } impl FromGlibContainerAsVec<*mut gobject_ffi::GValue, *mut *mut gobject_ffi::GValue> for $name { unsafe fn from_glib_none_num_as_vec( ptr: *mut *mut gobject_ffi::GValue, num: usize, ) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for i in 0..num { res.push(from_glib_none(ptr::read(ptr.add(i)))); } res } unsafe fn from_glib_container_num_as_vec( ptr: *mut *mut gobject_ffi::GValue, num: usize, ) -> Vec { let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec( ptr: *mut *mut gobject_ffi::GValue, num: usize, ) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for i in 0..num { res.push(from_glib_full(ptr::read(ptr.add(i)))); } ffi::g_free(ptr as *mut _); res } } impl FromGlibPtrArrayContainerAsVec<*mut gobject_ffi::GValue, *mut *mut gobject_ffi::GValue> for $name { unsafe fn from_glib_none_as_vec(ptr: *mut *mut gobject_ffi::GValue) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr)) } unsafe fn from_glib_container_as_vec(ptr: *mut *mut gobject_ffi::GValue) -> Vec { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, c_ptr_array_len(ptr)) } unsafe fn from_glib_full_as_vec(ptr: *mut *mut gobject_ffi::GValue) -> Vec { FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr)) } } impl FromGlibContainerAsVec<*mut gobject_ffi::GValue, *const *mut gobject_ffi::GValue> for $name { unsafe fn from_glib_none_num_as_vec( ptr: *const *mut gobject_ffi::GValue, num: usize, ) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *mut *mut _, num) } unsafe fn from_glib_container_num_as_vec( _: *const *mut gobject_ffi::GValue, _: usize, ) -> Vec { // Can't free a *const unimplemented!() } unsafe fn from_glib_full_num_as_vec( _: *const *mut gobject_ffi::GValue, _: usize, ) -> Vec { // Can't free a *const unimplemented!() } } impl FromGlibPtrArrayContainerAsVec< *mut gobject_ffi::GValue, *const *mut gobject_ffi::GValue, > for $name { unsafe fn from_glib_none_as_vec(ptr: *const *mut gobject_ffi::GValue) -> Vec { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr as *mut *mut _) } unsafe fn from_glib_container_as_vec(_: *const *mut gobject_ffi::GValue) -> Vec { // Can't free a *const unimplemented!() } unsafe fn from_glib_full_as_vec(_: *const *mut gobject_ffi::GValue) -> Vec { // Can't free a *const unimplemented!() } } }; } from_glib!(Value, |v| v); #[doc(alias = "GValue")] pub struct ValueArray(Vec); impl Drop for ValueArray { fn drop(&mut self) { unsafe { for value in &mut self.0 { // Before GLib 2.48, unsetting a zeroed GValue would give critical warnings // https://bugzilla.gnome.org/show_bug.cgi?id=755766 if value.g_type != gobject_ffi::G_TYPE_INVALID { gobject_ffi::g_value_unset(value); } } } } } /// A version of [`Value`](struct.Value.html) for storing `Send` types, that implements Send /// itself. /// /// See the [module documentation](index.html) for more details. #[derive(Clone)] #[repr(transparent)] pub struct SendValue(Value); unsafe impl Send for SendValue {} impl SendValue { /// Consumes `SendValue` and returns the corresponding `GValue`. pub fn into_raw(self) -> gobject_ffi::GValue { self.0.into_raw() } } impl fmt::Debug for SendValue { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { ::fmt(&self.0, f) } } impl Deref for SendValue { type Target = Value; fn deref(&self) -> &Value { &self.0 } } impl<'a, T: ?Sized + ToSendValue> From<&'a T> for SendValue { #[inline] fn from(value: &'a T) -> Self { value.to_send_value() } } from_glib!(SendValue, SendValue); #[doc(hidden)] impl<'a> ToGlibPtrMut<'a, *mut gobject_ffi::GValue> for SendValue { type Storage = &'a mut SendValue; fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut gobject_ffi::GValue, Self> { StashMut(&mut (self.0).0, self) } } /// Converts to `SendValue`. pub trait ToSendValue: Send + ToValue { /// Returns a `SendValue` clone of `self`. fn to_send_value(&self) -> SendValue; } impl ToSendValue for T { fn to_send_value(&self) -> SendValue { SendValue(self.to_value()) } } impl ValueType for &'static str { type Type = Self; } unsafe impl<'a> FromValue<'a> for &'a str { type Checker = GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a Value) -> Self { let ptr = gobject_ffi::g_value_get_string(value.to_glib_none().0); CStr::from_ptr(ptr).to_str().expect("Invalid UTF-8") } } impl ToValue for str { fn to_value(&self) -> Value { unsafe { let mut value = Value::from_type(::static_type()); gobject_ffi::g_value_take_string(value.to_glib_none_mut().0, self.to_glib_full()); value } } fn value_type(&self) -> Type { String::static_type() } } impl ToValue for &str { fn to_value(&self) -> Value { (*self).to_value() } fn value_type(&self) -> Type { String::static_type() } } impl ToValueOptional for str { fn to_value_optional(s: Option<&Self>) -> Value { let mut value = Value::for_value_type::(); unsafe { gobject_ffi::g_value_take_string(value.to_glib_none_mut().0, s.to_glib_full()); } value } } impl ValueType for String { type Type = String; } unsafe impl<'a> FromValue<'a> for String { type Checker = GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a Value) -> Self { String::from(<&str>::from_value(value)) } } impl ToValue for String { fn to_value(&self) -> Value { <&str>::to_value(&self.as_str()) } fn value_type(&self) -> Type { String::static_type() } } impl ToValueOptional for String { fn to_value_optional(s: Option<&Self>) -> Value { ::to_value_optional(s.as_ref().map(|s| s.as_str())) } } impl ValueType for Vec { type Type = Vec; } unsafe impl<'a> FromValue<'a> for Vec { type Checker = GenericValueTypeChecker; unsafe fn from_value(value: &'a Value) -> Self { let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char; FromGlibPtrContainer::from_glib_none(ptr) } } impl ToValue for Vec { fn to_value(&self) -> Value { unsafe { let mut value = Value::for_value_type::(); let ptr: *mut *mut c_char = self.to_glib_full(); gobject_ffi::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void); value } } fn value_type(&self) -> Type { >::static_type() } } impl<'a> ToValue for [&'a str] { fn to_value(&self) -> Value { unsafe { let mut value = Value::for_value_type::>(); let ptr: *mut *mut c_char = self.to_glib_full(); gobject_ffi::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void); value } } fn value_type(&self) -> Type { >::static_type() } } impl<'a> ToValue for &'a [&'a str] { fn to_value(&self) -> Value { unsafe { let mut value = Value::for_value_type::>(); let ptr: *mut *mut c_char = self.to_glib_full(); gobject_ffi::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void); value } } fn value_type(&self) -> Type { >::static_type() } } impl ValueType for bool { type Type = Self; } unsafe impl<'a> FromValue<'a> for bool { type Checker = GenericValueTypeChecker; unsafe fn from_value(value: &'a Value) -> Self { from_glib(gobject_ffi::g_value_get_boolean(value.to_glib_none().0)) } } impl ToValue for bool { fn to_value(&self) -> Value { let mut value = Value::for_value_type::(); unsafe { gobject_ffi::g_value_set_boolean(&mut value.0, self.into_glib()); } value } fn value_type(&self) -> Type { Self::static_type() } } macro_rules! numeric { ($name:ty, $get:expr, $set:expr) => { impl ValueType for $name { type Type = Self; } unsafe impl<'a> FromValue<'a> for $name { type Checker = GenericValueTypeChecker; unsafe fn from_value(value: &'a Value) -> Self { $get(value.to_glib_none().0) } } impl ToValue for $name { fn to_value(&self) -> Value { let mut value = Value::for_value_type::(); unsafe { $set(&mut value.0, *self); } value } fn value_type(&self) -> Type { Self::static_type() } } }; } numeric!( i8, gobject_ffi::g_value_get_schar, gobject_ffi::g_value_set_schar ); numeric!( u8, gobject_ffi::g_value_get_uchar, gobject_ffi::g_value_set_uchar ); numeric!( i32, gobject_ffi::g_value_get_int, gobject_ffi::g_value_set_int ); numeric!( u32, gobject_ffi::g_value_get_uint, gobject_ffi::g_value_set_uint ); numeric!( i64, gobject_ffi::g_value_get_int64, gobject_ffi::g_value_set_int64 ); numeric!( u64, gobject_ffi::g_value_get_uint64, gobject_ffi::g_value_set_uint64 ); numeric!( crate::ILong, |v| gobject_ffi::g_value_get_long(v).into(), |v, i: crate::ILong| gobject_ffi::g_value_set_long(v, i.0) ); numeric!( crate::ULong, |v| gobject_ffi::g_value_get_ulong(v).into(), |v, i: crate::ULong| gobject_ffi::g_value_set_ulong(v, i.0) ); numeric!( f32, gobject_ffi::g_value_get_float, gobject_ffi::g_value_set_float ); numeric!( f64, gobject_ffi::g_value_get_double, gobject_ffi::g_value_set_double ); /// A [`Value`] containing another [`Value`]. pub struct BoxedValue(pub Value); impl Deref for BoxedValue { type Target = Value; fn deref(&self) -> &Value { &self.0 } } impl ValueType for BoxedValue { type Type = BoxedValue; } unsafe impl<'a> FromValue<'a> for BoxedValue { type Checker = GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a Value) -> Self { let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0); BoxedValue(from_glib_none(ptr as *const gobject_ffi::GValue)) } } impl ToValue for BoxedValue { fn to_value(&self) -> Value { unsafe { let mut value = Value::from_type(::static_type()); gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, self.0.to_glib_none().0 as ffi::gconstpointer, ); value } } fn value_type(&self) -> Type { BoxedValue::static_type() } } impl ToValueOptional for BoxedValue { fn to_value_optional(s: Option<&Self>) -> Value { let mut value = Value::for_value_type::(); unsafe { gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, s.map(|s| &s.0).to_glib_none().0 as ffi::gconstpointer, ); } value } } #[cfg(test)] mod tests { use super::*; #[test] fn test_send_value() { use std::thread; let v = SendValue::from(&1i32); // Must compile, while it must fail with Value thread::spawn(move || drop(v)).join().unwrap(); } #[test] fn test_strv() { let v = vec!["123", "456"].to_value(); assert_eq!( v.get::>(), Ok(vec![GString::from("123"), GString::from("456")]) ); let v = vec![String::from("123"), String::from("456")].to_value(); assert_eq!( v.get::>(), Ok(vec![GString::from("123"), GString::from("456")]) ); } #[test] fn test_from_to_value() { let v = 123.to_value(); assert_eq!(v.get(), Ok(123)); assert_eq!( v.get::<&str>(), Err(ValueTypeMismatchError::new(Type::I32, Type::STRING).into()) ); assert_eq!( v.get::(), Err(ValueTypeMismatchError::new(Type::I32, Type::BOOL)) ); // Check if &str / str / Option<&str> etc can be converted and retrieved let v_str = "test".to_value(); assert_eq!(v_str.get::<&str>(), Ok("test")); assert_eq!(v_str.get::>(), Ok(Some("test"))); assert_eq!( v_str.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); let some_v = Some("test").to_value(); assert_eq!(some_v.get::<&str>(), Ok("test")); assert_eq!(some_v.get::>(), Ok(Some("test"))); assert_eq!( some_v.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); let none_str: Option<&str> = None; let none_v = none_str.to_value(); assert_eq!(none_v.get::>(), Ok(None)); assert_eq!( none_v.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); // Check if owned T and Option can be converted and retrieved let v_str = String::from("test").to_value(); assert_eq!(v_str.get::(), Ok(String::from("test"))); assert_eq!( v_str.get::>(), Ok(Some(String::from("test"))) ); assert_eq!( v_str.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); let some_v = Some(String::from("test")).to_value(); assert_eq!(some_v.get::(), Ok(String::from("test"))); assert_eq!( some_v.get::>(), Ok(Some(String::from("test"))) ); assert_eq!( some_v.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); let none_str: Option = None; let none_v = none_str.to_value(); assert_eq!(none_v.get::>(), Ok(None)); assert_eq!( none_v.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); // Check if &T and Option<&T> can be converted and retrieved let v_str = (&String::from("test")).to_value(); assert_eq!(v_str.get::(), Ok(String::from("test"))); assert_eq!( v_str.get::>(), Ok(Some(String::from("test"))) ); assert_eq!( v_str.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); let some_v = Some(&String::from("test")).to_value(); assert_eq!(some_v.get::(), Ok(String::from("test"))); assert_eq!( some_v.get::>(), Ok(Some(String::from("test"))) ); assert_eq!( some_v.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); let none_str: Option<&String> = None; let none_v = none_str.to_value(); assert_eq!(none_v.get::>(), Ok(None)); assert_eq!( none_v.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); } #[test] fn test_transform() { let v = 123.to_value(); let v2 = v .transform::() .expect("Failed to transform to string"); assert_eq!(v2.get::<&str>(), Ok("123")); } #[test] fn test_into_raw() { unsafe { let mut v = 123.to_value().into_raw(); assert_eq!(gobject_ffi::g_type_check_value(&v), ffi::GTRUE); assert_eq!(gobject_ffi::g_value_get_int(&v), 123); gobject_ffi::g_value_unset(&mut v); } } #[test] fn test_debug() { fn value_debug_string(val: T) -> String { format!("{:?}", val.to_value()) } assert_eq!(value_debug_string(1u32), "(guint) 1"); assert_eq!(value_debug_string(2i32), "(gint) 2"); assert_eq!(value_debug_string(false), "(gboolean) FALSE"); assert_eq!(value_debug_string("FooBar"), r#"(gchararray) "FooBar""#); } } glib-0.14.8/src/value_array.rs000064400000000000000000000075260072674642500143440ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::*; use crate::Value; use std::cmp::Ordering; use std::ops; use std::slice; wrapper! { #[derive(Debug)] #[doc(alias = "GValueArray")] pub struct ValueArray(Boxed); match fn { copy => |ptr| gobject_ffi::g_value_array_copy(mut_override(ptr)), free => |ptr| gobject_ffi::g_value_array_free(ptr), type_ => || gobject_ffi::g_value_array_get_type(), } } impl ValueArray { #[doc(alias = "g_value_array_new")] pub fn new(n_prealloced: u32) -> ValueArray { unsafe { from_glib_full(gobject_ffi::g_value_array_new(n_prealloced)) } } #[doc(alias = "g_value_array_append")] pub fn append(&mut self, value: &Value) { let value = value.to_glib_none(); unsafe { gobject_ffi::g_value_array_append(self.to_glib_none_mut().0, value.0); } } pub fn is_empty(&self) -> bool { self.len() == 0 } pub fn len(&self) -> usize { let value = self.to_glib_none(); value.1.n_values as usize } #[doc(alias = "get_nth")] #[doc(alias = "g_value_array_get_nth")] pub fn nth(&self, index_: u32) -> Option { unsafe { from_glib_none(gobject_ffi::g_value_array_get_nth( mut_override(self.to_glib_none().0), index_, )) } } #[doc(alias = "g_value_array_insert")] pub fn insert(&mut self, index_: u32, value: &Value) { let value = value.to_glib_none(); unsafe { gobject_ffi::g_value_array_insert(self.to_glib_none_mut().0, index_, value.0); } } #[doc(alias = "g_value_array_prepend")] pub fn prepend(&mut self, value: &Value) { let value = value.to_glib_none(); unsafe { gobject_ffi::g_value_array_prepend(self.to_glib_none_mut().0, value.0); } } #[doc(alias = "g_value_array_remove")] pub fn remove(&mut self, index_: u32) { unsafe { gobject_ffi::g_value_array_remove(self.to_glib_none_mut().0, index_); } } #[doc(alias = "g_value_array_sort_with_data")] pub fn sort_with_data Ordering>(&mut self, compare_func: F) { unsafe extern "C" fn compare_func_trampoline( a: ffi::gconstpointer, b: ffi::gconstpointer, func: ffi::gpointer, ) -> i32 { let func = func as *mut &mut (dyn FnMut(&Value, &Value) -> Ordering); let a = &*(a as *const Value); let b = &*(b as *const Value); match (*func)(a, b) { Ordering::Less => -1, Ordering::Equal => 0, Ordering::Greater => 1, } } unsafe { let mut func = compare_func; let func_obj: &mut (dyn FnMut(&Value, &Value) -> Ordering) = &mut func; let func_ptr = &func_obj as *const &mut (dyn FnMut(&Value, &Value) -> Ordering) as ffi::gpointer; gobject_ffi::g_value_array_sort_with_data( self.to_glib_none_mut().0, Some(compare_func_trampoline), func_ptr, ); } } } impl ops::Deref for ValueArray { type Target = [Value]; fn deref(&self) -> &[Value] { unsafe { slice::from_raw_parts( (*self.to_glib_none().0).values as *const Value, (*self.to_glib_none().0).n_values as usize, ) } } } impl ops::DerefMut for ValueArray { fn deref_mut(&mut self) -> &mut [Value] { unsafe { slice::from_raw_parts_mut( (*self.to_glib_none().0).values as *mut Value, (*self.to_glib_none().0).n_values as usize, ) } } } glib-0.14.8/src/variant.rs000064400000000000000000001073200072674642500134670ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! `Variant` binding and helper traits. //! //! [`Variant`](struct.Variant.html) is an immutable dynamically-typed generic //! container. Its type and value are defined at construction and never change. //! //! `Variant` types are described by [`VariantType`](../struct.VariantType.html) //! "type strings". //! //! Although `GVariant` supports arbitrarily complex types, this binding is //! currently limited to the basic ones: `bool`, `u8`, `i16`, `u16`, `i32`, //! `u32`, `i64`, `u64`, `f64`, `&str`/`String`, and [`VariantDict`](../struct.VariantDict.html). //! //! # Examples //! //! ``` //! use glib::prelude::*; // or `use gtk::prelude::*;` //! use glib::{Variant, FromVariant, ToVariant}; //! use std::collections::HashMap; //! //! // Using the `ToVariant` trait. //! let num = 10.to_variant(); //! //! // `is` tests the type of the value. //! assert!(num.is::()); //! //! // `get` tries to extract the value. //! assert_eq!(num.get::(), Some(10)); //! assert_eq!(num.get::(), None); //! //! // `get_str` tries to borrow a string slice. //! let hello = "Hello!".to_variant(); //! assert_eq!(hello.str(), Some("Hello!")); //! assert_eq!(num.str(), None); //! //! // `bytes` tries to borrow a byte array (GVariant type `ay`), //! // rather than creating a deep copy which would be expensive for //! // nontrivially sized byte arrays. //! // The test data here is the zstd compression header, which //! // stands in for arbitrary binary data (e.g. not UTF-8). //! let bufdata = b"\xFD\x2F\xB5\x28"; //! let bufv = bufdata.to_variant(); //! assert_eq!(bufv.bytes().unwrap(), bufdata); //! assert!(num.bytes().is_err()); //! //! // Variant carrying a Variant //! let variant = Variant::from_variant(&hello); //! let variant = variant.as_variant().unwrap(); //! assert_eq!(variant.str(), Some("Hello!")); //! //! // Variant carrying an array //! let array = ["Hello".to_variant(), "there!".to_variant()]; //! let variant = Variant::from_array::<&str>(&array); //! assert_eq!(variant.n_children(), 2); //! assert_eq!(variant.child_value(0).str(), Some("Hello")); //! assert_eq!(variant.child_value(1).str(), Some("there!")); //! //! // You can also convert from and to a Vec //! let array = vec!["Hello", "there!"].to_variant(); //! assert_eq!(variant.n_children(), 2); //! let vec = >::from_variant(&array).unwrap(); //! assert_eq!(vec[0], "Hello"); //! //! // Conversion to and from HashMap is also possible //! let mut map: HashMap = HashMap::new(); //! map.insert(1, "hi"); //! map.insert(2, "there"); //! let variant = map.to_variant(); //! assert_eq!(variant.n_children(), 2); //! let map: HashMap = HashMap::from_variant(&variant).unwrap(); //! assert_eq!(map[&1], "hi"); //! assert_eq!(map[&2], "there"); //! //! // And conversion to and from tuples. //! let variant = ("hello", 42u16, vec![ "there", "you" ],).to_variant(); //! assert_eq!(variant.n_children(), 3); //! assert_eq!(variant.type_().to_str(), "(sqas)"); //! let tuple = <(String, u16, Vec)>::from_variant(&variant).unwrap(); //! assert_eq!(tuple.0, "hello"); //! assert_eq!(tuple.1, 42); //! assert_eq!(tuple.2, &[ "there", "you"]); //! //! // `Option` is supported as well, through maybe types //! let variant = Some("hello").to_variant(); //! assert_eq!(variant.n_children(), 1); //! let mut s = >::from_variant(&variant).unwrap(); //! assert_eq!(s.unwrap(), "hello"); //! s = None; //! let variant = s.to_variant(); //! assert_eq!(variant.n_children(), 0); //! let s = >::from_variant(&variant).unwrap(); //! assert!(s.is_none()); //! ``` use crate::bytes::Bytes; use crate::gstring::GString; use crate::translate::*; use crate::StaticType; use crate::Type; use crate::VariantTy; use crate::VariantType; use crate::{VariantIter, VariantStrIter}; use std::borrow::Cow; use std::cmp::{Eq, Ordering, PartialEq, PartialOrd}; use std::collections::HashMap; use std::fmt; use std::hash::{BuildHasher, Hash, Hasher}; use std::slice; use std::str; wrapper! { /// A generic immutable value capable of carrying various types. /// /// See the [module documentation](index.html) for more details. #[doc(alias = "GVariant")] pub struct Variant(Shared); match fn { ref => |ptr| ffi::g_variant_ref_sink(ptr), unref => |ptr| ffi::g_variant_unref(ptr), } } impl StaticType for Variant { fn static_type() -> Type { Type::VARIANT } } #[doc(hidden)] impl crate::value::ValueType for Variant { type Type = Variant; } #[doc(hidden)] unsafe impl<'a> crate::value::FromValue<'a> for Variant { type Checker = crate::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a crate::Value) -> Self { let ptr = gobject_ffi::g_value_dup_variant(value.to_glib_none().0); assert!(!ptr.is_null()); from_glib_full(ptr) } } #[doc(hidden)] impl crate::value::ToValue for Variant { fn to_value(&self) -> crate::Value { unsafe { let mut value = crate::Value::from_type(Variant::static_type()); gobject_ffi::g_value_take_variant( value.to_glib_none_mut().0, self.to_glib_full() as *mut _, ); value } } fn value_type(&self) -> crate::Type { Variant::static_type() } } #[doc(hidden)] impl crate::value::ToValueOptional for Variant { fn to_value_optional(s: Option<&Self>) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { gobject_ffi::g_value_take_variant( value.to_glib_none_mut().0, s.to_glib_full() as *mut _, ); } value } } /// An error returned from the [`try_get`](struct.Variant.html#method.try_get) function /// on a [`Variant`](struct.Variant.html) when the expected type does not match the actual type. #[derive(Clone, PartialEq, Eq, Debug)] pub struct VariantTypeMismatchError { pub actual: VariantType, pub expected: VariantType, } impl VariantTypeMismatchError { pub fn new(actual: VariantType, expected: VariantType) -> Self { Self { actual, expected } } } impl fmt::Display for VariantTypeMismatchError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "Type mismatch: Expected '{}' got '{}'", self.expected, self.actual ) } } impl std::error::Error for VariantTypeMismatchError {} impl Variant { /// Returns the type of the value. pub fn type_(&self) -> &VariantTy { unsafe { VariantTy::from_ptr(ffi::g_variant_get_type(self.to_glib_none().0)) } } /// Returns `true` if the type of the value corresponds to `T`. #[inline] pub fn is(&self) -> bool { self.type_() == T::static_variant_type() } /// Tries to extract a value of type `T`. /// /// Returns `Some` if `T` matches the variant's type. #[inline] pub fn get(&self) -> Option { T::from_variant(self) } /// Tries to extract a value of type `T`. pub fn try_get(&self) -> Result { self.get().ok_or_else(|| { VariantTypeMismatchError::new( self.type_().to_owned(), T::static_variant_type().into_owned(), ) }) } /// Boxes value. #[inline] pub fn from_variant(value: &Variant) -> Self { unsafe { from_glib_none(ffi::g_variant_new_variant(value.to_glib_none().0)) } } /// Unboxes self. /// /// Returns `Some` if self contains a `Variant`. #[inline] #[doc(alias = "get_variant")] pub fn as_variant(&self) -> Option { unsafe { from_glib_full(ffi::g_variant_get_variant(self.to_glib_none().0)) } } /// Reads a child item out of a container `Variant` instance. /// /// # Panics /// /// * if `self` is not a container type. /// * if given `index` is larger than number of children. #[doc(alias = "get_child_value")] #[doc(alias = "g_variant_get_child_value")] pub fn child_value(&self, index: usize) -> Variant { assert!(self.is_container()); assert!(index < self.n_children()); unsafe { from_glib_full(ffi::g_variant_get_child_value(self.to_glib_none().0, index)) } } /// Try to read a child item out of a container `Variant` instance. /// /// It returns `None` if `self` is not a container type or if the given /// `index` is larger than number of children. pub fn try_child_value(&self, index: usize) -> Option { if !(self.is_container() && index < self.n_children()) { return None; } let v = unsafe { from_glib_full(ffi::g_variant_get_child_value(self.to_glib_none().0, index)) }; Some(v) } /// Try to read a child item out of a container `Variant` instance. /// /// It returns `Ok(None)` if `self` is not a container type or if the given /// `index` is larger than number of children. An error is thrown if the /// type does not match. pub fn try_child_get( &self, index: usize, ) -> Result, VariantTypeMismatchError> { // TODO: In the future optimize this by using g_variant_get_child() // directly to avoid allocating a GVariant. self.try_child_value(index).map(|v| v.try_get()).transpose() } /// Read a child item out of a container `Variant` instance. /// /// # Panics /// /// * if `self` is not a container type. /// * if given `index` is larger than number of children. /// * if the expected variant type does not match pub fn child_get(&self, index: usize) -> T { // TODO: In the future optimize this by using g_variant_get_child() // directly to avoid allocating a GVariant. self.child_value(index).get().unwrap() } /// Tries to extract a `&str`. /// /// Returns `Some` if the variant has a string type (`s`, `o` or `g` type /// strings). #[doc(alias = "get_str")] #[doc(alias = "g_variant_get_string")] pub fn str(&self) -> Option<&str> { unsafe { match self.type_().to_str() { "s" | "o" | "g" => { let mut len = 0; let ptr = ffi::g_variant_get_string(self.to_glib_none().0, &mut len); let ret = str::from_utf8_unchecked(slice::from_raw_parts( ptr as *const u8, len as usize, )); Some(ret) } _ => None, } } } /// Tries to extract a `&[u8]` from a variant of type `ay` (array of bytes). /// /// Returns an error if the type is not `ay`. pub fn bytes(&self) -> Result<&[u8], VariantTypeMismatchError> { unsafe { let t = self.type_(); let expected_ty = &*Vec::::static_variant_type(); if t == expected_ty { let selfv = self.to_glib_none(); let len = ffi::g_variant_get_size(selfv.0); let ptr = ffi::g_variant_get_data(selfv.0); let ret = slice::from_raw_parts(ptr as *const u8, len as usize); Ok(ret) } else { Err(VariantTypeMismatchError { actual: t.to_owned(), expected: expected_ty.to_owned(), }) } } } /// Creates a new GVariant array from children. /// /// All children must be of type `T`. pub fn from_array(children: &[Variant]) -> Self { let type_ = T::static_variant_type(); for child in children { assert_eq!(type_, child.type_()); } unsafe { from_glib_none(ffi::g_variant_new_array( type_.as_ptr() as *const _, children.to_glib_none().0, children.len(), )) } } /// Creates a new GVariant tuple from children. pub fn from_tuple(children: &[Variant]) -> Self { unsafe { from_glib_none(ffi::g_variant_new_tuple( children.to_glib_none().0, children.len(), )) } } /// Creates a new maybe Variant. pub fn from_maybe(child: Option<&Variant>) -> Self { let type_ = T::static_variant_type(); let ptr = match child { Some(child) => { assert_eq!(type_, child.type_()); child.to_glib_none().0 } None => std::ptr::null(), }; unsafe { from_glib_none(ffi::g_variant_new_maybe( type_.as_ptr() as *const _, ptr as *mut ffi::GVariant, )) } } /// Constructs a new serialised-mode GVariant instance. #[doc(alias = "g_variant_new_from_bytes")] pub fn from_bytes(bytes: &Bytes) -> Self { unsafe { from_glib_none(ffi::g_variant_new_from_bytes( T::static_variant_type().as_ptr() as *const _, bytes.to_glib_none().0, false.into_glib(), )) } } /// Constructs a new serialised-mode GVariant instance. /// /// This is the same as `from_bytes`, except that checks on the passed /// data are skipped. /// /// You should not use this function on data from external sources. /// /// # Safety /// /// Since the data is not validated, this is potentially dangerous if called /// on bytes which are not guaranteed to have come from serialising another /// Variant. The caller is responsible for ensuring bad data is not passed in. pub unsafe fn from_bytes_trusted(bytes: &Bytes) -> Self { from_glib_none(ffi::g_variant_new_from_bytes( T::static_variant_type().as_ptr() as *const _, bytes.to_glib_none().0, true.into_glib(), )) } /// Returns the serialised form of a GVariant instance. #[doc(alias = "get_data_as_bytes")] #[doc(alias = "g_variant_get_data_as_bytes")] pub fn data_as_bytes(&self) -> Bytes { unsafe { from_glib_full(ffi::g_variant_get_data_as_bytes(self.to_glib_none().0)) } } /// Returns a copy of the variant in normal form. #[doc(alias = "g_variant_get_normal_form")] pub fn normal_form(&self) -> Self { unsafe { from_glib_full(ffi::g_variant_get_normal_form(self.to_glib_none().0)) } } /// Returns a copy of the variant in the opposite endianness. #[doc(alias = "g_variant_byteswap")] pub fn byteswap(&self) -> Self { unsafe { from_glib_full(ffi::g_variant_byteswap(self.to_glib_none().0)) } } /// Determines the number of children in a container GVariant instance. #[doc(alias = "g_variant_n_children")] pub fn n_children(&self) -> usize { assert!(self.is_container()); unsafe { ffi::g_variant_n_children(self.to_glib_none().0) } } /// Create an iterator over items in the variant. /// /// Note that this heap allocates a variant for each element, /// which can be particularly expensive for large arrays. pub fn iter(&self) -> VariantIter { assert!(self.is_container()); VariantIter::new(self.clone()) } /// Create an iterator over borrowed strings from a GVariant of type `as` (array of string). /// /// This will fail if the variant is not an array of with /// the expected child type. /// /// A benefit of this API over [`Self::iter()`] is that it /// minimizes allocation, and provides strongly typed access. /// /// ``` /// # use glib::prelude::*; /// let strs = &["foo", "bar"]; /// let strs_variant: glib::Variant = strs.to_variant(); /// for s in strs_variant.array_iter_str()? { /// println!("{}", s); /// } /// # Ok::<(), Box>(()) /// ``` pub fn array_iter_str(&self) -> Result { let child_ty = String::static_variant_type(); let actual_ty = self.type_(); let expected_ty = child_ty.with_array(); if actual_ty != expected_ty { return Err(VariantTypeMismatchError { actual: actual_ty.to_owned(), expected: expected_ty, }); } Ok(VariantStrIter::new(self)) } /// Variant has a container type. #[doc(alias = "g_variant_is_container")] pub fn is_container(&self) -> bool { unsafe { ffi::g_variant_is_container(self.to_glib_none().0) != ffi::GFALSE } } } unsafe impl Send for Variant {} unsafe impl Sync for Variant {} impl fmt::Debug for Variant { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Variant") .field("ptr", &self.to_glib_none().0) .field("type", &self.type_()) .field("value", &self.to_string()) .finish() } } impl fmt::Display for Variant { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let serialized: GString = unsafe { from_glib_full(ffi::g_variant_print( self.to_glib_none().0, false.into_glib(), )) }; f.write_str(&serialized) } } impl PartialEq for Variant { #[doc(alias = "g_variant_equal")] fn eq(&self, other: &Self) -> bool { unsafe { from_glib(ffi::g_variant_equal( self.to_glib_none().0 as *const _, other.to_glib_none().0 as *const _, )) } } } impl Eq for Variant {} impl PartialOrd for Variant { fn partial_cmp(&self, other: &Self) -> Option { unsafe { if ffi::g_variant_classify(self.to_glib_none().0) != ffi::g_variant_classify(other.to_glib_none().0) { return None; } if self.is_container() { return None; } let res = ffi::g_variant_compare( self.to_glib_none().0 as *const _, other.to_glib_none().0 as *const _, ); Some(res.cmp(&0)) } } } impl Hash for Variant { #[doc(alias = "g_variant_hash")] fn hash(&self, state: &mut H) { unsafe { state.write_u32(ffi::g_variant_hash(self.to_glib_none().0 as *const _)) } } } /// Converts to `Variant`. pub trait ToVariant { /// Returns a `Variant` clone of `self`. fn to_variant(&self) -> Variant; } /// Extracts a value. pub trait FromVariant: Sized + StaticVariantType { /// Tries to extract a value. /// /// Returns `Some` if the variant's type matches `Self`. fn from_variant(variant: &Variant) -> Option; } /// Returns `VariantType` of `Self`. pub trait StaticVariantType { /// Returns the `VariantType` corresponding to `Self`. fn static_variant_type() -> Cow<'static, VariantTy>; } impl StaticVariantType for Variant { fn static_variant_type() -> Cow<'static, VariantTy> { unsafe { VariantTy::from_str_unchecked("v").into() } } } impl<'a, T: ?Sized + ToVariant> ToVariant for &'a T { fn to_variant(&self) -> Variant { ::to_variant(self) } } impl<'a, T: ?Sized + StaticVariantType> StaticVariantType for &'a T { fn static_variant_type() -> Cow<'static, VariantTy> { ::static_variant_type() } } macro_rules! impl_numeric { ($name:ty, $type_str:expr, $new_fn:ident, $get_fn:ident) => { impl StaticVariantType for $name { fn static_variant_type() -> Cow<'static, VariantTy> { unsafe { VariantTy::from_str_unchecked($type_str).into() } } } impl ToVariant for $name { fn to_variant(&self) -> Variant { unsafe { from_glib_none(ffi::$new_fn(*self)) } } } impl FromVariant for $name { fn from_variant(variant: &Variant) -> Option { unsafe { if variant.is::() { Some(ffi::$get_fn(variant.to_glib_none().0)) } else { None } } } } }; } impl_numeric!(u8, "y", g_variant_new_byte, g_variant_get_byte); impl_numeric!(i16, "n", g_variant_new_int16, g_variant_get_int16); impl_numeric!(u16, "q", g_variant_new_uint16, g_variant_get_uint16); impl_numeric!(i32, "i", g_variant_new_int32, g_variant_get_int32); impl_numeric!(u32, "u", g_variant_new_uint32, g_variant_get_uint32); impl_numeric!(i64, "x", g_variant_new_int64, g_variant_get_int64); impl_numeric!(u64, "t", g_variant_new_uint64, g_variant_get_uint64); impl_numeric!(f64, "d", g_variant_new_double, g_variant_get_double); impl StaticVariantType for bool { fn static_variant_type() -> Cow<'static, VariantTy> { unsafe { VariantTy::from_str_unchecked("b").into() } } } impl ToVariant for bool { fn to_variant(&self) -> Variant { unsafe { from_glib_none(ffi::g_variant_new_boolean(self.into_glib())) } } } impl FromVariant for bool { fn from_variant(variant: &Variant) -> Option { unsafe { if variant.is::() { Some(from_glib(ffi::g_variant_get_boolean( variant.to_glib_none().0, ))) } else { None } } } } impl StaticVariantType for String { fn static_variant_type() -> Cow<'static, VariantTy> { unsafe { VariantTy::from_str_unchecked("s").into() } } } impl ToVariant for String { fn to_variant(&self) -> Variant { self[..].to_variant() } } impl FromVariant for String { fn from_variant(variant: &Variant) -> Option { variant.str().map(String::from) } } impl StaticVariantType for str { fn static_variant_type() -> Cow<'static, VariantTy> { unsafe { VariantTy::from_str_unchecked("s").into() } } } impl ToVariant for str { fn to_variant(&self) -> Variant { unsafe { from_glib_none(ffi::g_variant_new_take_string(self.to_glib_full())) } } } impl StaticVariantType for Option { fn static_variant_type() -> Cow<'static, VariantTy> { let child_type = T::static_variant_type(); let signature = format!("m{}", child_type.to_str()); VariantType::new(&signature) .expect("incorrect signature") .into() } } impl ToVariant for Option { fn to_variant(&self) -> Variant { Variant::from_maybe::(self.as_ref().map(|m| m.to_variant()).as_ref()) } } impl FromVariant for Option { fn from_variant(variant: &Variant) -> Option { unsafe { if variant.is::() { let c_child = ffi::g_variant_get_maybe(variant.to_glib_none().0); if !c_child.is_null() { let child: Variant = from_glib_full(c_child); Some(T::from_variant(&child)) } else { Some(None) } } else { None } } } } impl StaticVariantType for [T] { fn static_variant_type() -> Cow<'static, VariantTy> { T::static_variant_type().with_array().into() } } impl ToVariant for [T] { fn to_variant(&self) -> Variant { let mut vec = Vec::with_capacity(self.len()); for child in self { vec.push(child.to_variant()); } Variant::from_array::(&vec) } } impl FromVariant for Vec { fn from_variant(variant: &Variant) -> Option { if !variant.is_container() { return None; } let mut vec = Vec::with_capacity(variant.n_children()); for i in 0..variant.n_children() { match variant.child_value(i).get() { Some(child) => vec.push(child), None => return None, } } Some(vec) } } impl ToVariant for Vec { fn to_variant(&self) -> Variant { let mut vec = Vec::with_capacity(self.len()); for child in self { vec.push(child.to_variant()); } Variant::from_array::(&vec) } } impl StaticVariantType for Vec { fn static_variant_type() -> Cow<'static, VariantTy> { <[T]>::static_variant_type() } } #[test] fn test_regression_from_variant_panics() { let variant = "text".to_variant(); let hashmap: Option> = FromVariant::from_variant(&variant); assert!(hashmap.is_none()); let variant = HashMap::::new().to_variant(); let hashmap: Option> = FromVariant::from_variant(&variant); assert!(hashmap.is_some()); } impl FromVariant for HashMap where K: FromVariant + Eq + Hash, V: FromVariant, H: BuildHasher + Default, { fn from_variant(variant: &Variant) -> Option { if !variant.is_container() { return None; } let mut map = HashMap::default(); for i in 0..variant.n_children() { let entry = variant.child_value(i); let key = match entry.child_value(0).get() { Some(key) => key, None => return None, }; let val = match entry.child_value(1).get() { Some(val) => val, None => return None, }; map.insert(key, val); } Some(map) } } impl ToVariant for HashMap where K: StaticVariantType + ToVariant + Eq + Hash, V: StaticVariantType + ToVariant, { fn to_variant(&self) -> Variant { let mut vec = Vec::with_capacity(self.len()); for (key, value) in self { let entry = DictEntry::new(key, value).to_variant(); vec.push(entry); } Variant::from_array::>(&vec) } } /// A Dictionary entry. /// /// While GVariant format allows a dictionary entry to be an independent type, typically you'll need /// to use this in a dictionary, which is simply an array of dictionary entries. The following code /// creates a dictionary: /// /// ``` ///# use glib::prelude::*; // or `use gtk::prelude::*;` /// use glib::{Variant, FromVariant, ToVariant}; /// use glib::variant::DictEntry; /// /// let entries = vec![ /// DictEntry::new("uuid", 1000u32).to_variant(), /// DictEntry::new("guid", 1001u32).to_variant(), /// ]; /// let dict = Variant::from_array::>(&entries); /// assert_eq!(dict.n_children(), 2); /// assert_eq!(dict.type_().to_str(), "a{su}"); /// ``` pub struct DictEntry { key: K, value: V, } impl DictEntry where K: StaticVariantType + ToVariant + Eq + Hash, V: StaticVariantType + ToVariant, { pub fn new(key: K, value: V) -> Self { Self { key, value } } pub fn key(&self) -> &K { &self.key } pub fn value(&self) -> &V { &self.value } } impl FromVariant for DictEntry where K: FromVariant + Eq + Hash, V: FromVariant, { fn from_variant(variant: &Variant) -> Option { let key = match variant.child_value(0).get() { Some(key) => key, None => return None, }; let value = match variant.child_value(1).get() { Some(value) => value, None => return None, }; Some(Self { key, value }) } } impl ToVariant for DictEntry where K: StaticVariantType + ToVariant + Eq + Hash, V: StaticVariantType + ToVariant, { fn to_variant(&self) -> Variant { unsafe { from_glib_none(ffi::g_variant_new_dict_entry( self.key.to_variant().to_glib_none().0, self.value.to_variant().to_glib_none().0, )) } } } impl ToVariant for Variant { fn to_variant(&self) -> Variant { Variant::from_variant(self) } } impl FromVariant for Variant { fn from_variant(variant: &Variant) -> Option { variant.as_variant() } } impl StaticVariantType for DictEntry { fn static_variant_type() -> Cow<'static, VariantTy> { let key_type = K::static_variant_type(); let value_type = V::static_variant_type(); let signature = format!("{{{}{}}}", key_type.to_str(), value_type.to_str()); VariantType::new(&signature) .expect("incorrect signature") .into() } } impl StaticVariantType for HashMap where K: StaticVariantType, V: StaticVariantType, H: BuildHasher + Default, { fn static_variant_type() -> Cow<'static, VariantTy> { let key_type = K::static_variant_type(); let value_type = V::static_variant_type(); let signature = format!("a{{{}{}}}", key_type.to_str(), value_type.to_str()); VariantType::new(&signature) .expect("incorrect signature") .into() } } macro_rules! tuple_impls { ($($len:expr => ($($n:tt $name:ident)+))+) => { $( impl<$($name),+> StaticVariantType for ($($name,)+) where $($name: StaticVariantType,)+ { fn static_variant_type() -> Cow<'static, VariantTy> { let mut signature = String::with_capacity(255); signature.push('('); $( signature.push_str($name::static_variant_type().to_str()); )+ signature.push(')'); VariantType::new(&signature).expect("incorrect signature").into() } } impl<$($name),+> FromVariant for ($($name,)+) where $($name: FromVariant,)+ { fn from_variant(variant: &Variant) -> Option { Some(( $( match $name::from_variant(&variant.child_value($n)) { Some(field) => field, None => return None, }, )+ )) } } impl<$($name),+> ToVariant for ($($name,)+) where $($name: ToVariant,)+ { fn to_variant(&self) -> Variant { let mut fields = Vec::with_capacity($len); $( let field = self.$n.to_variant(); fields.push(field); )+ Variant::from_tuple(&fields) } } )+ } } tuple_impls! { 1 => (0 T0) 2 => (0 T0 1 T1) 3 => (0 T0 1 T1 2 T2) 4 => (0 T0 1 T1 2 T2 3 T3) 5 => (0 T0 1 T1 2 T2 3 T3 4 T4) 6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5) 7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6) 8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7) 9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8) 10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9) 11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10) 12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11) 13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12) 14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13) 15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14) 16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15) } #[cfg(test)] mod tests { use super::*; use std::collections::{HashMap, HashSet}; macro_rules! unsigned { ($name:ident, $ty:ident) => { #[test] fn $name() { let mut n = $ty::max_value(); while n > 0 { let v = n.to_variant(); assert_eq!(v.get(), Some(n)); n /= 2; } } }; } macro_rules! signed { ($name:ident, $ty:ident) => { #[test] fn $name() { let mut n = $ty::max_value(); while n > 0 { let v = n.to_variant(); assert_eq!(v.get(), Some(n)); let v = (-n).to_variant(); assert_eq!(v.get(), Some(-n)); n /= 2; } } }; } unsigned!(test_u8, u8); unsigned!(test_u16, u16); unsigned!(test_u32, u32); unsigned!(test_u64, u64); signed!(test_i16, i16); signed!(test_i32, i32); signed!(test_i64, i64); #[test] fn test_str() { let s = "this is a test"; let v = s.to_variant(); assert_eq!(v.str(), Some(s)); assert_eq!(42u32.to_variant().str(), None); } #[test] fn test_bytes() { let b = b"this is a test"; let v = b.to_variant(); assert_eq!(v.bytes().unwrap(), b); assert!(42u32.to_variant().bytes().is_err()); } #[test] fn test_string() { let s = String::from("this is a test"); let v = s.to_variant(); assert_eq!(v.get(), Some(s)); assert_eq!(v.normal_form(), v); } #[test] fn test_eq() { let v1 = "this is a test".to_variant(); let v2 = "this is a test".to_variant(); let v3 = "test".to_variant(); assert_eq!(v1, v2); assert_ne!(v1, v3); } #[test] fn test_hash() { let v1 = "this is a test".to_variant(); let v2 = "this is a test".to_variant(); let v3 = "test".to_variant(); let mut set = HashSet::new(); set.insert(v1); assert!(set.contains(&v2)); assert!(!set.contains(&v3)); assert_eq!( >::static_variant_type().to_str(), "a{s(syu)}" ); } #[test] fn test_array() { assert_eq!(>::static_variant_type().to_str(), "as"); assert_eq!( >::static_variant_type().to_str(), "a(syu)" ); let a = ["foo", "bar", "baz"].to_variant(); assert_eq!(a.normal_form(), a); assert_eq!(a.array_iter_str().unwrap().len(), 3); let o = 0u32.to_variant(); assert!(o.array_iter_str().is_err()); } #[test] fn test_get() -> Result<(), Box> { let u = 42u32.to_variant(); assert!(u.get::().is_none()); assert_eq!(u.get::().unwrap(), 42); assert!(u.try_get::().is_err()); // Test ? conversion assert_eq!(u.try_get::()?, 42); Ok(()) } #[test] fn test_byteswap() { let u = 42u32.to_variant(); assert_eq!(u.byteswap().get::().unwrap(), 704643072u32); assert_eq!(u.byteswap().byteswap().get::().unwrap(), 42u32); } #[test] fn test_try_child() { let a = ["foo"].to_variant(); assert!(a.try_child_value(0).is_some()); assert_eq!(a.try_child_get::(0).unwrap().unwrap(), "foo"); assert_eq!(a.child_get::(0), "foo"); assert!(a.try_child_get::(0).is_err()); assert!(a.try_child_value(1).is_none()); assert!(a.try_child_get::(1).unwrap().is_none()); let u = 42u32.to_variant(); assert!(u.try_child_value(0).is_none()); assert!(u.try_child_get::(0).unwrap().is_none()); } } glib-0.14.8/src/variant_dict.rs000064400000000000000000000231500072674642500144700ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::borrow::Cow; use std::default::Default; use crate::translate::*; use crate::variant::*; use crate::variant_type::*; wrapper! { /// `VariantDict` is a mutable key/value store where the keys are always /// strings and the values are [`Variant`s](variant/struct.Variant.html). /// /// Variant dictionaries can easily be converted to/from `Variant`s of the /// appropriate type. In `glib` terms, this is a variant of the form `"a{sv}"`. /// /// # Panics /// /// Note, pretty much all methods on this struct will panic if the /// [`end_unsafe()`](#method.end_unsafe) method was called on the instance. #[doc(alias = "GVariantDict")] pub struct VariantDict(Shared); match fn { ref => |ptr| ffi::g_variant_dict_ref(ptr), unref => |ptr| ffi::g_variant_dict_unref(ptr), type_ => || ffi::g_variant_dict_get_type(), } } impl VariantDict { /// Create a new `VariantDict` optionally populating it with the given `Variant` /// /// Since `Variant`s are immutable, this does not couple the `VariantDict` with /// the input `Variant`, instead the contents are copied into the `VariantDict`. /// /// # Panics /// /// This function will panic if the given `Variant` is not of the correct type. #[doc(alias = "g_variant_dict_new")] pub fn new(from_asv: Option<&Variant>) -> Self { if let Some(var) = from_asv { assert_eq!(var.type_(), VariantDict::static_variant_type()); } unsafe { from_glib_full(ffi::g_variant_dict_new(from_asv.to_glib_none().0)) } } /// Check if this `VariantDict` contains the given key. /// /// Look up whether or not the given key is present, returning `true` if it /// is present in `self`. #[doc(alias = "g_variant_dict_contains")] pub fn contains(&self, key: &str) -> bool { unsafe { from_glib(ffi::g_variant_dict_contains( self.to_glib_none().0, key.to_glib_none().0, )) } } /// Look up a typed value from this `VariantDict`. /// /// The given `key` is looked up in `self`. /// /// This will return `None` if the `key` is not present in the dictionary, /// and an error if the key is present but with the wrong type. #[doc(alias = "g_variant_dict_lookup")] pub fn lookup(&self, key: &str) -> Result, VariantTypeMismatchError> { self.lookup_value(key, None) .map(|v| Variant::try_get(&v)) .transpose() } /// Look up and return a value from this `VariantDict`. /// /// The given `key` is looked up in `self`. If `expected_type` is not /// `None` then it will be matched against the type of any found value. /// /// This will return `None` if the `key` is not present in the dictionary /// or if it is present but the type of the value does not match a given /// `expected_type`. Otherwise, `Some(value)` will be returned where /// the `value` is an instance of [`Variant`](variant/struct.Variant.html). #[doc(alias = "g_variant_dict_lookup_value")] pub fn lookup_value(&self, key: &str, expected_type: Option<&VariantTy>) -> Option { unsafe { from_glib_full(ffi::g_variant_dict_lookup_value( self.to_glib_none().0, key.to_glib_none().0, expected_type.to_glib_none().0, )) } } /// Insert a variant into the dictionary. /// /// The given `key`/`value` pair is inserted into `self`. If a value /// was previously associated with `key` then it is overwritten. /// /// For convenience, you may use the [`insert()`](#method.insert) if /// you have a value which implements [`ToVariant`](variant/trait.ToVariant.html). #[doc(alias = "g_variant_dict_insert_value")] pub fn insert_value(&self, key: &str, value: &Variant) { unsafe { ffi::g_variant_dict_insert_value( self.to_glib_none().0, key.to_glib_none().0, value.to_glib_none().0, ) } } /// Insert a value into the dictionary /// /// The given `key`/`value` pair is inserted into `self`. If a value /// was previously associated with `key` then it is overwritten. /// /// This is a convenience method which automatically calls /// [`to_variant()`](variant/trait.ToVariant.html#method.to_variant) for you /// on the given value. /// /// If, on the other hand, you have a [`Variant`](variant/struct.Variant.html) /// instance already, you should use the [`insert_value()`](#method.insert_value) /// method instead. #[doc(alias = "g_variant_dict_insert_value")] pub fn insert(&self, key: &str, value: &T) { unsafe { ffi::g_variant_dict_insert_value( self.to_glib_none().0, key.to_glib_none().0, value.to_variant().to_glib_none().0, ) } } /// Remove the given `key` from the dictionary. /// /// This removes the given `key` from the dictionary, releasing the reference /// on the associated value if one is present. /// /// If a `key`/`value` pair was removed from the dictionary, `true` is /// returned. If `key` was not present then `false` is returned instead. #[doc(alias = "g_variant_dict_remove")] pub fn remove(&self, key: &str) -> bool { unsafe { from_glib(ffi::g_variant_dict_remove( self.to_glib_none().0, key.to_glib_none().0, )) } } /// Convert this dictionary to a [`Variant`](variant/struct.Variant.html) /// /// This method converts `self` into an instance of [`Variant`](variant/struct.Variant.html) /// but in doing so renders it very unsafe to use. /// /// # Safety /// /// After calling this, the underlying `GVariantDict` is in a state where /// the only valid operations to perform as reference ones. As such /// any attempt to read/update the dictionary *will* fail and emit warnings /// of such. /// /// You should only use this function if the extra cost of the safe function /// is too much for your performance critical codepaths pub unsafe fn end_unsafe(&self) -> Variant { from_glib_none(ffi::g_variant_dict_end(self.to_glib_none().0)) } /// Convert this dictionary to a [`Variant`](variant/struct.Variant.html) /// /// This method converts `self` into an instance of [`Variant`](variant/struct.Variant.html) /// and then reinitialises itself in order to be safe for further use. /// /// If you are certain that nothing other than disposing of references will /// be done after ending the instance, you can call the /// [`end_unsafe()`](#method.end_unsafe) method instead to avoid the unnecessary /// reinitialisation of the dictionary. pub fn end(&self) -> Variant { unsafe { let ret = self.end_unsafe(); // Reinitialise the dict so that we can continue safely ffi::g_variant_dict_init(self.to_glib_none().0, None::.to_glib_none().0); ret } } } impl Default for VariantDict { fn default() -> Self { Self::new(None) } } impl StaticVariantType for VariantDict { fn static_variant_type() -> Cow<'static, VariantTy> { unsafe { VariantTy::from_str_unchecked("a{sv}").into() } } } impl ToVariant for VariantDict { fn to_variant(&self) -> Variant { self.end() } } impl FromVariant for VariantDict { fn from_variant(variant: &Variant) -> Option { if variant.type_() == VariantDict::static_variant_type() { Some(Self::new(Some(variant))) } else { None } } } impl From for VariantDict { fn from(other: Variant) -> Self { Self::new(Some(&other)) } } #[cfg(test)] mod test { use super::*; #[test] fn create_destroy() { let _dict = VariantDict::new(None); } #[test] fn create_roundtrip() { let dict = VariantDict::default(); let var: Variant = dict.to_variant(); let _dict2: VariantDict = var.into(); } #[test] fn create_populate_destroy() { let dict = VariantDict::default(); dict.insert_value("one", &(1u8.to_variant())); assert_eq!(dict.lookup_value("one", None), Some(1u8.to_variant())); } #[test] fn create_populate_roundtrip() { let dict = VariantDict::default(); dict.insert_value("one", &(1u8.to_variant())); let var: Variant = dict.to_variant(); let dict = VariantDict::from_variant(&var).expect("Not a dict?"); assert_eq!(dict.lookup_value("one", None), Some(1u8.to_variant())); } #[test] fn lookup() -> Result<(), Box> { let dict = VariantDict::default(); dict.insert_value("one", &(1u8.to_variant())); assert_eq!(dict.lookup::("one")?.unwrap(), 1u8); assert_eq!( dict.lookup::("one").err().unwrap().actual, u8::static_variant_type() ); assert!(dict.lookup::("two")?.is_none()); Ok(()) } #[test] fn create_populate_remove() { let dict = VariantDict::default(); let empty_var = dict.to_variant(); dict.insert("one", &1u64); assert!(dict.remove("one")); assert!(!dict.remove("one")); let var2 = dict.to_variant(); assert_eq!(empty_var, var2); } } glib-0.14.8/src/variant_iter.rs000064400000000000000000000111350072674642500145100ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // This is similar to the GVariantIter provided by glib, but that would // introduce a heap allocation and doesn't provide a way to determine how // many items are left in the iterator. use std::iter::{DoubleEndedIterator, ExactSizeIterator, Iterator}; use crate::translate::*; use crate::variant::Variant; /// Iterator over items in a variant. #[derive(Debug)] pub struct VariantIter { variant: Variant, head: usize, tail: usize, } impl VariantIter { pub(crate) fn new(variant: Variant) -> Self { let tail = variant.n_children(); Self { variant, head: 0, tail, } } } impl Iterator for VariantIter { type Item = Variant; fn next(&mut self) -> Option { if self.head == self.tail { None } else { let value = self.variant.child_value(self.head); self.head += 1; Some(value) } } fn size_hint(&self) -> (usize, Option) { let size = self.tail - self.head; (size, Some(size)) } } impl DoubleEndedIterator for VariantIter { fn next_back(&mut self) -> Option { if self.head == self.tail { None } else { self.tail -= 1; Some(self.variant.child_value(self.tail)) } } } impl ExactSizeIterator for VariantIter {} /// Iterator over items in a variant of type `as`. #[derive(Debug)] pub struct VariantStrIter<'a> { variant: &'a Variant, head: usize, tail: usize, } impl<'a> VariantStrIter<'a> { pub(crate) fn new(variant: &'a Variant) -> Self { let tail = variant.n_children(); Self { variant, head: 0, tail, } } fn impl_get(&self, i: usize) -> &'a str { unsafe { let p: *mut libc::c_char = std::ptr::null_mut(); let s = b"&s\0"; ffi::g_variant_get_child( self.variant.to_glib_none().0, i, s as *const u8 as *const _, &p, std::ptr::null::(), ); let p = std::ffi::CStr::from_ptr(p); p.to_str().unwrap() } } } impl<'a> Iterator for VariantStrIter<'a> { type Item = &'a str; fn next(&mut self) -> Option<&'a str> { if self.head == self.tail { None } else { let v = self.impl_get(self.head); self.head += 1; Some(v) } } fn size_hint(&self) -> (usize, Option) { let size = self.tail - self.head; (size, Some(size)) } } impl<'a> DoubleEndedIterator for VariantStrIter<'a> { fn next_back(&mut self) -> Option<&'a str> { if self.head == self.tail { None } else { self.tail -= 1; Some(self.impl_get(self.tail)) } } } impl<'a> ExactSizeIterator for VariantStrIter<'a> {} #[cfg(test)] mod tests { use crate::prelude::*; use crate::variant::{DictEntry, Variant}; use std::collections::HashMap; #[test] fn test_variant_iter_variant() { let v = Variant::from_variant(&"foo".to_string().to_variant()); let vec: Vec = v.iter().map(|i| i.get().unwrap()).collect(); assert_eq!(vec, vec!["foo".to_string()]); } #[test] fn test_variant_iter_array() { let v = Variant::from_array::(&[ "foo".to_string().to_variant(), "bar".to_string().to_variant(), ]); let vec: Vec = v.iter().map(|i| i.get().unwrap()).collect(); let a = vec!["foo".to_string(), "bar".to_string()]; assert_eq!(&vec, &a); let vec: Vec<_> = v.array_iter_str().unwrap().collect(); assert_eq!(&vec, &a); } #[test] fn test_variant_iter_tuple() { let v = Variant::from_tuple(&[ "foo".to_string().to_variant(), "bar".to_string().to_variant(), ]); let vec: Vec = v.iter().map(|i| i.get().unwrap()).collect(); assert_eq!(vec, vec!["foo".to_string(), "bar".to_string()]); } #[test] fn test_variant_iter_dictentry() { let v = DictEntry::new("foo", 1337).to_variant(); println!("{:?}", v.iter().collect::>()); assert_eq!(v.iter().count(), 2); } #[test] fn test_variant_iter_map() { let mut map = HashMap::new(); map.insert("foo", 1); map.insert("bar", 1); let v = map.to_variant(); assert_eq!(v.iter().count(), 2); } } glib-0.14.8/src/variant_type.rs000064400000000000000000000345440072674642500145370ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::*; use crate::types::StaticType; use crate::types::Type; use crate::BoolError; use std::borrow::{Borrow, Cow, ToOwned}; use std::cmp::{Eq, PartialEq}; use std::fmt; use std::hash::{Hash, Hasher}; use std::ops::Deref; use std::slice; /// Describes `Variant` types. /// /// The `Variant` type system (based on the D-Bus one) describes types with /// "type strings". `VariantType` is an owned immutable type string (you can /// think of it as a `Box` statically guaranteed to be a valid type /// string), `&VariantTy` is a borrowed one (like `&str`). #[doc(alias = "GVariantType")] pub struct VariantType { // GVariantType* essentially is a char*, that always is valid UTF-8 but // isn't NUL-terminated. ptr: *mut ffi::GVariantType, // We query the length on creation assuming it's cheap (because type strings // are short) and likely to happen anyway. len: usize, } impl VariantType { /// Tries to create a `VariantType` from a string slice. /// /// Returns `Ok` if the string is a valid type string, `Err` otherwise. pub fn new(type_string: &str) -> Result { VariantTy::new(type_string).map(ToOwned::to_owned) } } unsafe impl Send for VariantType {} unsafe impl Sync for VariantType {} impl Drop for VariantType { fn drop(&mut self) { unsafe { ffi::g_variant_type_free(self.ptr) } } } impl Borrow for VariantType { fn borrow(&self) -> &VariantTy { self } } impl Clone for VariantType { fn clone(&self) -> VariantType { unsafe { VariantType { ptr: ffi::g_variant_type_copy(self.ptr), len: self.len, } } } } impl Deref for VariantType { type Target = VariantTy; fn deref(&self) -> &VariantTy { unsafe { &*(slice::from_raw_parts(self.ptr as *const u8, self.len) as *const [u8] as *const VariantTy) } } } impl fmt::Debug for VariantType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, f) } } impl fmt::Display for VariantType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.to_str()) } } impl Hash for VariantType { fn hash(&self, state: &mut H) { ::hash(self, state) } } impl<'a> From for Cow<'a, VariantTy> { fn from(ty: VariantType) -> Cow<'a, VariantTy> { Cow::Owned(ty) } } #[doc(hidden)] impl<'a> ToGlibPtr<'a, *const ffi::GVariantType> for VariantType { type Storage = &'a Self; fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GVariantType, Self> { Stash(self.ptr, self) } fn to_glib_full(&self) -> *const ffi::GVariantType { unsafe { ffi::g_variant_type_copy(self.ptr) } } } #[doc(hidden)] impl<'a> ToGlibPtr<'a, *mut ffi::GVariantType> for VariantType { type Storage = &'a Self; fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GVariantType, Self> { Stash(self.ptr, self) } fn to_glib_full(&self) -> *mut ffi::GVariantType { unsafe { ffi::g_variant_type_copy(self.ptr) } } } #[doc(hidden)] impl<'a> ToGlibPtrMut<'a, *mut ffi::GVariantType> for VariantType { type Storage = &'a mut Self; fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GVariantType, Self> { StashMut(self.ptr, self) } } #[doc(hidden)] impl FromGlibPtrNone<*const ffi::GVariantType> for VariantType { unsafe fn from_glib_none(ptr: *const ffi::GVariantType) -> VariantType { VariantTy::from_ptr(ptr).to_owned() } } #[doc(hidden)] impl FromGlibPtrFull<*const ffi::GVariantType> for VariantType { unsafe fn from_glib_full(ptr: *const ffi::GVariantType) -> VariantType { // Don't assume ownership of a const pointer. // A transfer: full annotation on a `const GVariantType*` is likely a bug. VariantTy::from_ptr(ptr).to_owned() } } /// Describes `Variant` types. /// /// This is a borrowed counterpart of [`VariantType`](struct.VariantType.html). /// Essentially it's a `str` statically guaranteed to be a valid type string. #[derive(Debug, PartialEq, Eq, Hash)] pub struct VariantTy { inner: str, } impl VariantTy { /// An indefinite type that is a supertype of every type (including itself). #[doc(alias = "G_VARIANT_TYPE_ANY")] pub const ANY: &'static VariantTy = unsafe { std::mem::transmute::<&str, &VariantTy>("*") }; /// Tries to create a `&VariantTy` from a string slice. /// /// Returns `Ok` if the string is a valid type string, `Err` otherwise. pub fn new(type_string: &str) -> Result<&VariantTy, BoolError> { let ptr = type_string.as_ptr(); let limit = ptr as usize + type_string.len(); let mut end = 0_usize; unsafe { let ok = from_glib(ffi::g_variant_type_string_scan( ptr as *const _, limit as *const _, &mut end as *mut usize as *mut _, )); if ok && end == limit { Ok(&*(type_string.as_bytes() as *const [u8] as *const VariantTy)) } else { Err(bool_error!("Invalid type string: '{}'", type_string)) } } } /// Converts a type string into `&VariantTy` without any checks. /// /// # Safety /// /// The caller is responsible for passing in only a valid variant type string /// which is already registered with the type system. pub unsafe fn from_str_unchecked(type_string: &str) -> &VariantTy { &*(type_string as *const str as *const VariantTy) } /// Creates `&VariantTy` with a wildcard lifetime from a `GVariantType` /// pointer. #[doc(hidden)] pub unsafe fn from_ptr<'a>(ptr: *const ffi::GVariantType) -> &'a VariantTy { let len = ffi::g_variant_type_get_string_length(ptr) as usize; &*(slice::from_raw_parts(ptr as *const u8, len) as *const [u8] as *const VariantTy) } /// Returns a `GVariantType` pointer. #[doc(hidden)] pub fn as_ptr(&self) -> *const ffi::GVariantType { self.inner.as_ptr() as *const _ } /// Converts to a string slice. pub fn to_str(&self) -> &str { &self.inner } /// Return this type as an array. pub(crate) fn with_array(&self) -> VariantType { VariantType::new(&format!("a{}", self.to_str())).expect("invalid variant signature") } } unsafe impl Sync for VariantTy {} #[doc(hidden)] impl<'a> ToGlibPtr<'a, *const ffi::GVariantType> for VariantTy { type Storage = &'a Self; fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GVariantType, Self> { Stash(self.as_ptr(), self) } } impl fmt::Display for VariantTy { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.to_str()) } } impl<'a> From<&'a VariantTy> for Cow<'a, VariantTy> { fn from(ty: &'a VariantTy) -> Cow<'a, VariantTy> { Cow::Borrowed(ty) } } impl ToOwned for VariantTy { type Owned = VariantType; fn to_owned(&self) -> VariantType { unsafe { VariantType { ptr: ffi::g_variant_type_copy(self.as_ptr()), len: self.inner.len(), } } } } impl StaticType for VariantTy { fn static_type() -> Type { unsafe { from_glib(ffi::g_variant_type_get_gtype()) } } } #[doc(hidden)] unsafe impl<'a> crate::value::FromValue<'a> for &'a VariantTy { type Checker = crate::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a crate::Value) -> Self { let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0); assert!(!ptr.is_null()); VariantTy::from_ptr(ptr as *const ffi::GVariantType) } } #[doc(hidden)] impl crate::value::ToValue for VariantTy { fn to_value(&self) -> crate::Value { unsafe { let mut value = crate::Value::from_type(VariantTy::static_type()); gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, self.to_glib_none().0 as *mut _, ); value } } fn value_type(&self) -> crate::Type { VariantTy::static_type() } } #[doc(hidden)] impl crate::value::ToValue for &VariantTy { fn to_value(&self) -> crate::Value { (*self).to_value() } fn value_type(&self) -> crate::Type { VariantTy::static_type() } } #[doc(hidden)] impl crate::value::ToValueOptional for &VariantTy { fn to_value_optional(s: Option<&Self>) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, s.to_glib_none().0 as *mut _, ); } value } } impl StaticType for VariantType { fn static_type() -> Type { unsafe { from_glib(ffi::g_variant_type_get_gtype()) } } } #[doc(hidden)] impl crate::value::ValueType for VariantType { type Type = VariantType; } #[doc(hidden)] unsafe impl<'a> crate::value::FromValue<'a> for VariantType { type Checker = crate::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a crate::Value) -> Self { let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0); assert!(!ptr.is_null()); from_glib_none(ptr as *const ffi::GVariantType) } } #[doc(hidden)] impl crate::value::ToValue for VariantType { fn to_value(&self) -> crate::Value { unsafe { let mut value = crate::Value::from_type(VariantType::static_type()); gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, ToGlibPtr::<*mut _>::to_glib_none(&self).0 as *mut _, ); value } } fn value_type(&self) -> crate::Type { VariantType::static_type() } } #[doc(hidden)] impl crate::value::ToValueOptional for VariantType { fn to_value_optional(s: Option<&Self>) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, ToGlibPtr::<*mut _>::to_glib_none(&s).0 as *mut _, ); } value } } impl PartialEq for VariantType { #[inline] fn eq(&self, other: &Self) -> bool { ::eq(self, other) } } macro_rules! impl_eq { ($lhs:ty, $rhs: ty) => { impl<'a, 'b> PartialEq<$rhs> for $lhs { #[inline] fn eq(&self, other: &$rhs) -> bool { ::eq(self, other) } } impl<'a, 'b> PartialEq<$lhs> for $rhs { #[inline] fn eq(&self, other: &$lhs) -> bool { ::eq(self, other) } } }; } impl_eq!(VariantType, VariantTy); impl_eq!(VariantType, &'a VariantTy); impl_eq!(VariantType, Cow<'a, VariantTy>); impl_eq!(&'a VariantTy, Cow<'b, VariantTy>); macro_rules! impl_str_eq { ($lhs:ty, $rhs: ty) => { #[allow(clippy::redundant_slicing)] impl<'a, 'b> PartialEq<$rhs> for $lhs { #[inline] fn eq(&self, other: &$rhs) -> bool { self.to_str().eq(&other[..]) } } impl<'a, 'b> PartialEq<$lhs> for $rhs { #[inline] fn eq(&self, other: &$lhs) -> bool { self[..].eq(other.to_str()) } } }; } impl_str_eq!(VariantTy, str); impl_str_eq!(VariantTy, &'a str); impl_str_eq!(&'a VariantTy, str); impl_str_eq!(VariantTy, String); impl_str_eq!(&'a VariantTy, String); impl_str_eq!(VariantType, str); impl_str_eq!(VariantType, &'a str); impl_str_eq!(VariantType, String); impl Eq for VariantType {} #[cfg(test)] mod tests { use super::*; use crate::ToValue; unsafe fn equal(ptr1: *const T, ptr2: *const U) -> bool { from_glib(ffi::g_variant_type_equal( ptr1 as *const _, ptr2 as *const _, )) } #[test] fn new() { let ty = VariantTy::new("((iii)s)").unwrap(); unsafe { assert!(equal(ty.as_ptr(), b"((iii)s)\0" as *const u8)); } } #[test] fn new_empty() { assert!(VariantTy::new("").is_err()); } #[test] fn new_with_nul() { assert!(VariantTy::new("((iii\0)s)").is_err()); } #[test] fn new_too_short() { assert!(VariantTy::new("((iii").is_err()); } #[test] fn new_too_long() { assert!(VariantTy::new("(iii)s").is_err()); } #[test] fn eq() { let ty1 = VariantTy::new("((iii)s)").unwrap(); let ty2 = VariantTy::new("((iii)s)").unwrap(); assert_eq!(ty1, ty2); assert_eq!(ty1, "((iii)s)"); unsafe { assert!(equal(ty1.as_ptr(), ty2.as_ptr())); } } #[test] fn ne() { let ty1 = VariantTy::new("((iii)s)").unwrap(); let ty2 = VariantTy::new("((iii)o)").unwrap(); assert_ne!(ty1, ty2); assert_ne!(ty1, "((iii)o)"); unsafe { assert!(!equal(ty1.as_ptr(), ty2.as_ptr())); } } #[test] fn from_bytes() { unsafe { let ty = VariantTy::from_ptr(b"((iii)s)" as *const u8 as *const _); assert_eq!(ty, "((iii)s)"); assert!(equal(ty.as_ptr(), "((iii)s)".as_ptr())); } } #[test] fn to_owned() { let ty1 = VariantTy::new("((iii)s)").unwrap(); let ty2 = ty1.to_owned(); assert_eq!(ty1, ty2); assert_eq!(ty2, "((iii)s)"); unsafe { assert!(equal(ty1.as_ptr(), ty2.as_ptr())); } } #[test] fn value() { let ty1 = VariantType::new("*").unwrap(); let tyv = ty1.to_value(); let ty2 = tyv.get::().unwrap(); assert_eq!(ty1, ty2); let ty3 = VariantTy::new("*").unwrap(); let tyv2 = ty3.to_value(); let ty4 = tyv2.get::().unwrap(); assert_eq!(ty3, ty4); let ty5 = VariantTy::ANY; let tyv3 = ty5.to_value(); let ty6 = tyv3.get::().unwrap(); assert_eq!(ty5, ty6); } #[test] fn type_() { assert_eq!(VariantTy::static_type(), VariantType::static_type()) } } glib-0.14.8/src/win32.rs000064400000000000000000000006770072674642500127740ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::*; use std::path::PathBuf; #[doc(alias = "g_win32_get_package_installation_directory_of_module")] pub fn win32_get_package_installation_directory_of_module( hmodule: ffi::gpointer, ) -> Option { unsafe { from_glib_full(ffi::g_win32_get_package_installation_directory_of_module( hmodule, )) } } glib-0.14.8/src/wrapper.rs000064400000000000000000000445220072674642500135070ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. //! `IMPL` The `wrapper!` macro and miscellaneous wrapper traits. /// Defines a wrapper type and implements the appropriate traits. /// /// The basic syntax is /// /// ```ignore /// wrapper! { /// /// Your documentation goes here /// pub struct $name($kind<$foreign>); /// /// match fn { /// $fn_name => /* a closure-like expression */, /// ... /// } /// } /// ``` /// /// This creates a wrapper named `$name` around the foreign type /// `$foreign` of `$kind` — one of [`Boxed`][#boxed], /// [`Shared`][#shared], or [`Object`][#object]. /// /// Inside the `match fn` block there are closure-like expressions to /// provide ways of copying/freeing, or referencing/unreferencing the /// value that you are wrapping. These expressions will be evaluated /// in an `unsafe` context, since they frequently invoke `extern` /// functions from an FFI crate. /// /// What follows is a description of each of the possible `$kind`: /// [`Boxed`][#boxed], [`Shared`][#shared], and [`Object`][#object]; /// note that each supports different sets of `$fn_name` inside the /// `match fn` block. Also, `Object` may require you to specify /// things like the class struct to wrap, plus any interfaces that the /// class implements. /// /// ### Boxed /// /// Boxed records with single ownership. /// /// With no registered `glib_ffi::GType`: /// /// ```ignore /// wrapper! { /// /// Text buffer iterator /// pub struct TextIter(Boxed); /// /// match fn { /// copy => |ptr| ffi::gtk_text_iter_copy(ptr), /// free => |ptr| ffi::gtk_text_iter_free(ptr), /// } /// } /// ``` /// /// `copy`: `|*const $foreign| -> *mut $foreign` creates a copy of the value. /// /// `free`: `|*mut $foreign|` frees the value. /// /// With a registered `glib_ffi::GType`: /// /// ```ignore /// wrapper! { /// /// Text buffer iterator /// pub struct TextIter(Boxed); /// /// match fn { /// copy => |ptr| ffi::gtk_text_iter_copy(ptr), /// free => |ptr| ffi::gtk_text_iter_free(ptr), /// type_ => || ffi::gtk_text_iter_get_type(), /// } /// } /// ``` /// /// `type_`: `|| -> glib_ffi::GType` (optional) returns the /// `glib_ffi::GType` that corresponds to the foreign struct. /// /// ### Shared /// /// Records with reference-counted, shared ownership. /// /// With no registered `glib_ffi::GType`: /// /// ```ignore /// wrapper! { /// /// Object holding timing information for a single frame. /// pub struct FrameTimings(Shared); /// /// match fn { /// ref => |ptr| ffi::gdk_frame_timings_ref(ptr), /// unref => |ptr| ffi::gdk_frame_timings_unref(ptr), /// } /// } /// ``` /// /// `ref`: `|*mut $foreign|` increases the refcount. /// /// `unref`: `|*mut $foreign|` decreases the refcount. /// /// With a registered `glib_ffi::GType`: /// /// ```ignore /// wrapper! { /// /// Object holding timing information for a single frame. /// pub struct FrameTimings(Shared); /// /// match fn { /// ref => |ptr| ffi::gdk_frame_timings_ref(ptr), /// unref => |ptr| ffi::gdk_frame_timings_unref(ptr), /// type_ => || ffi::gdk_frame_timings_get_type(), /// } /// } /// ``` /// /// `type_`: `|| -> glib_ffi::GType` (optional) returns the /// `glib_ffi::GType` that corresponds to the foreign struct. /// /// ### Object /// /// Objects -- classes. Note that the class name, if available, must be specified after the /// $foreign type; see below for [non-derivable classes][#non-derivable-classes]. /// /// The basic syntax is this: /// /// ```ignore /// wrapper! { /// /// Your documentation goes here /// pub struct InstanceName(Object) /// @extends ParentClass, GrandparentClass, ..., /// @implements Interface1, Interface2, ...; /// /// match fn { /// type_ => || ffi::instance_get_type(), /// } /// } /// ``` /// /// `type_`: `|| -> glib_ffi::GType` returns the `glib_ffi::GType` /// that corresponds to the foreign class. /// /// #### All parent classes must be specified /// /// In the example above, "`@extends ParentClass, GrandparentClass, ...,`" is where you must /// specify all the parent classes of the one you are wrapping. The uppermost parent class, /// `glib::Object`, must not be specified. /// /// For example, `ffi::GtkWindowGroup` derives directly from /// `GObject`, so it can be simply wrapped as follows: /// /// ```ignore /// wrapper! { /// pub struct WindowGroup(Object); /// /// match fn { /// type_ => || ffi::gtk_window_group_get_type(), /// } /// } /// ``` /// /// In contrast, `ffi::GtkButton` has a parent, grandparent, etc. classes, which must be specified: /// /// ```ignore /// wrapper! { /// pub struct Button(Object) @extends Bin, Container, Widget; /// // see note on interfaces in the example below /// /// match fn { /// type_ => || ffi::gtk_button_get_type(), /// } /// } /// ``` /// /// #### Objects which implement interfaces /// /// The example above is incomplete, since `ffi::GtkButton` actually implements two interfaces, /// `Buildable` and `Actionable`. In this case, they must be specified after all the parent classes /// behind the `@implements` keyword: /// /// ```ignore /// wrapper! { /// pub struct Button(Object) /// @extends Bin, Container, Widget, // parent classes /// @implements Buildable, Actionable; // interfaces /// /// match fn { /// type_ => || ffi::gtk_button_get_type(), /// } /// } /// ``` /// /// #### Non-derivable classes /// /// By convention, GObject implements "final" classes, i.e. those who /// cannot be subclassed, by *not* exposing a public Class struct. /// This way it is not possible to override any methods, as there are /// no `klass.method_name` fields to overwrite. In this case, don't /// specify a FFI class name at all in the `Object<>` part: /// /// ```ignore /// wrapper! { /// pub struct Clipboard(Object); /// ... /// } /// ``` /// /// #### Interfaces /// /// Interfaces are passed in the same way to the macro but instead of specifying /// `Object`, `Interface` has to be specified: /// /// ```ignore /// wrapper! { /// pub struct TreeModel(Interface); /// ... /// } /// ``` /// /// #### Interfaces with prerequisites /// /// Interfaces can declare prerequisites, i.e. the classes from which types that implement the /// interface have to inherit or interfaces that have to be implemented: /// /// ```ignore /// wrapper! { /// pub struct TreeSortable(Interface) @requires TreeModel; /// ... /// } /// ``` /// /// [#boxed]: #boxed /// [#shared]: #shared /// [#object]: #object /// [#non-derivable-classes]: #non-derivable-classes #[macro_export] macro_rules! wrapper { // Boxed ( $(#[$attr:meta])* pub struct $name:ident(Boxed<$ffi_name:ty>); match fn { copy => |$copy_arg:ident| $copy_expr:expr, free => |$free_arg:ident| $free_expr:expr, } ) => { $crate::glib_boxed_wrapper!([$($attr)*] $name, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr); }; ( $(#[$attr:meta])* pub struct $name:ident(Boxed<$ffi_name:ty>); match fn { copy => |$copy_arg:ident| $copy_expr:expr, free => |$free_arg:ident| $free_expr:expr, type_ => || $get_type_expr:expr, } ) => { $crate::glib_boxed_wrapper!([$($attr)*] $name, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr, @type_ $get_type_expr); }; ( $(#[$attr:meta])* pub struct $name:ident(Boxed<$ffi_name:ty>); match fn { copy => |$copy_arg:ident| $copy_expr:expr, free => |$free_arg:ident| $free_expr:expr, init => |$init_arg:ident| $init_expr:expr, clear => |$clear_arg:ident| $clear_expr:expr, } ) => { $crate::glib_boxed_wrapper!([$($attr)*] $name, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr, @init $init_arg $init_expr, @clear $clear_arg $clear_expr); }; ( $(#[$attr:meta])* pub struct $name:ident(Boxed<$ffi_name:ty>); match fn { copy => |$copy_arg:ident| $copy_expr:expr, free => |$free_arg:ident| $free_expr:expr, init => |$init_arg:ident| $init_expr:expr, clear => |$clear_arg:ident| $clear_expr:expr, type_ => || $get_type_expr:expr, } ) => { $crate::glib_boxed_wrapper!([$($attr)*] $name, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr, @init $init_arg $init_expr, @clear $clear_arg $clear_expr, @type_ $get_type_expr); }; // Shared ( $(#[$attr:meta])* pub struct $name:ident(Shared<$ffi_name:ty>); match fn { ref => |$ref_arg:ident| $ref_expr:expr, unref => |$unref_arg:ident| $unref_expr:expr, } ) => { $crate::glib_shared_wrapper!([$($attr)*] $name, $ffi_name, @ref $ref_arg $ref_expr, @unref $unref_arg $unref_expr); }; ( $(#[$attr:meta])* pub struct $name:ident(Shared<$ffi_name:ty>); match fn { ref => |$ref_arg:ident| $ref_expr:expr, unref => |$unref_arg:ident| $unref_expr:expr, type_ => || $get_type_expr:expr, } ) => { $crate::glib_shared_wrapper!([$($attr)*] $name, $ffi_name, @ref $ref_arg $ref_expr, @unref $unref_arg $unref_expr, @type_ $get_type_expr); }; // Object, no class struct, no parents or interfaces ( $(#[$attr:meta])* pub struct $name:ident(Object<$ffi_name:ty>); match fn { type_ => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, std::os::raw::c_void, @type_ $get_type_expr, @extends [], @implements []); }; // Object, class struct, no parents or interfaces ( $(#[$attr:meta])* pub struct $name:ident(Object<$ffi_name:ty, $ffi_class_name:ty>); match fn { type_ => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $ffi_class_name, @type_ $get_type_expr, @extends [], @implements []); }; // Object, no class struct, parents, no interfaces ( $(#[$attr:meta])* pub struct $name:ident(Object<$ffi_name:ty>) @extends $($extends:path),+; match fn { type_ => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, std::os::raw::c_void, @type_ $get_type_expr, @extends [$($extends),+], @implements []); }; // Object, class struct, parents, no interfaces ( $(#[$attr:meta])* pub struct $name:ident(Object<$ffi_name:ty, $ffi_class_name:ty>) @extends $($extends:path),+; match fn { type_ => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $ffi_class_name, @type_ $get_type_expr, @extends [$($extends),+], @implements []); }; // Object, no class struct, no parents, interfaces ( $(#[$attr:meta])* pub struct $name:ident(Object<$ffi_name:ty>) @implements $($implements:path),+; match fn { type_ => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, std::os::raw::c_void, @type_ $get_type_expr, @extends [], @implements [$($implements),+]); }; // Object, class struct, no parents, interfaces ( $(#[$attr:meta])* pub struct $name:ident(Object<$ffi_name:ty, $ffi_class_name:ty>) @implements $($implements:path),+; match fn { type_ => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $ffi_class_name, @type_ $get_type_expr, @extends [], @implements [$($implements),+]); }; // Object, no class struct, parents and interfaces ( $(#[$attr:meta])* pub struct $name:ident(Object<$ffi_name:ty>) @extends $($extends:path),+, @implements $($implements:path),+; match fn { type_ => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, std::os::raw::c_void, @type_ $get_type_expr, @extends [$($extends),+], @implements [$($implements),+]); }; // Object, class struct, parents and interfaces ( $(#[$attr:meta])* pub struct $name:ident(Object<$ffi_name:ty, $ffi_class_name:ty>) @extends $($extends:path),+, @implements $($implements:path),+; match fn { type_ => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $ffi_class_name, @type_ $get_type_expr, @extends [$($extends),+], @implements [$($implements),+]); }; // ObjectSubclass, no parents or interfaces ( $(#[$attr:meta])* pub struct $name:ident(ObjectSubclass<$subclass:ty>); ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, <$subclass as $crate::subclass::types::ObjectSubclass>::Instance, <$subclass as $crate::subclass::types::ObjectSubclass>::Class, @type_ $crate::translate::IntoGlib::into_glib(<$subclass as $crate::subclass::types::ObjectSubclassType>::type_()), @extends [], @implements []); unsafe impl $crate::object::ObjectSubclassIs for $name { type Subclass = $subclass; } }; // ObjectSubclass, no parents, interfaces ( $(#[$attr:meta])* pub struct $name:ident(ObjectSubclass<$subclass:ty>) @implements $($implements:path),+; ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, <$subclass as $crate::subclass::types::ObjectSubclass>::Instance, <$subclass as $crate::subclass::types::ObjectSubclass>::Class, @type_ $crate::translate::IntoGlib::into_glib(<$subclass as $crate::subclass::types::ObjectSubclassType>::type_()), @extends [], @implements [$($implements),+]); unsafe impl $crate::object::ObjectSubclassIs for $name { type Subclass = $subclass; } }; // ObjectSubclass, parents, no interfaces ( $(#[$attr:meta])* pub struct $name:ident(ObjectSubclass<$subclass:ty>) @extends $($extends:path),+; ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, <$subclass as $crate::subclass::types::ObjectSubclass>::Instance, <$subclass as $crate::subclass::types::ObjectSubclass>::Class, @type_ $crate::translate::IntoGlib::into_glib(<$subclass as $crate::subclass::types::ObjectSubclassType>::type_()), @extends [$($extends),+], @implements []); unsafe impl $crate::object::ObjectSubclassIs for $name { type Subclass = $subclass; } }; // ObjectSubclass, parents and interfaces ( $(#[$attr:meta])* pub struct $name:ident(ObjectSubclass<$subclass:ty>) @extends $($extends:path),+, @implements $($implements:path),+; ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, <$subclass as $crate::subclass::types::ObjectSubclass>::Instance, <$subclass as $crate::subclass::types::ObjectSubclass>::Class, @type_ $crate::translate::IntoGlib::into_glib(<$subclass as $crate::subclass::types::ObjectSubclassType>::type_()), @extends [$($extends),+], @implements [$($implements),+]); unsafe impl $crate::object::ObjectSubclassIs for $name { type Subclass = $subclass; } }; // Interface, no prerequisites, no class ( $(#[$attr:meta])* pub struct $name:ident(Interface<$ffi_name:ty>); match fn { type_ => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@interface [$($attr)*] $name, $ffi_name, std::os::raw::c_void, @type_ $get_type_expr, @requires []); }; // Interface, prerequisites, no class ( $(#[$attr:meta])* pub struct $name:ident(Interface<$ffi_name:ty>) @requires $($requires:path),+; match fn { type_ => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@interface [$($attr)*] $name, $ffi_name, std::os::raw::c_void, @type_ $get_type_expr, @requires [$($requires),+]); }; // Interface, no prerequisites, class ( $(#[$attr:meta])* pub struct $name:ident(Interface<$ffi_name:ty, $ffi_class_name:ty>); match fn { type_ => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@interface [$($attr)*] $name, $ffi_name, $ffi_class_name, @type_ $get_type_expr, @requires []); }; // Interface, prerequisites, class ( $(#[$attr:meta])* pub struct $name:ident(Interface<$ffi_name:ty, $ffi_class_name:ty>) @requires $($requires:path),+; match fn { type_ => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@interface [$($attr)*] $name, $ffi_name, $ffi_class_name, @type_ $get_type_expr, @requires [$($requires),+]); }; // ObjectInterface, no prerequisites ( $(#[$attr:meta])* pub struct $name:ident(ObjectInterface<$iface_name:ty>); ) => { $crate::glib_object_wrapper!(@interface [$($attr)*] $name, std::os::raw::c_void, $iface_name, @type_ $crate::translate::IntoGlib::into_glib(<$iface_name as $crate::subclass::interface::ObjectInterfaceType>::type_()), @requires []); }; // ObjectInterface, prerequisites ( $(#[$attr:meta])* pub struct $name:ident(ObjectInterface<$iface_name:ty>) @requires $($requires:path),+; ) => { $crate::glib_object_wrapper!(@interface [$($attr)*] $name, std::os::raw::c_void, $iface_name, @type_ $crate::translate::IntoGlib::into_glib(<$iface_name as $crate::subclass::interface::ObjectInterfaceType>::type_()), @requires [$($requires),+]); }; } glib-0.14.8/tests/clone.rs000064400000000000000000000465630072674642500135110ustar 00000000000000use std::cell::RefCell; use std::panic; use std::rc::Rc; use std::sync::{Arc, Mutex}; use std::thread; use futures_executor::block_on; use glib::clone; struct State { count: i32, started: bool, } impl State { fn new() -> Self { Self { count: 0, started: false, } } } #[test] fn clone_and_references() { let state = Rc::new(RefCell::new(State::new())); let ref_state = &state; assert!(!ref_state.borrow().started); let closure = { clone!(@weak ref_state => move || { ref_state.borrow_mut().started = true; }) }; closure(); assert!(ref_state.borrow().started); } #[test] fn subfields_renaming() { struct Foo { v: Rc, } impl Foo { fn foo(&self) { let state = Rc::new(RefCell::new(State::new())); let closure = clone!(@strong self.v as v, @weak state as hello => move |_| { println!("v: {}", v); hello.borrow_mut().started = true; }); closure(2); } } Foo { v: Rc::new(0) }.foo(); } #[test] fn renaming() { let state = Rc::new(RefCell::new(State::new())); assert!(!state.borrow().started); let closure = { clone!(@weak state as hello => move || { hello.borrow_mut().started = true; }) }; closure(); assert!(state.borrow().started); } #[test] fn clone_closure() { let state = Rc::new(RefCell::new(State::new())); assert!(!state.borrow().started); let closure = { clone!(@weak state => move || { state.borrow_mut().started = true; }) }; closure(); assert!(state.borrow().started); assert_eq!(state.borrow().count, 0); let closure = { let state2 = Rc::new(RefCell::new(State::new())); assert!(state.borrow().started); clone!(@weak state, @strong state2 => move || { state.borrow_mut().count += 1; state.borrow_mut().started = true; state2.borrow_mut().started = true; }) }; closure(); assert_eq!(state.borrow().count, 1); assert!(state.borrow().started); } #[test] fn clone_default_value() { let closure = { let state = Rc::new(RefCell::new(State::new())); clone!(@weak state => @default-return 42, move |_| { state.borrow_mut().started = true; 10 }) }; assert_eq!(42, closure(50)); } #[test] fn clone_panic() { let state = Arc::new(Mutex::new(State::new())); state.lock().expect("Failed to lock state mutex").count = 20; let closure = { let state2 = Arc::new(Mutex::new(State::new())); clone!(@weak state2, @strong state => @default-return panic!(), move |_| { state.lock().expect("Failed to lock state mutex").count = 21; state2.lock().expect("Failed to lock state2 mutex").started = true; 10 }) }; let result = panic::catch_unwind(|| { closure(50); }); assert!(result.is_err()); assert_eq!(state.lock().expect("Failed to lock state mutex").count, 20); } #[test] fn clone_import_rename() { import_rename::test(); } mod import_rename { use glib::clone as clone_g; #[allow(unused_macros)] macro_rules! clone { ($($anything:tt)*) => { |_, _| panic!("The clone! macro doesn't support renaming") }; } #[allow(unused_variables)] pub fn test() { let n = 2; let closure: Box = Box::new(clone_g!( @strong n => move |_, _| println!("The clone! macro does support renaming") )); closure(0, 0); } } #[test] fn test_clone_macro_self_rename() { #[derive(Debug)] struct Foo { v: u8, } impl Foo { #[allow(dead_code)] fn foo(&self) { let closure = clone!(@strong self as this => move |_x| { println!("v: {:?}", this); }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@strong self as this => move || { println!("v: {:?}", this); }); let closure = clone!(@strong self as this => move |_x| println!("v: {:?}", this)); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@strong self as this => move || println!("v: {:?}", this)); // Fields now! let closure = clone!(@strong self.v as v => move |_x| { println!("v: {:?}", v); }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@strong self.v as v => move || println!("v: {:?}", v)); // With @default-panic let closure = clone!(@strong self.v as v => @default-panic, move |_x| { println!("v: {:?}", v); }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@strong self.v as v => @default-panic, move || println!("v: {:?}", v)); // With @default-return let closure = clone!(@strong self.v as _v => @default-return true, move |_x| { false }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@strong self.v as _v => @default-return true, move || false); } } } #[test] fn test_clone_macro_rename() { let v = Rc::new(1); let closure = clone!(@weak v as y => @default-panic, move |_x| { println!("v: {}", y); }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@weak v as y => @default-panic, move || println!("v: {}", y)); let closure = clone!(@strong v as y => @default-panic, move |_x| { println!("v: {}", y); }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@strong v as y => @default-panic, move || println!("v: {}", y)); let closure = clone!(@weak v as y => move |_x| { println!("v: {}", y); }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@weak v as y => move || println!("v: {}", y)); let closure = clone!(@strong v as y => move |_x| { println!("v: {}", y); }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@strong v as y => move || println!("v: {}", y)); let closure = clone!(@weak v as _y => @default-return true, move |_x| { false }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@weak v as _y => @default-return true, move || false); let closure = clone!(@strong v as _y => @default-return true, move |_x| false); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@strong v as _y => @default-return true, move || false); } #[test] fn test_clone_macro_simple() { let v = Rc::new(1); let closure = clone!(@weak v => @default-panic, move |_x| { println!("v: {}", v); }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@weak v => @default-panic, move || println!("v: {}", v)); let closure = clone!(@strong v => @default-panic, move |_x| { println!("v: {}", v); }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@strong v => @default-panic, move || println!("v: {}", v)); let closure = clone!(@weak v => move |_x| { println!("v: {}", v); }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@weak v => move || println!("v: {}", v)); let closure = clone!(@strong v => move |_x| { println!("v: {}", v); }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@strong v => move || println!("v: {}", v)); let closure = clone!(@weak v => @default-return true, move |_x| { false }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@weak v => @default-return true, move || false); let closure = clone!(@strong v => @default-return true, move |_x| false); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@strong v => @default-return true, move || false); } #[test] fn test_clone_macro_double_simple() { let v = Rc::new(1); let w = Rc::new(2); let closure = clone!(@weak v, @weak w => @default-panic, move |_x| { println!("v: {}, w: {}", v, w); }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@weak v, @weak w => @default-panic, move || println!("v: {}, w: {}", v, w)); let closure = clone!(@strong v, @strong w => @default-panic, move |_x| { println!("v: {}, w: {}", v, w); }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@strong v, @strong w => @default-panic, move || println!("v: {}, w: {}", v, w)); let closure = clone!(@weak v, @weak w => move |_x| { println!("v: {}, w: {}", v, w); }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@weak v, @weak w => move || println!("v: {}, w: {}", v, w)); let closure = clone!(@strong v, @strong w => move |_x| { println!("v: {}, w: {}", v, w); }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@strong v, @strong w => move || println!("v: {}, w: {}", v, w)); let closure = clone!(@weak v, @weak w => @default-return true, move |_x| { false }); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@weak v, @weak w => @default-return true, move || false); let closure = clone!(@strong v, @strong w => @default-return true, move |_x| false); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!(@strong v, @strong w => @default-return true, move || false); } #[test] fn test_clone_macro_double_rename() { let v = Rc::new(1); let w = Rc::new(2); let done = Rc::new(RefCell::new(0)); let closure = clone!(@weak v as x, @weak w => @default-panic, move |z| { z + *x + *w }); assert_eq!(closure(1i8), 4i8); let closure = clone!(@weak v as x, @weak w => @default-panic, move || 1); assert_eq!(closure(), 1); let closure = clone!(@weak v, @weak w as x => @default-panic, move |z| { z + *v + *x }); assert_eq!(closure(10i8), 13i8); let closure = clone!(@weak v, @weak w as x => @default-panic, move || 2 + *x); assert_eq!(closure(), 4); let closure = clone!(@strong v as x, @strong w => @default-panic, move |z| { z + *x + *w }); assert_eq!(closure(3i8), 6i8); let closure = clone!(@strong v as x, @strong w => @default-panic, move || 4 + *w); assert_eq!(closure(), 6); let closure = clone!(@strong v, @strong w as x => @default-panic, move |z| { z + *v + *x }); assert_eq!(closure(0i8), 3i8); let closure = clone!(@strong v, @strong w as x => @default-panic, move || 5); assert_eq!(closure(), 5); let t_done = done.clone(); let closure = clone!(@weak v as x, @weak w => move |z| { *t_done.borrow_mut() = z + *x + *w; }); closure(4i8); assert_eq!(*done.borrow(), 7); let t_done = done.clone(); let closure = clone!(@weak v as x, @weak w => move || *t_done.borrow_mut() = *x + *w); closure(); assert_eq!(*done.borrow(), 3); let t_done = done.clone(); let closure = clone!(@weak v, @weak w as x => move |z| { *t_done.borrow_mut() = z + *v + *x; }); closure(8i8); assert_eq!(*done.borrow(), 11i8); let t_done = done.clone(); let closure = clone!(@weak v, @weak w as x => move || *t_done.borrow_mut() = *v * *x); closure(); assert_eq!(*done.borrow(), 2); let t_done = done.clone(); let closure = clone!(@strong v as x, @strong w => move |z| { *t_done.borrow_mut() = z + *x + *w; }); closure(9i8); assert_eq!(*done.borrow(), 12i8); let t_done = done.clone(); let closure = clone!(@strong v as x, @strong w => move || *t_done.borrow_mut() = *x - *w); closure(); assert_eq!(*done.borrow(), -1); let t_done = done.clone(); let closure = clone!(@strong v, @strong w as x => move |z| { *t_done.borrow_mut() = *v + *x * z; }); closure(2i8); assert_eq!(*done.borrow(), 5); let t_done = done.clone(); let closure = clone!(@strong v, @strong w as x => move || *t_done.borrow_mut() = *x - *v); closure(); assert_eq!(*done.borrow(), 1); let closure = clone!(@weak v as _x, @weak w => @default-return true, move |_| { false }); assert!(!closure(0u8)); let closure = clone!(@weak v as _x, @weak w => @default-return true, move || false); assert!(!closure()); let closure = clone!(@weak v, @weak w as _x => @default-return true, move |_| { false }); assert!(!closure("a")); let closure = clone!(@weak v, @weak w as _x => @default-return true, move || false); assert!(!closure()); let closure = clone!(@strong v as _x, @strong w => @default-return true, move |_| { false }); assert!(!closure('a')); let closure = clone!(@strong v as _x, @strong w => @default-return true, move || false); assert!(!closure()); let closure = clone!(@strong v, @strong w as _x => @default-return true, move |_| { false }); assert!(!closure(12.)); let closure = clone!(@strong v, @strong w as _x => @default-return true, move || false); assert!(!closure()); } #[test] fn test_clone_macro_typed_args() { macro_rules! test_closure { ($kind:tt, panic) => {{ // We need Arc and Mutex to use them below in the thread. let check = Arc::new(Mutex::new(0)); let v = Arc::new(Mutex::new(1)); let w = Arc::new(Mutex::new(1)); let closure = clone!(@$kind v as x, @$kind w, @weak check => @default-panic, move |arg: i8| { *x.lock().unwrap() += arg; *w.lock().unwrap() += arg; *check.lock().unwrap() += 1; }); closure(1); assert_eq!(2, *v.lock().unwrap()); assert_eq!(2, *w.lock().unwrap()); assert_eq!(1, *check.lock().unwrap()); let closure2 = clone!(@$kind v, @$kind w as x, @weak check => @default-panic, move |arg: i8| { *v.lock().unwrap() += arg; *x.lock().unwrap() += arg; *check.lock().unwrap() += 1; }); closure2(1); assert_eq!(3, *v.lock().unwrap()); assert_eq!(3, *w.lock().unwrap()); assert_eq!(2, *check.lock().unwrap()); macro_rules! inner { (strong) => {{}}; (weak) => {{ std::mem::drop(v); std::mem::drop(w); // We use the threads to ensure that the closure panics as expected. assert!(thread::spawn(move || { closure(1); }).join().is_err()); assert_eq!(2, *check.lock().unwrap()); assert!(thread::spawn(move || { closure2(1); }).join().is_err()); assert_eq!(2, *check.lock().unwrap()); }} } inner!($kind); }}; ($kind:tt) => {{ let check = Rc::new(RefCell::new(0)); let v = Rc::new(RefCell::new(1)); let w = Rc::new(RefCell::new(1)); let closure = clone!(@$kind v as x, @$kind w, @weak check => move |arg: i8| { *x.borrow_mut() += arg; *w.borrow_mut() += arg; *check.borrow_mut() += 1; }); closure(1); assert_eq!(2, *v.borrow()); assert_eq!(2, *w.borrow()); assert_eq!(1, *check.borrow()); let closure2 = clone!(@$kind v, @$kind w as x, @weak check => move |arg: i8| { *v.borrow_mut() += arg; *x.borrow_mut() += arg; *check.borrow_mut() += 1; }); closure2(1); assert_eq!(3, *v.borrow()); assert_eq!(3, *w.borrow()); assert_eq!(2, *check.borrow()); macro_rules! inner { (strong) => {{}}; (weak) => {{ std::mem::drop(v); std::mem::drop(w); closure(1); assert_eq!(2, *check.borrow()); closure2(1); assert_eq!(2, *check.borrow()); }} } inner!($kind); }}; ($kind:tt, $($t:tt)+) => {{ }} } test_closure!(weak, panic); test_closure!(strong, panic); test_closure!(weak); test_closure!(strong); let check = Rc::new(RefCell::new(0)); let v = Rc::new(RefCell::new(1)); let w = Rc::new(RefCell::new(1)); let closure = clone!(@weak v, @weak w as x, @weak check => move |arg: i8, arg2| { *v.borrow_mut() = arg; *x.borrow_mut() = arg2; *check.borrow_mut() += 1; }); closure(0, 9); assert_eq!(0, *v.borrow()); assert_eq!(9, *w.borrow()); assert_eq!(1, *check.borrow()); std::mem::drop(v); std::mem::drop(w); assert_eq!(1, *check.borrow()); } #[test] #[allow(clippy::bool_assert_comparison)] fn test_clone_macro_default_return() { macro_rules! test_default { ($ret:expr, $($closure_body:tt)*) => {{ let v = Rc::new(1); let tmp = clone!(@weak v => @default-return $ret, move || $($closure_body)*); assert_eq!(tmp(), $($closure_body)*, "shouldn't use default-return value!"); ::std::mem::drop(v); assert_eq!(tmp(), $ret, "should use default-return value!"); }} } #[derive(PartialEq, Debug)] struct Foo(i32); test_default!(Foo(0), Foo(1)); #[derive(PartialEq, Debug)] struct Bar { x: i32, } test_default!(Bar { x: 0 }, Bar { x: 1 }); #[derive(PartialEq, Debug)] enum Enum { A, B(i32), C { x: i32 }, } test_default!(Enum::A, Enum::B(0)); test_default!(Enum::B(0), Enum::A); test_default!(Enum::C { x: 0 }, Enum::A); test_default!( { let x = 12; x + 2 }, 19 ); // This one is simply to check that we wait for the comma for the default-return value. test_default!(Enum::A == Enum::B(0) || false, true); } #[test] fn test_clone_macro_body() { let v = Arc::new(Mutex::new(0)); let closure = clone!(@weak v => move || { std::thread::spawn(move || { let mut lock = v.lock().expect("failed to lock"); for _ in 1..=10 { *lock += 1; } }).join().expect("thread::spawn failed"); }); closure(); assert_eq!(10, *v.lock().expect("failed to lock")); } #[test] fn test_clone_macro_async_kinds() { let v = Rc::new(RefCell::new(1)); // This one is still a rust unstable feature. // let _closure = clone!(@weak v => async move || 0); let closure = clone!(@weak v => move || async move { *v.borrow_mut() += 1; }); block_on(closure()); assert_eq!(*v.borrow(), 2); block_on(clone!(@weak v => async move { *v.borrow_mut() += 1; })); assert_eq!(*v.borrow(), 3); } glib-0.14.8/tests/derive.rs000064400000000000000000000012470072674642500136550ustar 00000000000000use std::marker::PhantomData; use glib::{Downgrade, Object}; #[test] fn derive_downgrade() { #[derive(Downgrade)] pub struct NewType(Object); #[derive(Downgrade)] pub struct Struct { o1: Object, o2: std::rc::Rc, } #[derive(Downgrade)] pub enum Enum { None, Pair { x: Object, y: Object }, Unit(), SingleUnnamed(Object), MultipleUnnamed(Object, Object, Object), } #[derive(Downgrade)] pub struct TypedWrapper(Object, PhantomData); #[derive(Downgrade)] pub enum TypedEnum { This(Object, PhantomData), That(Object, PhantomData), } } glib-0.14.8/tests/log.rs000064400000000000000000000071660072674642500131660ustar 00000000000000use glib::*; use std::sync::{Arc, Mutex}; #[derive(Default)] struct Counters { criticals: usize, warnings: usize, messages: usize, infos: usize, debugs: usize, } fn assert_counts( count: &Arc>, criticals: usize, warnings: usize, messages: usize, infos: usize, debugs: usize, ) { let count = count.lock().expect("failed to lock 1"); assert_eq!(count.criticals, criticals); assert_eq!(count.warnings, warnings); assert_eq!(count.messages, messages); assert_eq!(count.infos, infos); assert_eq!(count.debugs, debugs); } #[test] fn check_log_handlers() { // We set the fatal level explicitly in case it's set outside of the test. log_set_fatal_mask(Some("domain"), LogLevels::LEVEL_ERROR); // // log_set_default_handler check part // let count = Arc::new(Mutex::new(Counters::default())); log_set_default_handler(clone!(@weak count => move |_, level, _| { match level { LogLevel::Critical => { (*count.lock().expect("failed to lock 3")).criticals += 1; } LogLevel::Warning => { (*count.lock().expect("failed to lock 4")).warnings += 1; } LogLevel::Message => { (*count.lock().expect("failed to lock 5")).messages += 1; } LogLevel::Info => { (*count.lock().expect("failed to lock 6")).infos += 1; } LogLevel::Debug => { (*count.lock().expect("failed to lock 7")).debugs += 1; } _ => unreachable!(), } })); assert_counts(&count, 0, 0, 0, 0, 0); g_warning!(Some("domain"), "hello"); assert_counts(&count, 0, 1, 0, 0, 0); g_warning!(Some("domain"), "hello"); g_critical!(Some("domain"), "hello"); g_warning!(Some("domain"), "hello"); g_message!(Some("domain"), "hello"); g_info!(Some("domain"), "hello"); g_debug!(Some("domain"), "hello"); g_info!(Some("domain"), "hello"); assert_counts(&count, 1, 3, 1, 2, 1); // We now unset our callback and check if it has really been unset. log_unset_default_handler(); g_info!(Some("domain"), "hello"); g_debug!(Some("domain"), "hello"); assert_counts(&count, 1, 3, 1, 2, 1); // // log_set_handler check part // let count = Arc::new(Mutex::new(Counters::default())); // We set the handler for both warning and debug. let handler_id = log_set_handler( Some("domain"), LogLevels::LEVEL_WARNING | LogLevels::LEVEL_DEBUG, false, false, clone!(@weak count => move |_, level, _| { match level { LogLevel::Warning => { (*count.lock().expect("failed to lock 4")).warnings += 1; } LogLevel::Debug => { (*count.lock().expect("failed to lock 7")).debugs += 1; } _ => unreachable!(), } }), ); assert_counts(&count, 0, 0, 0, 0, 0); g_warning!(Some("domain"), "hello"); assert_counts(&count, 0, 1, 0, 0, 0); g_critical!(Some("domain"), "hello"); g_message!(Some("domain"), "hello"); g_info!(Some("domain"), "hello"); assert_counts(&count, 0, 1, 0, 0, 0); g_debug!(Some("domain"), "hello"); assert_counts(&count, 0, 1, 0, 0, 1); // We check that only "domain" messages are calling our callback. g_debug!(Some("not-domain"), "hello"); g_warning!(Some("not-domain"), "hello"); assert_counts(&count, 0, 1, 0, 0, 1); log_remove_handler(Some("domain"), handler_id); g_critical!(Some("domain"), "hello"); g_message!(Some("domain"), "hello"); g_info!(Some("domain"), "hello"); g_debug!(Some("domain"), "hello"); g_warning!(Some("domain"), "hello"); assert_counts(&count, 0, 1, 0, 0, 1); } glib-0.14.8/tests/print.rs000064400000000000000000000032610072674642500135310ustar 00000000000000use glib::*; use std::sync::{Arc, Mutex}; // Funny thing: we can't put those two tests in two different functions, otherwise they might // conflict with the results of the other one (or it would be mandatory to run the tests on only // one thread). #[test] fn check_print_handler() { // // g_print check part // let count = Arc::new(Mutex::new(0)); set_print_handler(clone!(@weak count => move |_| { // we don't care about the message in here! *count.lock().expect("failed to lock 1") += 1; })); g_print!("test"); assert_eq!(*count.lock().expect("failed to lock 2"), 1); g_printerr!("one"); assert_eq!(*count.lock().expect("failed to lock 3"), 1); g_print!("another"); assert_eq!(*count.lock().expect("failed to lock 4"), 2); unset_print_handler(); g_print!("tadam"); assert_eq!(*count.lock().expect("failed to lock 5"), 2); g_printerr!("toudoum"); assert_eq!(*count.lock().expect("failed to lock 6"), 2); // // g_printerr check part // let count = Arc::new(Mutex::new(0)); set_printerr_handler(clone!(@weak count => move |_| { // we don't care about the message in here! *count.lock().expect("failed to lock a") += 1; })); g_printerr!("test"); assert_eq!(*count.lock().expect("failed to lock b"), 1); g_print!("one"); assert_eq!(*count.lock().expect("failed to lock c"), 1); g_printerr!("another"); assert_eq!(*count.lock().expect("failed to lock d"), 2); unset_printerr_handler(); g_printerr!("tadam"); assert_eq!(*count.lock().expect("failed to lock e"), 2); g_print!("toudoum"); assert_eq!(*count.lock().expect("failed to lock f"), 2); } glib-0.14.8/tests/value.rs000064400000000000000000000032620072674642500135120ustar 00000000000000use glib::*; use std::ops::Deref; // FIXME all .get::() should be replaced with .get(); the compiler is totally able to infer the type itself. // But somehow without some tests are failing on Windows because the type inference doesn't work or something. /// Test that `ToValue` (and conversely, `FromValue`) uphold the promised invariants #[test] pub fn to_value_invariants() { // Inverse assert_eq!(0i32, 0i32.to_value().get::().unwrap()); assert_eq!(0i32, (&0i32.to_value()).get::().unwrap()); // Idempotence assert_eq!( &0i32.to_value().type_(), &0i32.to_value().to_value().type_() ); assert_eq!(0i32, 0i32.to_value().to_value().get::().unwrap()); assert_eq!( 0i32, 0i32.to_value() .get::() .unwrap() .get::() .unwrap() ); assert_eq!( 0i32, (&0i32.to_value()) .get::() .unwrap() .get::() .unwrap() ); } /// Test that `ToValue` and `FromValue` handle nexted boxed values correctly (as per the documentation) #[test] pub fn to_value_boxed() { let x = 0i32.to_value(); let boxed = BoxedValue(x); assert_eq!( 0i32, boxed .to_value() .to_value() .get::() .unwrap() .deref() .get::() .unwrap() ); assert_eq!( 0i32, boxed .to_value() .get::() .unwrap() .get::() .unwrap() .deref() .get::() .unwrap() ); }