glib-0.8.2/.gitignore010066400017500001750000000001451352206036300126510ustar0000000000000000test/bin/ target/ doc/ configure.in config.log config.status *.dylib .rust *.so *.o *.swp Cargo.lock glib-0.8.2/.gitmodules010066400017500001750000000002401352206036300130320ustar0000000000000000[submodule "gir"] path = gir url = https://github.com/gtk-rs/gir.git [submodule "gir-files"] path = gir-files url = https://github.com/gtk-rs/gir-files.git glib-0.8.2/.travis.yml010066400017500001750000000047651354212555500130150ustar0000000000000000dist: xenial language: rust matrix: include: - os: linux rust: nightly env: GTK=3.14 FEATURES=subclassing,futures - os: linux rust: nightly env: GTK=3.24 FEATURES=subclassing,v2_48,futures - os: linux rust: beta env: GTK=3.14 FEATURES=subclassing - os: linux rust: beta env: GTK=3.24 FEATURES=subclassing,v2_48 - os: linux rust: 1.34.0 env: GTK=3.14 FEATURES=subclassing - os: linux rust: 1.34.0 env: GTK=3.24 FEATURES=subclassing,v2_48 - os: osx rust: nightly env: GTK=3.14 FEATURES=subclassing,futures # - os: osx # rust: nightly # env: GTK=3.24 FEATURES=subclassing,v2_48,futures - os: osx rust: beta env: GTK=3.14 FEATURES=subclassing # - os: osx # rust: beta # env: GTK=3.24 FEATURES=subclassing,v2_48 - os: osx rust: stable env: GTK=3.14 FEATURES=subclassing # - os: osx # rust: stable # env: GTK=3.24 FEATURES=subclassing,v2_48 - os: linux rust: nightly env: GTK=3.14 FEATURES=subclassing,futures ARM=1 OTHER_TARGET="--target armv7-unknown-linux-gnueabihf" - os: linux rust: nightly env: GTK=3.24 FEATURES=subclassing,v2_48,futures ARM=1 OTHER_TARGET="--target armv7-unknown-linux-gnueabihf" addons: apt: packages: - libgtk-3-dev - libmount-dev before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install gtk+3 cairo atk; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig; fi - if [[ "$ARM" == "1" ]]; then rustup target add armv7-unknown-linux-gnueabihf; fi script: - if [ "$TRAVIS_RUST_VERSION" == "beta" ]; then rustup component add clippy; cargo clippy --release; fi - if [ "$TRAVIS_RUST_VERSION" == "nightly" ] && [ "$GTK" == "3.14" ] && ! [ "$ARM" == "1" ]; then rustup component add rustfmt; make regen_check; fi - if ! [ "$ARM" == "1" ]; then cargo doc --features "dox"; fi - if ! [ "$ARM" == "1" ]; then cargo test --features "$FEATURES"; fi - if [ "$ARM" == "1" ]; then PKG_CONFIG_ALLOW_CROSS=1 cargo build --features "$FEATURES" $OTHER_TARGET; fi - rustc --version - mkdir .cargo - echo 'paths = ["."]' > .cargo/config - git clone -q --depth 50 -b pending https://github.com/gtk-rs/examples _examples - cd _examples - ./build_travis.sh glib-0.8.2/COPYRIGHT010066400017500001750000000050021352206036300121510ustar0000000000000000The Gtk-rs Project is copyright 2013-2016, The Gtk-rs Project Developers: Adam Crume Adolfo Ochagavía Andre Bogus Anton Konjahin Arne Dussin Boden Garman Brian Kropf Bryant Mairs Chris Greenaway Chris Palmer Corey Farwell Daniel Zalevskiy David Li Edward Shaw Edward Yang Esption Evgenii Pashkin Geoffrey French Gleb Kozyrev Glenn Watson Google Inc. Guillaume Gomez Gulshan Singh Jakob Gillich James Shepherdson Jeremy Letang John Vrbanac kennytm Laurence Tratt Lionel Flandrin Lucas Werkmeister Lukas Diekmann Mathijs Henquet Maxwell Koo mitaa Nick Herman Nicolas Koch Oliver Schneider Ömer Sinan Ağacan Ralph Giles Paul Dennis Paul Hendry Philipp Brüschweiler Raphael Nestler Robertas Romain Gauthier S.J.R. van Schaik Sebastian Schulze Silvio Fricke Simon Sapin Steve Klabnik Tobias Bales trolleyman Umur Gedik UrKr Vojtech Kral Zach Oakes Zach Ploskey The Gtk-rs Project is licensed under the MIT license, see the LICENSE file or . 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, see the LGPL file. glib-0.8.2/Cargo.toml.orig010066400017500001750000000022221354212621600135500ustar0000000000000000[package] name = "glib" documentation = "http://gtk-rs.org/docs/glib/" homepage = "http://gtk-rs.org/" authors = ["The Gtk-rs Project Developers"] description = "Rust bindings for the GLib library" readme = "README.md" version = "0.8.2" keywords = ["glib", "gtk-rs", "gnome", "GUI"] repository = "https://github.com/gtk-rs/glib" license = "MIT" exclude = [ "gir-files/*", ] [badges] appveyor = { repository = "GuillaumeGomez/glib", service = "github" } travis-ci = { repository = "gtk-rs/glib" } [lib] name = "glib" [dependencies] lazy_static = "1.2" libc = "0.2" bitflags = "1.0" gobject-sys = "0.9.0" glib-sys = "0.9.0" futures-preview = { version = "0.3.0-alpha", optional = true } [dev-dependencies] tempfile = "3" [features] v2_44 = ["glib-sys/v2_44", "gobject-sys/v2_44"] v2_46 = ["v2_44", "glib-sys/v2_46", "gobject-sys/v2_46"] v2_48 = ["v2_46", "glib-sys/v2_48"] v2_50 = ["v2_48", "glib-sys/v2_50"] v2_52 = ["v2_50", "glib-sys/v2_52"] v2_54 = ["v2_52", "glib-sys/v2_54", "gobject-sys/v2_54"] v2_56 = ["v2_54", "glib-sys/v2_56"] v2_58 = ["v2_56", "glib-sys/v2_58"] futures = ["futures-preview"] subclassing = [] dox = ["glib-sys/dox", "gobject-sys/dox"] glib-0.8.2/Cargo.toml0000644000000034130000000000000100160ustar00# 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 believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "glib" version = "0.8.2" authors = ["The Gtk-rs Project Developers"] exclude = ["gir-files/*"] description = "Rust bindings for the GLib library" homepage = "http://gtk-rs.org/" documentation = "http://gtk-rs.org/docs/glib/" readme = "README.md" keywords = ["glib", "gtk-rs", "gnome", "GUI"] license = "MIT" repository = "https://github.com/gtk-rs/glib" [lib] name = "glib" [dependencies.bitflags] version = "1.0" [dependencies.futures-preview] version = "0.3.0-alpha" optional = true [dependencies.glib-sys] version = "0.9.0" [dependencies.gobject-sys] version = "0.9.0" [dependencies.lazy_static] version = "1.2" [dependencies.libc] version = "0.2" [dev-dependencies.tempfile] version = "3" [features] dox = ["glib-sys/dox", "gobject-sys/dox"] futures = ["futures-preview"] subclassing = [] v2_44 = ["glib-sys/v2_44", "gobject-sys/v2_44"] v2_46 = ["v2_44", "glib-sys/v2_46", "gobject-sys/v2_46"] v2_48 = ["v2_46", "glib-sys/v2_48"] v2_50 = ["v2_48", "glib-sys/v2_50"] v2_52 = ["v2_50", "glib-sys/v2_52"] v2_54 = ["v2_52", "glib-sys/v2_54", "gobject-sys/v2_54"] v2_56 = ["v2_54", "glib-sys/v2_56"] v2_58 = ["v2_56", "glib-sys/v2_58"] [badges.appveyor] repository = "GuillaumeGomez/glib" service = "github" [badges.travis-ci] repository = "gtk-rs/glib" glib-0.8.2/Gir.toml010066400017500001750000000306201352206036300123000ustar0000000000000000[options] girs_dir = "gir-files" library = "GLib" version = "2.0" min_cfg_version = "2.42" target_path = "." work_mode = "normal" single_version_file = true deprecate_by_min_version = true generate = [ "GLib.DateDay", "GLib.DateMonth", "GLib.DateWeekday", "GLib.DateYear", "GLib.FormatSizeFlags", "GLib.KeyFileError", "GLib.KeyFileFlags", "GLib.OptionArg", "GLib.OptionFlags", "GLib.SeekType", "GLib.SpawnFlags", "GLib.Time", "GLib.TimeType", "GLib.TimeSpan", "GLib.FileTest", "GLib.IOCondition", ] 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]] name = "unix_open_pipe" 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]] 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 = "markup_escape_text" [object.function.return] nullable = false [[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_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 = "spawn_command_line_async" [[object.function.parameter]] name = "command_line" 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.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]] name = "GLib.Checksum" status = "generate" concurrency = "send+sync" [[object.function]] name = "get_digest" #wrong array definition ignore = true [[object.function]] name = "get_string" #consume ignore = true [[object]] name = "GLib.ChecksumType" status = "generate" [[object.member]] name = "sha512" version = "2.36" [[object.member]] name = "sha384" version = "2.52" [[object]] name = "GLib.KeyFile" status = "generate" [[object.function]] name = "load_from_data_dirs" ignore = true [[object.function]] name = "load_from_dirs" ignore = true [[object.function]] name = "error_quark" ignore = true [[object.function]] name = "save_to_file" # file parameter needs to be a PathBuf ignore = 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 ignore = 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 ignore = true [[object.function]] name = "has_key" #boolean return value needs to be returned ignore = true [[object.function]] name = "get_boolean_list" #boolean array needs to be converted to Vec ignore = true [[object]] name = "GLib.DateTime" status = "generate" concurrency = "send+sync" [[object]] name = "GLib.MainContext" status = "generate" concurrency = "send+sync" [[object.function]] name = "prepare" # out parameter not marked as such ignore = true [[object.function]] name = "find_source_by_id" # source id is a newtype ignore = true [[object.function]] name = "default" [object.function.return] nullable = false [[object.function]] name = "ref_thread_default" [object.function.return] nullable = false [[object.function]] name = "invoke" ignore = true [[object.function]] name = "invoke_full" ignore = true [[object]] name = "GLib.MainLoop" status = "generate" concurrency = "send+sync" [[object.function]] name = "get_context" [object.function.return] nullable = false [[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 [[object]] name = "GLib.TimeZone" status = "generate" concurrency = "send+sync" [[object.function]] name = "adjust_time" # in-out parameter ignore = true glib-0.8.2/Gir_GObject.toml010066400017500001750000000010311352206036300136670ustar0000000000000000[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 generate = [ "GObject.BindingFlags", "GObject.ParamFlags", "GObject.SignalFlags", ] ignore = [ ] manual = [ "GObject.Object", "GObject.Value", ] [[object]] name = "GObject.Binding" status = "generate" trait = false concurrency = "send+sync" [[object]] name = "GObject.*" status = "ignore" glib-0.8.2/LGPL010066400017500001750000000613141352206036300113470ustar0000000000000000 GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA. Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! glib-0.8.2/LICENSE010066400017500001750000000021201352206036300116610ustar0000000000000000The MIT License (MIT) Copyright (c) 2013-2015, The Gtk-rs Project Developers. Permission 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.8.2/Makefile010066400017500001750000000015601352206036300123230ustar0000000000000000GIR = gir/target/bin/gir GIR_SRC = gir/Cargo.toml gir/Cargo.lock gir/build.rs $(shell find gir/src -name '*.rs') GIR_FILES = gir-files/Glib-2.0.gir gir-files/GObject-2.0.gir # Run `gir` generating the bindings gir : src/auto/mod.rs src/gobject/auto/mod.rs cargo fmt doc: $(GIR) $(GIR_FILES) $(GIR) -m doc -c Gir.toml not_bound: $(GIR) $(GIR_FILES) $(GIR) -m not_bound -c Gir.toml regen_check: $(GIR) $(GIR_FILES) rm src/auto/* rm src/gobject/auto/* $(GIR) -c Gir.toml $(GIR) -c Gir_GObject.toml cargo fmt git diff -R --exit-code src/auto/mod.rs : Gir.toml $(GIR) $(GIR_FILES) $(GIR) -c Gir.toml src/gobject/auto/mod.rs : Gir_GObject.toml $(GIR) $(GIR_FILES) $(GIR) -c Gir_GObject.toml $(GIR) : $(GIR_SRC) rm -f gir/target/bin/gir cargo install --path gir --root gir/target rm -f gir/target/.crates.toml $(GIR_SRC) $(GIR_FILES) : git submodule update --init glib-0.8.2/README.md010066400017500001750000000014601352206036300121410ustar0000000000000000# glib [![Build Status](https://travis-ci.org/gtk-rs/glib.png?branch=master)](https://travis-ci.org/gtk-rs/glib) [![Build status](https://ci.appveyor.com/api/projects/status/jphtjb5hr51970fh?svg=true)](https://ci.appveyor.com/project/GuillaumeGomez/glib-l2j1a) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gtk-rs/gtk) GLib bindings for Rust. Alongside GLib bindings, this crate also includes the infrastructure to subclass `GObject` for extending libraries like GTK+. A code example can be found in the documentation of this crate in the `subclass` module. - [Gtk-rs project site](http://gtk-rs.org/) - [Online documentation](http://gtk-rs.org/docs/) - [Readme](https://github.com/gtk-rs/gtk/blob/master/README.md) in our [main repo](https://github.com/gtk-rs/gtk) ## License MIT glib-0.8.2/appveyor.yml010066400017500001750000000014771354212555500132710ustar0000000000000000environment: matrix: - RUST: stable BITS: 32 - RUST: stable BITS: 64 install: - IF "%BITS%" == "32" SET ARCH=i686 - IF "%BITS%" == "64" SET ARCH=x86_64 - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe --default-host "%ARCH%-pc-windows-gnu" --default-toolchain %RUST% -y - SET PATH=C:\Users\appveyor\.cargo\bin;C:\msys64\mingw%BITS%\bin;%PATH%;C:\msys64\usr\bin - rustc -Vv - cargo -Vv - pacman --noconfirm -S mingw-w64-%ARCH%-gtk3 build_script: - cargo doc --features "dox" - cargo test --features subclassing - cargo test --features subclassing,v2_58 - mkdir .cargo - echo paths = ["."] > .cargo\config - git clone -q --depth 50 https://github.com/gtk-rs/examples _examples - cd _examples - cargo build - cargo build --features gtk_3_24 test: false glib-0.8.2/src/auto/alias.rs010066400017500001750000000004171352206036300140610ustar0000000000000000// 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 auto::*; pub type DateDay = u8; pub type DateYear = u16; pub type Time = i32; pub type TimeSpan = i64; glib-0.8.2/src/auto/checksum.rs010066400017500001750000000023531352206036300145730ustar0000000000000000// 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 glib_sys; use translate::*; use ChecksumType; glib_wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Checksum(Boxed); match fn { copy => |ptr| glib_sys::g_checksum_copy(mut_override(ptr)), free => |ptr| glib_sys::g_checksum_free(ptr), get_type => || glib_sys::g_checksum_get_type(), } } impl Checksum { pub fn new(checksum_type: ChecksumType) -> Checksum { unsafe { from_glib_full(glib_sys::g_checksum_new(checksum_type.to_glib())) } } pub fn reset(&mut self) { unsafe { glib_sys::g_checksum_reset(self.to_glib_none_mut().0); } } pub fn update(&mut self, data: &[u8]) { let length = data.len() as isize; unsafe { glib_sys::g_checksum_update(self.to_glib_none_mut().0, data.to_glib_none().0, length); } } pub fn type_get_length(checksum_type: ChecksumType) -> isize { unsafe { glib_sys::g_checksum_type_get_length(checksum_type.to_glib()) } } } unsafe impl Send for Checksum {} unsafe impl Sync for Checksum {} glib-0.8.2/src/auto/constants.rs010066400017500001750000000164311354212555500150160ustar0000000000000000// 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 glib_sys; use std::ffi::CStr; lazy_static! { pub static ref CSET_A_2_Z: &'static str = unsafe { CStr::from_ptr(glib_sys::G_CSET_A_2_Z).to_str().unwrap() }; } lazy_static! { pub static ref CSET_DIGITS: &'static str = unsafe { CStr::from_ptr(glib_sys::G_CSET_DIGITS).to_str().unwrap() }; } lazy_static! { pub static ref CSET_a_2_z: &'static str = unsafe { CStr::from_ptr(glib_sys::G_CSET_a_2_z).to_str().unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_ACTION_GROUP_PREFIX: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_ACTION_GROUP_PREFIX) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_GROUP: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_GROUP) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_ACTIONS: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_ACTIONS) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_CATEGORIES: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_CATEGORIES) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_COMMENT: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_COMMENT) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_EXEC: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_EXEC) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_FULLNAME: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_FULLNAME) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_GENERIC_NAME: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_GENERIC_NAME) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_HIDDEN: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_HIDDEN) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_ICON: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_ICON) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_KEYWORDS: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_KEYWORDS) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_MIME_TYPE: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_MIME_TYPE) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_NAME: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_NAME) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_NO_DISPLAY: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_PATH: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_PATH) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_TERMINAL: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_TERMINAL) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_TRY_EXEC: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_TRY_EXEC) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_TYPE: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_TYPE) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_URL: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_URL) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_KEY_VERSION: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_KEY_VERSION) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_TYPE_APPLICATION: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_TYPE_APPLICATION) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_TYPE_DIRECTORY: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_TYPE_DIRECTORY) .to_str() .unwrap() }; } lazy_static! { pub static ref KEY_FILE_DESKTOP_TYPE_LINK: &'static str = unsafe { CStr::from_ptr(glib_sys::G_KEY_FILE_DESKTOP_TYPE_LINK) .to_str() .unwrap() }; } lazy_static! { pub static ref OPTION_REMAINING: &'static str = unsafe { CStr::from_ptr(glib_sys::G_OPTION_REMAINING) .to_str() .unwrap() }; } lazy_static! { pub static ref STR_DELIMITERS: &'static str = unsafe { CStr::from_ptr(glib_sys::G_STR_DELIMITERS).to_str().unwrap() }; } lazy_static! { pub static ref URI_RESERVED_CHARS_GENERIC_DELIMITERS: &'static str = unsafe { CStr::from_ptr(glib_sys::G_URI_RESERVED_CHARS_GENERIC_DELIMITERS) .to_str() .unwrap() }; } lazy_static! { pub static ref URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS: &'static str = unsafe { CStr::from_ptr(glib_sys::G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS) .to_str() .unwrap() }; } glib-0.8.2/src/auto/date_time.rs010066400017500001750000000250071354212555500147340ustar0000000000000000// 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 glib_sys; use std::cmp; use std::hash; use std::mem; use translate::*; use GString; use TimeSpan; use TimeZone; glib_wrapper! { #[derive(Debug)] pub struct DateTime(Shared); match fn { ref => |ptr| glib_sys::g_date_time_ref(ptr), unref => |ptr| glib_sys::g_date_time_unref(ptr), get_type => || glib_sys::g_date_time_get_type(), } } impl DateTime { pub fn new( tz: &TimeZone, year: i32, month: i32, day: i32, hour: i32, minute: i32, seconds: f64, ) -> DateTime { unsafe { from_glib_full(glib_sys::g_date_time_new( tz.to_glib_none().0, year, month, day, hour, minute, seconds, )) } } #[cfg(any(feature = "v2_56", feature = "dox"))] pub fn new_from_iso8601(text: &str, default_tz: Option<&TimeZone>) -> Option { unsafe { from_glib_full(glib_sys::g_date_time_new_from_iso8601( text.to_glib_none().0, default_tz.to_glib_none().0, )) } } //pub fn new_from_timeval_local(tv: /*Ignored*/&TimeVal) -> DateTime { // unsafe { TODO: call glib_sys:g_date_time_new_from_timeval_local() } //} //pub fn new_from_timeval_utc(tv: /*Ignored*/&TimeVal) -> DateTime { // unsafe { TODO: call glib_sys:g_date_time_new_from_timeval_utc() } //} pub fn new_from_unix_local(t: i64) -> DateTime { unsafe { from_glib_full(glib_sys::g_date_time_new_from_unix_local(t)) } } pub fn new_from_unix_utc(t: i64) -> DateTime { unsafe { from_glib_full(glib_sys::g_date_time_new_from_unix_utc(t)) } } pub fn new_local( year: i32, month: i32, day: i32, hour: i32, minute: i32, seconds: f64, ) -> DateTime { unsafe { from_glib_full(glib_sys::g_date_time_new_local( year, month, day, hour, minute, seconds, )) } } pub fn new_now(tz: &TimeZone) -> DateTime { unsafe { from_glib_full(glib_sys::g_date_time_new_now(tz.to_glib_none().0)) } } pub fn new_now_local() -> DateTime { unsafe { from_glib_full(glib_sys::g_date_time_new_now_local()) } } pub fn new_now_utc() -> DateTime { unsafe { from_glib_full(glib_sys::g_date_time_new_now_utc()) } } pub fn new_utc( year: i32, month: i32, day: i32, hour: i32, minute: i32, seconds: f64, ) -> DateTime { unsafe { from_glib_full(glib_sys::g_date_time_new_utc( year, month, day, hour, minute, seconds, )) } } pub fn add(&self, timespan: TimeSpan) -> Option { unsafe { from_glib_full(glib_sys::g_date_time_add(self.to_glib_none().0, timespan)) } } pub fn add_days(&self, days: i32) -> Option { unsafe { from_glib_full(glib_sys::g_date_time_add_days(self.to_glib_none().0, days)) } } pub fn add_full( &self, years: i32, months: i32, days: i32, hours: i32, minutes: i32, seconds: f64, ) -> Option { unsafe { from_glib_full(glib_sys::g_date_time_add_full( self.to_glib_none().0, years, months, days, hours, minutes, seconds, )) } } pub fn add_hours(&self, hours: i32) -> Option { unsafe { from_glib_full(glib_sys::g_date_time_add_hours( self.to_glib_none().0, hours, )) } } pub fn add_minutes(&self, minutes: i32) -> Option { unsafe { from_glib_full(glib_sys::g_date_time_add_minutes( self.to_glib_none().0, minutes, )) } } pub fn add_months(&self, months: i32) -> Option { unsafe { from_glib_full(glib_sys::g_date_time_add_months( self.to_glib_none().0, months, )) } } pub fn add_seconds(&self, seconds: f64) -> Option { unsafe { from_glib_full(glib_sys::g_date_time_add_seconds( self.to_glib_none().0, seconds, )) } } pub fn add_weeks(&self, weeks: i32) -> Option { unsafe { from_glib_full(glib_sys::g_date_time_add_weeks( self.to_glib_none().0, weeks, )) } } pub fn add_years(&self, years: i32) -> Option { unsafe { from_glib_full(glib_sys::g_date_time_add_years( self.to_glib_none().0, years, )) } } pub fn difference(&self, begin: &DateTime) -> TimeSpan { unsafe { glib_sys::g_date_time_difference(self.to_glib_none().0, begin.to_glib_none().0) } } pub fn format(&self, format: &str) -> Option { unsafe { from_glib_full(glib_sys::g_date_time_format( self.to_glib_none().0, format.to_glib_none().0, )) } } pub fn get_day_of_month(&self) -> i32 { unsafe { glib_sys::g_date_time_get_day_of_month(self.to_glib_none().0) } } pub fn get_day_of_week(&self) -> i32 { unsafe { glib_sys::g_date_time_get_day_of_week(self.to_glib_none().0) } } pub fn get_day_of_year(&self) -> i32 { unsafe { glib_sys::g_date_time_get_day_of_year(self.to_glib_none().0) } } pub fn get_hour(&self) -> i32 { unsafe { glib_sys::g_date_time_get_hour(self.to_glib_none().0) } } pub fn get_microsecond(&self) -> i32 { unsafe { glib_sys::g_date_time_get_microsecond(self.to_glib_none().0) } } pub fn get_minute(&self) -> i32 { unsafe { glib_sys::g_date_time_get_minute(self.to_glib_none().0) } } pub fn get_month(&self) -> i32 { unsafe { glib_sys::g_date_time_get_month(self.to_glib_none().0) } } pub fn get_second(&self) -> i32 { unsafe { glib_sys::g_date_time_get_second(self.to_glib_none().0) } } pub fn get_seconds(&self) -> f64 { unsafe { glib_sys::g_date_time_get_seconds(self.to_glib_none().0) } } #[cfg(any(feature = "v2_58", feature = "dox"))] pub fn get_timezone(&self) -> Option { unsafe { from_glib_none(glib_sys::g_date_time_get_timezone(self.to_glib_none().0)) } } pub fn get_timezone_abbreviation(&self) -> Option { unsafe { from_glib_none(glib_sys::g_date_time_get_timezone_abbreviation( self.to_glib_none().0, )) } } pub fn get_utc_offset(&self) -> TimeSpan { unsafe { glib_sys::g_date_time_get_utc_offset(self.to_glib_none().0) } } pub fn get_week_numbering_year(&self) -> i32 { unsafe { glib_sys::g_date_time_get_week_numbering_year(self.to_glib_none().0) } } pub fn get_week_of_year(&self) -> i32 { unsafe { glib_sys::g_date_time_get_week_of_year(self.to_glib_none().0) } } pub fn get_year(&self) -> i32 { unsafe { glib_sys::g_date_time_get_year(self.to_glib_none().0) } } pub fn get_ymd(&self) -> (i32, i32, i32) { unsafe { let mut year = mem::uninitialized(); let mut month = mem::uninitialized(); let mut day = mem::uninitialized(); glib_sys::g_date_time_get_ymd(self.to_glib_none().0, &mut year, &mut month, &mut day); (year, month, day) } } pub fn is_daylight_savings(&self) -> bool { unsafe { from_glib(glib_sys::g_date_time_is_daylight_savings( self.to_glib_none().0, )) } } pub fn to_local(&self) -> Option { unsafe { from_glib_full(glib_sys::g_date_time_to_local(self.to_glib_none().0)) } } //pub fn to_timeval(&self, tv: /*Ignored*/&mut TimeVal) -> bool { // unsafe { TODO: call glib_sys:g_date_time_to_timeval() } //} pub fn to_timezone(&self, tz: &TimeZone) -> Option { unsafe { from_glib_full(glib_sys::g_date_time_to_timezone( self.to_glib_none().0, tz.to_glib_none().0, )) } } pub fn to_unix(&self) -> i64 { unsafe { glib_sys::g_date_time_to_unix(self.to_glib_none().0) } } pub fn to_utc(&self) -> Option { unsafe { from_glib_full(glib_sys::g_date_time_to_utc(self.to_glib_none().0)) } } fn compare(&self, dt2: &DateTime) -> i32 { unsafe { glib_sys::g_date_time_compare( ToGlibPtr::<*mut glib_sys::GDateTime>::to_glib_none(self).0 as glib_sys::gconstpointer, ToGlibPtr::<*mut glib_sys::GDateTime>::to_glib_none(dt2).0 as glib_sys::gconstpointer, ) } } fn equal(&self, dt2: &DateTime) -> bool { unsafe { from_glib(glib_sys::g_date_time_equal( ToGlibPtr::<*mut glib_sys::GDateTime>::to_glib_none(self).0 as glib_sys::gconstpointer, ToGlibPtr::<*mut glib_sys::GDateTime>::to_glib_none(dt2).0 as glib_sys::gconstpointer, )) } } fn hash(&self) -> u32 { unsafe { glib_sys::g_date_time_hash( ToGlibPtr::<*mut glib_sys::GDateTime>::to_glib_none(self).0 as glib_sys::gconstpointer, ) } } } 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.8.2/src/auto/enums.rs010066400017500001750000000344261352206036300141260ustar0000000000000000// 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 error::ErrorDomain; use glib_sys; use std::fmt; use translate::*; use Quark; #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] pub enum ChecksumType { Md5, Sha1, Sha256, Sha512, #[cfg(any(feature = "v2_52", feature = "dox"))] Sha384, #[doc(hidden)] __Unknown(i32), } impl fmt::Display for ChecksumType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "ChecksumType::{}", match *self { ChecksumType::Md5 => "Md5", ChecksumType::Sha1 => "Sha1", ChecksumType::Sha256 => "Sha256", ChecksumType::Sha512 => "Sha512", #[cfg(any(feature = "v2_52", feature = "dox"))] ChecksumType::Sha384 => "Sha384", _ => "Unknown", } ) } } #[doc(hidden)] impl ToGlib for ChecksumType { type GlibType = glib_sys::GChecksumType; fn to_glib(&self) -> glib_sys::GChecksumType { match *self { ChecksumType::Md5 => glib_sys::G_CHECKSUM_MD5, ChecksumType::Sha1 => glib_sys::G_CHECKSUM_SHA1, ChecksumType::Sha256 => glib_sys::G_CHECKSUM_SHA256, ChecksumType::Sha512 => glib_sys::G_CHECKSUM_SHA512, #[cfg(any(feature = "v2_52", feature = "dox"))] ChecksumType::Sha384 => glib_sys::G_CHECKSUM_SHA384, ChecksumType::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for ChecksumType { fn from_glib(value: glib_sys::GChecksumType) -> Self { match value { 0 => ChecksumType::Md5, 1 => ChecksumType::Sha1, 2 => ChecksumType::Sha256, 3 => ChecksumType::Sha512, #[cfg(any(feature = "v2_52", feature = "dox"))] 4 => ChecksumType::Sha384, value => ChecksumType::__Unknown(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] pub enum DateMonth { BadMonth, January, February, March, April, May, June, July, August, September, October, November, December, #[doc(hidden)] __Unknown(i32), } impl fmt::Display for DateMonth { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "DateMonth::{}", match *self { DateMonth::BadMonth => "BadMonth", DateMonth::January => "January", DateMonth::February => "February", DateMonth::March => "March", DateMonth::April => "April", DateMonth::May => "May", DateMonth::June => "June", DateMonth::July => "July", DateMonth::August => "August", DateMonth::September => "September", DateMonth::October => "October", DateMonth::November => "November", DateMonth::December => "December", _ => "Unknown", } ) } } #[doc(hidden)] impl ToGlib for DateMonth { type GlibType = glib_sys::GDateMonth; fn to_glib(&self) -> glib_sys::GDateMonth { match *self { DateMonth::BadMonth => glib_sys::G_DATE_BAD_MONTH, DateMonth::January => glib_sys::G_DATE_JANUARY, DateMonth::February => glib_sys::G_DATE_FEBRUARY, DateMonth::March => glib_sys::G_DATE_MARCH, DateMonth::April => glib_sys::G_DATE_APRIL, DateMonth::May => glib_sys::G_DATE_MAY, DateMonth::June => glib_sys::G_DATE_JUNE, DateMonth::July => glib_sys::G_DATE_JULY, DateMonth::August => glib_sys::G_DATE_AUGUST, DateMonth::September => glib_sys::G_DATE_SEPTEMBER, DateMonth::October => glib_sys::G_DATE_OCTOBER, DateMonth::November => glib_sys::G_DATE_NOVEMBER, DateMonth::December => glib_sys::G_DATE_DECEMBER, DateMonth::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for DateMonth { fn from_glib(value: glib_sys::GDateMonth) -> Self { match value { 0 => DateMonth::BadMonth, 1 => DateMonth::January, 2 => DateMonth::February, 3 => DateMonth::March, 4 => DateMonth::April, 5 => DateMonth::May, 6 => DateMonth::June, 7 => DateMonth::July, 8 => DateMonth::August, 9 => DateMonth::September, 10 => DateMonth::October, 11 => DateMonth::November, 12 => DateMonth::December, value => DateMonth::__Unknown(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] pub enum DateWeekday { BadWeekday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday, #[doc(hidden)] __Unknown(i32), } impl fmt::Display for DateWeekday { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "DateWeekday::{}", match *self { DateWeekday::BadWeekday => "BadWeekday", DateWeekday::Monday => "Monday", DateWeekday::Tuesday => "Tuesday", DateWeekday::Wednesday => "Wednesday", DateWeekday::Thursday => "Thursday", DateWeekday::Friday => "Friday", DateWeekday::Saturday => "Saturday", DateWeekday::Sunday => "Sunday", _ => "Unknown", } ) } } #[doc(hidden)] impl ToGlib for DateWeekday { type GlibType = glib_sys::GDateWeekday; fn to_glib(&self) -> glib_sys::GDateWeekday { match *self { DateWeekday::BadWeekday => glib_sys::G_DATE_BAD_WEEKDAY, DateWeekday::Monday => glib_sys::G_DATE_MONDAY, DateWeekday::Tuesday => glib_sys::G_DATE_TUESDAY, DateWeekday::Wednesday => glib_sys::G_DATE_WEDNESDAY, DateWeekday::Thursday => glib_sys::G_DATE_THURSDAY, DateWeekday::Friday => glib_sys::G_DATE_FRIDAY, DateWeekday::Saturday => glib_sys::G_DATE_SATURDAY, DateWeekday::Sunday => glib_sys::G_DATE_SUNDAY, DateWeekday::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for DateWeekday { fn from_glib(value: glib_sys::GDateWeekday) -> Self { match value { 0 => DateWeekday::BadWeekday, 1 => DateWeekday::Monday, 2 => DateWeekday::Tuesday, 3 => DateWeekday::Wednesday, 4 => DateWeekday::Thursday, 5 => DateWeekday::Friday, 6 => DateWeekday::Saturday, 7 => DateWeekday::Sunday, value => DateWeekday::__Unknown(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] pub enum KeyFileError { UnknownEncoding, Parse, NotFound, KeyNotFound, GroupNotFound, InvalidValue, #[doc(hidden)] __Unknown(i32), } impl fmt::Display for KeyFileError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "KeyFileError::{}", match *self { KeyFileError::UnknownEncoding => "UnknownEncoding", KeyFileError::Parse => "Parse", KeyFileError::NotFound => "NotFound", KeyFileError::KeyNotFound => "KeyNotFound", KeyFileError::GroupNotFound => "GroupNotFound", KeyFileError::InvalidValue => "InvalidValue", _ => "Unknown", } ) } } #[doc(hidden)] impl ToGlib for KeyFileError { type GlibType = glib_sys::GKeyFileError; fn to_glib(&self) -> glib_sys::GKeyFileError { match *self { KeyFileError::UnknownEncoding => glib_sys::G_KEY_FILE_ERROR_UNKNOWN_ENCODING, KeyFileError::Parse => glib_sys::G_KEY_FILE_ERROR_PARSE, KeyFileError::NotFound => glib_sys::G_KEY_FILE_ERROR_NOT_FOUND, KeyFileError::KeyNotFound => glib_sys::G_KEY_FILE_ERROR_KEY_NOT_FOUND, KeyFileError::GroupNotFound => glib_sys::G_KEY_FILE_ERROR_GROUP_NOT_FOUND, KeyFileError::InvalidValue => glib_sys::G_KEY_FILE_ERROR_INVALID_VALUE, KeyFileError::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for KeyFileError { fn from_glib(value: glib_sys::GKeyFileError) -> Self { match value { 0 => KeyFileError::UnknownEncoding, 1 => KeyFileError::Parse, 2 => KeyFileError::NotFound, 3 => KeyFileError::KeyNotFound, 4 => KeyFileError::GroupNotFound, 5 => KeyFileError::InvalidValue, value => KeyFileError::__Unknown(value), } } } impl ErrorDomain for KeyFileError { fn domain() -> Quark { unsafe { from_glib(glib_sys::g_key_file_error_quark()) } } fn code(self) -> i32 { self.to_glib() } fn from(code: i32) -> Option { match code { 0 => Some(KeyFileError::UnknownEncoding), 1 => Some(KeyFileError::Parse), 2 => Some(KeyFileError::NotFound), 3 => Some(KeyFileError::KeyNotFound), 4 => Some(KeyFileError::GroupNotFound), 5 => Some(KeyFileError::InvalidValue), value => Some(KeyFileError::__Unknown(value)), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] pub enum OptionArg { None, String, Int, Callback, Filename, StringArray, FilenameArray, Double, Int64, #[doc(hidden)] __Unknown(i32), } impl fmt::Display for OptionArg { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "OptionArg::{}", match *self { OptionArg::None => "None", OptionArg::String => "String", OptionArg::Int => "Int", OptionArg::Callback => "Callback", OptionArg::Filename => "Filename", OptionArg::StringArray => "StringArray", OptionArg::FilenameArray => "FilenameArray", OptionArg::Double => "Double", OptionArg::Int64 => "Int64", _ => "Unknown", } ) } } #[doc(hidden)] impl ToGlib for OptionArg { type GlibType = glib_sys::GOptionArg; fn to_glib(&self) -> glib_sys::GOptionArg { match *self { OptionArg::None => glib_sys::G_OPTION_ARG_NONE, OptionArg::String => glib_sys::G_OPTION_ARG_STRING, OptionArg::Int => glib_sys::G_OPTION_ARG_INT, OptionArg::Callback => glib_sys::G_OPTION_ARG_CALLBACK, OptionArg::Filename => glib_sys::G_OPTION_ARG_FILENAME, OptionArg::StringArray => glib_sys::G_OPTION_ARG_STRING_ARRAY, OptionArg::FilenameArray => glib_sys::G_OPTION_ARG_FILENAME_ARRAY, OptionArg::Double => glib_sys::G_OPTION_ARG_DOUBLE, OptionArg::Int64 => glib_sys::G_OPTION_ARG_INT64, OptionArg::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for OptionArg { fn from_glib(value: glib_sys::GOptionArg) -> Self { match value { 0 => OptionArg::None, 1 => OptionArg::String, 2 => OptionArg::Int, 3 => OptionArg::Callback, 4 => OptionArg::Filename, 5 => OptionArg::StringArray, 6 => OptionArg::FilenameArray, 7 => OptionArg::Double, 8 => OptionArg::Int64, value => OptionArg::__Unknown(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] pub enum SeekType { Cur, Set, End, #[doc(hidden)] __Unknown(i32), } impl fmt::Display for SeekType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "SeekType::{}", match *self { SeekType::Cur => "Cur", SeekType::Set => "Set", SeekType::End => "End", _ => "Unknown", } ) } } #[doc(hidden)] impl ToGlib for SeekType { type GlibType = glib_sys::GSeekType; fn to_glib(&self) -> glib_sys::GSeekType { match *self { SeekType::Cur => glib_sys::G_SEEK_CUR, SeekType::Set => glib_sys::G_SEEK_SET, SeekType::End => glib_sys::G_SEEK_END, SeekType::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for SeekType { fn from_glib(value: glib_sys::GSeekType) -> Self { match value { 0 => SeekType::Cur, 1 => SeekType::Set, 2 => SeekType::End, value => SeekType::__Unknown(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] pub enum TimeType { Standard, Daylight, Universal, #[doc(hidden)] __Unknown(i32), } impl fmt::Display for TimeType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "TimeType::{}", match *self { TimeType::Standard => "Standard", TimeType::Daylight => "Daylight", TimeType::Universal => "Universal", _ => "Unknown", } ) } } #[doc(hidden)] impl ToGlib for TimeType { type GlibType = glib_sys::GTimeType; fn to_glib(&self) -> glib_sys::GTimeType { match *self { TimeType::Standard => glib_sys::G_TIME_TYPE_STANDARD, TimeType::Daylight => glib_sys::G_TIME_TYPE_DAYLIGHT, TimeType::Universal => glib_sys::G_TIME_TYPE_UNIVERSAL, TimeType::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for TimeType { fn from_glib(value: glib_sys::GTimeType) -> Self { match value { 0 => TimeType::Standard, 1 => TimeType::Daylight, 2 => TimeType::Universal, value => TimeType::__Unknown(value), } } } glib-0.8.2/src/auto/flags.rs010066400017500001750000000107141352206036300140650ustar0000000000000000// 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 glib_sys; use gobject_sys; use translate::*; use value::FromValue; use value::FromValueOptional; use value::SetValue; use value::Value; use StaticType; use Type; bitflags! { pub struct FileTest: u32 { const IS_REGULAR = 1; const IS_SYMLINK = 2; const IS_DIR = 4; const IS_EXECUTABLE = 8; const EXISTS = 16; } } #[doc(hidden)] impl ToGlib for FileTest { type GlibType = glib_sys::GFileTest; fn to_glib(&self) -> glib_sys::GFileTest { self.bits() } } #[doc(hidden)] impl FromGlib for FileTest { fn from_glib(value: glib_sys::GFileTest) -> FileTest { FileTest::from_bits_truncate(value) } } bitflags! { pub struct FormatSizeFlags: u32 { const DEFAULT = 0; const LONG_FORMAT = 1; const IEC_UNITS = 2; const BITS = 4; } } #[doc(hidden)] impl ToGlib for FormatSizeFlags { type GlibType = glib_sys::GFormatSizeFlags; fn to_glib(&self) -> glib_sys::GFormatSizeFlags { self.bits() } } #[doc(hidden)] impl FromGlib for FormatSizeFlags { fn from_glib(value: glib_sys::GFormatSizeFlags) -> FormatSizeFlags { FormatSizeFlags::from_bits_truncate(value) } } bitflags! { pub struct IOCondition: u32 { const IN = 1; const OUT = 4; const PRI = 2; const ERR = 8; const HUP = 16; const NVAL = 32; } } #[doc(hidden)] impl ToGlib for IOCondition { type GlibType = glib_sys::GIOCondition; fn to_glib(&self) -> glib_sys::GIOCondition { self.bits() } } #[doc(hidden)] impl FromGlib for IOCondition { fn from_glib(value: glib_sys::GIOCondition) -> IOCondition { IOCondition::from_bits_truncate(value) } } impl StaticType for IOCondition { fn static_type() -> Type { unsafe { from_glib(glib_sys::g_io_condition_get_type()) } } } impl<'a> FromValueOptional<'a> for IOCondition { unsafe fn from_value_optional(value: &Value) -> Option { Some(FromValue::from_value(value)) } } impl<'a> FromValue<'a> for IOCondition { unsafe fn from_value(value: &Value) -> Self { from_glib(gobject_sys::g_value_get_flags(value.to_glib_none().0)) } } impl SetValue for IOCondition { unsafe fn set_value(value: &mut Value, this: &Self) { gobject_sys::g_value_set_flags(value.to_glib_none_mut().0, this.to_glib()) } } bitflags! { pub struct KeyFileFlags: u32 { const NONE = 0; const KEEP_COMMENTS = 1; const KEEP_TRANSLATIONS = 2; } } #[doc(hidden)] impl ToGlib for KeyFileFlags { type GlibType = glib_sys::GKeyFileFlags; fn to_glib(&self) -> glib_sys::GKeyFileFlags { self.bits() } } #[doc(hidden)] impl FromGlib for KeyFileFlags { fn from_glib(value: glib_sys::GKeyFileFlags) -> KeyFileFlags { KeyFileFlags::from_bits_truncate(value) } } bitflags! { pub struct OptionFlags: u32 { const NONE = 0; const HIDDEN = 1; const IN_MAIN = 2; const REVERSE = 4; const NO_ARG = 8; const FILENAME = 16; const OPTIONAL_ARG = 32; const NOALIAS = 64; } } #[doc(hidden)] impl ToGlib for OptionFlags { type GlibType = glib_sys::GOptionFlags; fn to_glib(&self) -> glib_sys::GOptionFlags { self.bits() } } #[doc(hidden)] impl FromGlib for OptionFlags { fn from_glib(value: glib_sys::GOptionFlags) -> OptionFlags { OptionFlags::from_bits_truncate(value) } } bitflags! { pub struct SpawnFlags: u32 { const DEFAULT = 0; const LEAVE_DESCRIPTORS_OPEN = 1; const DO_NOT_REAP_CHILD = 2; const SEARCH_PATH = 4; const STDOUT_TO_DEV_NULL = 8; const STDERR_TO_DEV_NULL = 16; const CHILD_INHERITS_STDIN = 32; const FILE_AND_ARGV_ZERO = 64; const SEARCH_PATH_FROM_ENVP = 128; const CLOEXEC_PIPES = 256; } } #[doc(hidden)] impl ToGlib for SpawnFlags { type GlibType = glib_sys::GSpawnFlags; fn to_glib(&self) -> glib_sys::GSpawnFlags { self.bits() } } #[doc(hidden)] impl FromGlib for SpawnFlags { fn from_glib(value: glib_sys::GSpawnFlags) -> SpawnFlags { SpawnFlags::from_bits_truncate(value) } } glib-0.8.2/src/auto/functions.rs010066400017500001750000001336471354212555500150230ustar0000000000000000// 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 glib_sys; use libc; use std; use std::mem; use std::ptr; use translate::*; use types; use Bytes; use ChecksumType; use Error; use FileTest; use FormatSizeFlags; use GString; use Source; use UserDirectory; pub fn access>(filename: P, mode: i32) -> i32 { unsafe { glib_sys::g_access(filename.as_ref().to_glib_none().0, mode) } } pub fn assert_warning( log_domain: &str, file: &str, line: i32, pretty_function: &str, expression: &str, ) { unsafe { glib_sys::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, ); } } pub fn assertion_message(domain: &str, file: &str, line: i32, func: &str, message: &str) { unsafe { glib_sys::g_assertion_message( domain.to_glib_none().0, file.to_glib_none().0, line, func.to_glib_none().0, message.to_glib_none().0, ); } } //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: Char) { // unsafe { TODO: call glib_sys:g_assertion_message_cmpnum() } //} pub fn assertion_message_cmpstr( domain: &str, file: &str, line: i32, func: &str, expr: &str, arg1: &str, cmp: &str, arg2: &str, ) { unsafe { glib_sys::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, ); } } pub fn base64_decode(text: &str) -> Vec { unsafe { let mut out_len = mem::uninitialized(); let ret = FromGlibContainer::from_glib_full_num( glib_sys::g_base64_decode(text.to_glib_none().0, &mut out_len), out_len as usize, ); ret } } //pub fn base64_decode_inplace(text: /*Unimplemented*/Vec) -> u8 { // unsafe { TODO: call glib_sys:g_base64_decode_inplace() } //} //pub fn base64_decode_step(in_: &[u8], out: Vec, state: &mut i32, save: &mut u32) -> usize { // unsafe { TODO: call glib_sys:g_base64_decode_step() } //} pub fn base64_encode(data: &[u8]) -> Option { let len = data.len() as usize; unsafe { from_glib_full(glib_sys::g_base64_encode(data.to_glib_none().0, len)) } } //pub fn base64_encode_close(break_lines: bool, out: Vec, state: &mut i32, save: &mut i32) -> usize { // unsafe { TODO: call glib_sys:g_base64_encode_close() } //} //pub fn base64_encode_step(in_: &[u8], break_lines: bool, out: Vec, state: &mut i32, save: &mut i32) -> usize { // unsafe { TODO: call glib_sys:g_base64_encode_step() } //} pub fn bit_nth_lsf(mask: libc::c_ulong, nth_bit: i32) -> i32 { unsafe { glib_sys::g_bit_nth_lsf(mask, nth_bit) } } pub fn bit_nth_msf(mask: libc::c_ulong, nth_bit: i32) -> i32 { unsafe { glib_sys::g_bit_nth_msf(mask, nth_bit) } } pub fn bit_storage(number: libc::c_ulong) -> u32 { unsafe { glib_sys::g_bit_storage(number) } } //pub fn build_filename>(first_element: P, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> Option { // unsafe { TODO: call glib_sys:g_build_filename() } //} //#[cfg(any(feature = "v2_56", feature = "dox"))] //pub fn build_filename_valist>(first_element: P, args: /*Unknown conversion*//*Unimplemented*/Unsupported) -> Option { // unsafe { TODO: call glib_sys:g_build_filename_valist() } //} pub fn build_filenamev(args: &[&std::path::Path]) -> Option { unsafe { from_glib_full(glib_sys::g_build_filenamev(args.to_glib_none().0)) } } //pub fn build_path, Q: AsRef>(separator: P, first_element: Q, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> Option { // unsafe { TODO: call glib_sys:g_build_path() } //} pub fn build_pathv(separator: &str, args: &[&std::path::Path]) -> Option { unsafe { from_glib_full(glib_sys::g_build_pathv( separator.to_glib_none().0, args.to_glib_none().0, )) } } #[cfg(any(feature = "v2_58", feature = "dox"))] pub fn canonicalize_filename, Q: AsRef>( filename: P, relative_to: Q, ) -> Option { unsafe { from_glib_full(glib_sys::g_canonicalize_filename( filename.as_ref().to_glib_none().0, relative_to.as_ref().to_glib_none().0, )) } } pub fn chdir>(path: P) -> i32 { unsafe { glib_sys::g_chdir(path.as_ref().to_glib_none().0) } } pub fn check_version( required_major: u32, required_minor: u32, required_micro: u32, ) -> Option { unsafe { from_glib_none(glib_sys::glib_check_version( required_major, required_minor, required_micro, )) } } pub fn clear_error() -> Result<(), Error> { unsafe { let mut error = ptr::null_mut(); let _ = glib_sys::g_clear_error(&mut error); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } //#[cfg(any(feature = "v2_56", feature = "dox"))] //pub fn clear_handle_id(tag_ptr: u32, clear_func: P) { // unsafe { TODO: call glib_sys:g_clear_handle_id() } //} //pub fn clear_pointer(pp: /*Unimplemented*/Fundamental: Pointer) { // unsafe { TODO: call glib_sys:g_clear_pointer() } //} pub fn compute_checksum_for_bytes(checksum_type: ChecksumType, data: &Bytes) -> Option { unsafe { from_glib_full(glib_sys::g_compute_checksum_for_bytes( checksum_type.to_glib(), data.to_glib_none().0, )) } } pub fn compute_checksum_for_data(checksum_type: ChecksumType, data: &[u8]) -> Option { let length = data.len() as usize; unsafe { from_glib_full(glib_sys::g_compute_checksum_for_data( checksum_type.to_glib(), data.to_glib_none().0, length, )) } } pub fn compute_checksum_for_string(checksum_type: ChecksumType, str: &str) -> Option { let length = str.len() as isize; unsafe { from_glib_full(glib_sys::g_compute_checksum_for_string( checksum_type.to_glib(), str.to_glib_none().0, length, )) } } #[cfg(any(feature = "v2_50", feature = "dox"))] pub fn compute_hmac_for_bytes( digest_type: ChecksumType, key: &Bytes, data: &Bytes, ) -> Option { unsafe { from_glib_full(glib_sys::g_compute_hmac_for_bytes( digest_type.to_glib(), key.to_glib_none().0, data.to_glib_none().0, )) } } pub fn compute_hmac_for_data( digest_type: ChecksumType, key: &[u8], data: &[u8], ) -> Option { let key_len = key.len() as usize; let length = data.len() as usize; unsafe { from_glib_full(glib_sys::g_compute_hmac_for_data( digest_type.to_glib(), key.to_glib_none().0, key_len, data.to_glib_none().0, length, )) } } pub fn compute_hmac_for_string( digest_type: ChecksumType, key: &[u8], str: &str, ) -> Option { let key_len = key.len() as usize; let length = str.len() as isize; unsafe { from_glib_full(glib_sys::g_compute_hmac_for_string( digest_type.to_glib(), key.to_glib_none().0, key_len, str.to_glib_none().0, length, )) } } //pub fn convert_with_iconv(str: &[u8], converter: /*Ignored*/&IConv) -> Result<(Vec, usize), Error> { // unsafe { TODO: call glib_sys:g_convert_with_iconv() } //} //pub fn datalist_clear(datalist: /*Ignored*/&mut Data) { // unsafe { TODO: call glib_sys:g_datalist_clear() } //} //pub fn datalist_foreach(datalist: /*Ignored*/&mut Data, func: /*Unimplemented*/FnMut(Quark, /*Unimplemented*/Option), user_data: /*Unimplemented*/Option) { // unsafe { TODO: call glib_sys:g_datalist_foreach() } //} //pub fn datalist_get_data(datalist: /*Ignored*/&mut Data, key: &str) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_datalist_get_data() } //} //pub fn datalist_get_flags(datalist: /*Ignored*/&mut Data) -> u32 { // unsafe { TODO: call glib_sys:g_datalist_get_flags() } //} //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 glib_sys:g_datalist_id_dup_data() } //} //pub fn datalist_id_get_data(datalist: /*Ignored*/&mut Data, key_id: Quark) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_datalist_id_get_data() } //} //pub fn datalist_id_remove_no_notify(datalist: /*Ignored*/&mut Data, key_id: Quark) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_datalist_id_remove_no_notify() } //} //pub fn datalist_id_replace_data(datalist: /*Ignored*/&mut Data, key_id: Quark, oldval: /*Unimplemented*/Option, newval: /*Unimplemented*/Option) -> Option { // unsafe { TODO: call glib_sys:g_datalist_id_replace_data() } //} //pub fn datalist_id_set_data_full(datalist: /*Ignored*/&mut Data, key_id: Quark, data: /*Unimplemented*/Option) { // unsafe { TODO: call glib_sys:g_datalist_id_set_data_full() } //} //pub fn datalist_init(datalist: /*Ignored*/&mut Data) { // unsafe { TODO: call glib_sys:g_datalist_init() } //} //pub fn datalist_set_flags(datalist: /*Ignored*/&mut Data, flags: u32) { // unsafe { TODO: call glib_sys:g_datalist_set_flags() } //} //pub fn datalist_unset_flags(datalist: /*Ignored*/&mut Data, flags: u32) { // unsafe { TODO: call glib_sys:g_datalist_unset_flags() } //} //pub fn dataset_destroy(dataset_location: /*Unimplemented*/Fundamental: Pointer) { // unsafe { TODO: call glib_sys:g_dataset_destroy() } //} //pub fn dataset_foreach(dataset_location: /*Unimplemented*/Fundamental: Pointer, func: /*Unimplemented*/FnMut(Quark, /*Unimplemented*/Option), user_data: /*Unimplemented*/Option) { // unsafe { TODO: call glib_sys:g_dataset_foreach() } //} //pub fn dataset_id_get_data(dataset_location: /*Unimplemented*/Fundamental: Pointer, key_id: Quark) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_dataset_id_get_data() } //} //pub fn dataset_id_remove_no_notify(dataset_location: /*Unimplemented*/Fundamental: Pointer, key_id: Quark) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_dataset_id_remove_no_notify() } //} //pub fn dataset_id_set_data_full(dataset_location: /*Unimplemented*/Fundamental: Pointer, key_id: Quark, data: /*Unimplemented*/Option) { // unsafe { TODO: call glib_sys:g_dataset_id_set_data_full() } //} pub fn dcgettext(domain: Option<&str>, msgid: &str, category: i32) -> Option { unsafe { from_glib_none(glib_sys::g_dcgettext( domain.to_glib_none().0, msgid.to_glib_none().0, category, )) } } pub fn dgettext(domain: Option<&str>, msgid: &str) -> Option { unsafe { from_glib_none(glib_sys::g_dgettext( domain.to_glib_none().0, msgid.to_glib_none().0, )) } } //pub fn direct_equal(v1: /*Unimplemented*/Option, v2: /*Unimplemented*/Option) -> bool { // unsafe { TODO: call glib_sys:g_direct_equal() } //} //pub fn direct_hash(v: /*Unimplemented*/Option) -> u32 { // unsafe { TODO: call glib_sys:g_direct_hash() } //} pub fn dngettext( domain: Option<&str>, msgid: &str, msgid_plural: &str, n: libc::c_ulong, ) -> Option { unsafe { from_glib_none(glib_sys::g_dngettext( domain.to_glib_none().0, msgid.to_glib_none().0, msgid_plural.to_glib_none().0, n, )) } } //pub fn double_equal(v1: /*Unimplemented*/Fundamental: Pointer, v2: /*Unimplemented*/Fundamental: Pointer) -> bool { // unsafe { TODO: call glib_sys:g_double_equal() } //} //pub fn double_hash(v: /*Unimplemented*/Fundamental: Pointer) -> u32 { // unsafe { TODO: call glib_sys:g_double_hash() } //} pub fn dpgettext(domain: Option<&str>, msgctxtid: &str, msgidoffset: usize) -> Option { unsafe { from_glib_none(glib_sys::g_dpgettext( domain.to_glib_none().0, msgctxtid.to_glib_none().0, msgidoffset, )) } } pub fn dpgettext2(domain: Option<&str>, context: &str, msgid: &str) -> Option { unsafe { from_glib_none(glib_sys::g_dpgettext2( domain.to_glib_none().0, context.to_glib_none().0, msgid.to_glib_none().0, )) } } //pub fn file_error_from_errno(err_no: i32) -> /*Ignored*/FileError { // unsafe { TODO: call glib_sys:g_file_error_from_errno() } //} pub fn file_get_contents>(filename: P) -> Result, Error> { unsafe { let mut contents = ptr::null_mut(); let mut length = mem::uninitialized(); let mut error = ptr::null_mut(); let _ = glib_sys::g_file_get_contents( filename.as_ref().to_glib_none().0, &mut contents, &mut length, &mut error, ); if error.is_null() { Ok(FromGlibContainer::from_glib_full_num( contents, length as usize, )) } else { Err(from_glib_full(error)) } } } pub fn file_open_tmp>( tmpl: P, ) -> Result<(i32, std::path::PathBuf), Error> { unsafe { let mut name_used = ptr::null_mut(); let mut error = ptr::null_mut(); let ret = glib_sys::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)) } } } pub fn file_read_link>(filename: P) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = glib_sys::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)) } } } pub fn file_set_contents>( filename: P, contents: &[u8], ) -> Result<(), Error> { let length = contents.len() as isize; unsafe { let mut error = ptr::null_mut(); let _ = glib_sys::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)) } } } pub fn file_test>(filename: P, test: FileTest) -> bool { unsafe { from_glib(glib_sys::g_file_test( filename.as_ref().to_glib_none().0, test.to_glib(), )) } } pub fn filename_display_basename>(filename: P) -> Option { unsafe { from_glib_full(glib_sys::g_filename_display_basename( filename.as_ref().to_glib_none().0, )) } } pub fn filename_display_name>(filename: P) -> Option { unsafe { from_glib_full(glib_sys::g_filename_display_name( filename.as_ref().to_glib_none().0, )) } } pub fn format_size(size: u64) -> Option { unsafe { from_glib_full(glib_sys::g_format_size(size)) } } pub fn format_size_full(size: u64, flags: FormatSizeFlags) -> Option { unsafe { from_glib_full(glib_sys::g_format_size_full(size, flags.to_glib())) } } //pub fn fprintf(file: /*Unimplemented*/Fundamental: Pointer, format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> i32 { // unsafe { TODO: call glib_sys:g_fprintf() } //} //pub fn free(mem: /*Unimplemented*/Option) { // unsafe { TODO: call glib_sys:g_free() } //} pub fn get_application_name() -> Option { unsafe { from_glib_none(glib_sys::g_get_application_name()) } } pub fn get_charset() -> Option { unsafe { let mut charset = ptr::null(); let ret = from_glib(glib_sys::g_get_charset(&mut charset)); if ret { Some(from_glib_none(charset)) } else { None } } } pub fn get_codeset() -> Option { unsafe { from_glib_full(glib_sys::g_get_codeset()) } } //pub fn get_current_time(result: /*Ignored*/&mut TimeVal) { // unsafe { TODO: call glib_sys:g_get_current_time() } //} pub fn get_environ() -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(glib_sys::g_get_environ()) } } pub fn get_host_name() -> Option { unsafe { from_glib_none(glib_sys::g_get_host_name()) } } pub fn get_language_names() -> Vec { unsafe { FromGlibPtrContainer::from_glib_none(glib_sys::g_get_language_names()) } } #[cfg(any(feature = "v2_58", feature = "dox"))] pub fn get_language_names_with_category(category_name: &str) -> Vec { unsafe { FromGlibPtrContainer::from_glib_none(glib_sys::g_get_language_names_with_category( category_name.to_glib_none().0, )) } } pub fn get_locale_variants(locale: &str) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(glib_sys::g_get_locale_variants( locale.to_glib_none().0, )) } } pub fn get_monotonic_time() -> i64 { unsafe { glib_sys::g_get_monotonic_time() } } pub fn get_num_processors() -> u32 { unsafe { glib_sys::g_get_num_processors() } } pub fn get_real_time() -> i64 { unsafe { glib_sys::g_get_real_time() } } pub fn get_system_config_dirs() -> Vec { unsafe { FromGlibPtrContainer::from_glib_none(glib_sys::g_get_system_config_dirs()) } } pub fn get_system_data_dirs() -> Vec { unsafe { FromGlibPtrContainer::from_glib_none(glib_sys::g_get_system_data_dirs()) } } pub fn get_user_cache_dir() -> Option { unsafe { from_glib_none(glib_sys::g_get_user_cache_dir()) } } pub fn get_user_config_dir() -> Option { unsafe { from_glib_none(glib_sys::g_get_user_config_dir()) } } pub fn get_user_data_dir() -> Option { unsafe { from_glib_none(glib_sys::g_get_user_data_dir()) } } pub fn get_user_runtime_dir() -> Option { unsafe { from_glib_none(glib_sys::g_get_user_runtime_dir()) } } pub fn get_user_special_dir(directory: UserDirectory) -> Option { unsafe { from_glib_none(glib_sys::g_get_user_special_dir(directory.to_glib())) } } pub fn hostname_is_ascii_encoded(hostname: &str) -> bool { unsafe { from_glib(glib_sys::g_hostname_is_ascii_encoded( hostname.to_glib_none().0, )) } } pub fn hostname_is_ip_address(hostname: &str) -> bool { unsafe { from_glib(glib_sys::g_hostname_is_ip_address( hostname.to_glib_none().0, )) } } pub fn hostname_is_non_ascii(hostname: &str) -> bool { unsafe { from_glib(glib_sys::g_hostname_is_non_ascii(hostname.to_glib_none().0)) } } pub fn hostname_to_ascii(hostname: &str) -> Option { unsafe { from_glib_full(glib_sys::g_hostname_to_ascii(hostname.to_glib_none().0)) } } pub fn hostname_to_unicode(hostname: &str) -> Option { unsafe { from_glib_full(glib_sys::g_hostname_to_unicode(hostname.to_glib_none().0)) } } //pub fn iconv(converter: /*Ignored*/&IConv, inbuf: &str, inbytes_left: usize, outbuf: &str, outbytes_left: usize) -> usize { // unsafe { TODO: call glib_sys:g_iconv() } //} //pub fn idle_remove_by_data(data: /*Unimplemented*/Option) -> bool { // unsafe { TODO: call glib_sys:g_idle_remove_by_data() } //} //pub fn int64_equal(v1: /*Unimplemented*/Fundamental: Pointer, v2: /*Unimplemented*/Fundamental: Pointer) -> bool { // unsafe { TODO: call glib_sys:g_int64_equal() } //} //pub fn int64_hash(v: /*Unimplemented*/Fundamental: Pointer) -> u32 { // unsafe { TODO: call glib_sys:g_int64_hash() } //} //pub fn int_equal(v1: /*Unimplemented*/Fundamental: Pointer, v2: /*Unimplemented*/Fundamental: Pointer) -> bool { // unsafe { TODO: call glib_sys:g_int_equal() } //} //pub fn int_hash(v: /*Unimplemented*/Fundamental: Pointer) -> u32 { // unsafe { TODO: call glib_sys:g_int_hash() } //} //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 glib_sys:g_io_add_watch() } //} //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 glib_sys:g_io_add_watch_full() } //} //pub fn io_create_watch(channel: /*Ignored*/&IOChannel, condition: IOCondition) -> Option { // unsafe { TODO: call glib_sys:g_io_create_watch() } //} pub fn listenv() -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(glib_sys::g_listenv()) } } //pub fn log(log_domain: Option<&str>, log_level: /*Ignored*/LogLevelFlags, format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) { // unsafe { TODO: call glib_sys:g_log() } //} //pub fn log_default_handler(log_domain: Option<&str>, log_level: /*Ignored*/LogLevelFlags, message: Option<&str>, unused_data: /*Unimplemented*/Option) { // unsafe { TODO: call glib_sys:g_log_default_handler() } //} pub fn log_remove_handler(log_domain: &str, handler_id: u32) { unsafe { glib_sys::g_log_remove_handler(log_domain.to_glib_none().0, handler_id); } } //pub fn log_set_always_fatal(fatal_mask: /*Ignored*/LogLevelFlags) -> /*Ignored*/LogLevelFlags { // unsafe { TODO: call glib_sys:g_log_set_always_fatal() } //} //pub fn log_set_default_handler(log_func: /*Unimplemented*/Fn(&str, /*Ignored*/LogLevelFlags, &str), user_data: /*Unimplemented*/Option) -> /*Unimplemented*/Fn(&str, /*Ignored*/LogLevelFlags, &str) { // unsafe { TODO: call glib_sys:g_log_set_default_handler() } //} //pub fn log_set_fatal_mask(log_domain: &str, fatal_mask: /*Ignored*/LogLevelFlags) -> /*Ignored*/LogLevelFlags { // unsafe { TODO: call glib_sys:g_log_set_fatal_mask() } //} //pub fn log_set_handler(log_domain: Option<&str>, log_levels: /*Ignored*/LogLevelFlags, log_func: /*Unimplemented*/Fn(&str, /*Ignored*/LogLevelFlags, &str), user_data: /*Unimplemented*/Option) -> u32 { // unsafe { TODO: call glib_sys:g_log_set_handler() } //} //#[cfg(any(feature = "v2_46", feature = "dox"))] //pub fn log_set_handler_full(log_domain: Option<&str>, log_levels: /*Ignored*/LogLevelFlags, log_func: /*Unimplemented*/Fn(&str, /*Ignored*/LogLevelFlags, &str), user_data: /*Unimplemented*/Option) -> u32 { // unsafe { TODO: call glib_sys:g_log_set_handler_full() } //} //#[cfg(any(feature = "v2_50", feature = "dox"))] //pub fn log_set_writer_func(func: /*Unimplemented*/Fn(/*Ignored*/LogLevelFlags, /*Ignored*/Vec, usize) -> /*Ignored*/LogWriterOutput, user_data: /*Unimplemented*/Option) { // unsafe { TODO: call glib_sys:g_log_set_writer_func() } //} //#[cfg(any(feature = "v2_50", feature = "dox"))] //pub fn log_structured(log_domain: &str, log_level: /*Ignored*/LogLevelFlags, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) { // unsafe { TODO: call glib_sys:g_log_structured() } //} //#[cfg(any(feature = "v2_50", feature = "dox"))] //pub fn log_structured_array(log_level: /*Ignored*/LogLevelFlags, fields: /*Ignored*/&[&LogField]) { // unsafe { TODO: call glib_sys:g_log_structured_array() } //} //pub fn log_structured_standard(log_domain: &str, log_level: /*Ignored*/LogLevelFlags, file: &str, line: &str, func: &str, message_format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) { // unsafe { TODO: call glib_sys:g_log_structured_standard() } //} //#[cfg(any(feature = "v2_50", feature = "dox"))] //pub fn log_variant(log_domain: Option<&str>, log_level: /*Ignored*/LogLevelFlags, fields: &Variant) { // unsafe { TODO: call glib_sys:g_log_variant() } //} //#[cfg(any(feature = "v2_50", feature = "dox"))] //pub fn log_writer_default(log_level: /*Ignored*/LogLevelFlags, fields: /*Ignored*/&[&LogField], user_data: /*Unimplemented*/Option) -> /*Ignored*/LogWriterOutput { // unsafe { TODO: call glib_sys:g_log_writer_default() } //} //#[cfg(any(feature = "v2_50", feature = "dox"))] //pub fn log_writer_format_fields(log_level: /*Ignored*/LogLevelFlags, fields: /*Ignored*/&[&LogField], use_color: bool) -> Option { // unsafe { TODO: call glib_sys:g_log_writer_format_fields() } //} //#[cfg(any(feature = "v2_50", feature = "dox"))] //pub fn log_writer_journald(log_level: /*Ignored*/LogLevelFlags, fields: /*Ignored*/&[&LogField], user_data: /*Unimplemented*/Option) -> /*Ignored*/LogWriterOutput { // unsafe { TODO: call glib_sys:g_log_writer_journald() } //} //#[cfg(any(feature = "v2_50", feature = "dox"))] //pub fn log_writer_standard_streams(log_level: /*Ignored*/LogLevelFlags, fields: /*Ignored*/&[&LogField], user_data: /*Unimplemented*/Option) -> /*Ignored*/LogWriterOutput { // unsafe { TODO: call glib_sys:g_log_writer_standard_streams() } //} //pub fn logv(log_domain: Option<&str>, log_level: /*Ignored*/LogLevelFlags, format: &str, args: /*Unknown conversion*//*Unimplemented*/Unsupported) { // unsafe { TODO: call glib_sys:g_logv() } //} pub fn main_current_source() -> Option { unsafe { from_glib_none(glib_sys::g_main_current_source()) } } pub fn main_depth() -> i32 { unsafe { glib_sys::g_main_depth() } } //pub fn malloc(n_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_malloc() } //} //pub fn malloc0(n_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_malloc0() } //} //pub fn malloc0_n(n_blocks: usize, n_block_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_malloc0_n() } //} //pub fn malloc_n(n_blocks: usize, n_block_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_malloc_n() } //} //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 glib_sys:g_markup_collect_attributes() } //} pub fn markup_escape_text(text: &str) -> GString { let length = text.len() as isize; unsafe { from_glib_full(glib_sys::g_markup_escape_text( text.to_glib_none().0, length, )) } } //pub fn markup_printf_escaped(format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> Option { // unsafe { TODO: call glib_sys:g_markup_printf_escaped() } //} //pub fn markup_vprintf_escaped(format: &str, args: /*Unknown conversion*//*Unimplemented*/Unsupported) -> Option { // unsafe { TODO: call glib_sys:g_markup_vprintf_escaped() } //} #[cfg_attr(feature = "v2_46", deprecated)] pub fn mem_is_system_malloc() -> bool { unsafe { from_glib(glib_sys::g_mem_is_system_malloc()) } } #[cfg_attr(feature = "v2_46", deprecated)] pub fn mem_profile() { unsafe { glib_sys::g_mem_profile(); } } //#[cfg_attr(feature = "v2_46", deprecated)] //pub fn mem_set_vtable(vtable: /*Ignored*/&mut MemVTable) { // unsafe { TODO: call glib_sys:g_mem_set_vtable() } //} //pub fn memdup(mem: /*Unimplemented*/Option, byte_size: u32) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_memdup() } //} pub fn mkdir_with_parents>(pathname: P, mode: i32) -> i32 { unsafe { glib_sys::g_mkdir_with_parents(pathname.as_ref().to_glib_none().0, mode) } } pub fn mkdtemp>(tmpl: P) -> Option { unsafe { from_glib_full(glib_sys::g_mkdtemp(tmpl.as_ref().to_glib_none().0)) } } pub fn mkdtemp_full>(tmpl: P, mode: i32) -> Option { unsafe { from_glib_full(glib_sys::g_mkdtemp_full( tmpl.as_ref().to_glib_none().0, mode, )) } } pub fn mkstemp_full>(tmpl: P, flags: i32, mode: i32) -> i32 { unsafe { glib_sys::g_mkstemp_full(tmpl.as_ref().to_glib_none().0, flags, mode) } } //pub fn nullify_pointer(nullify_location: /*Unimplemented*/Fundamental: Pointer) { // unsafe { TODO: call glib_sys:g_nullify_pointer() } //} pub fn on_error_query(prg_name: &str) { unsafe { glib_sys::g_on_error_query(prg_name.to_glib_none().0); } } pub fn on_error_stack_trace(prg_name: &str) { unsafe { glib_sys::g_on_error_stack_trace(prg_name.to_glib_none().0); } } //pub fn parse_debug_string(string: Option<&str>, keys: /*Ignored*/&[&DebugKey]) -> u32 { // unsafe { TODO: call glib_sys:g_parse_debug_string() } //} pub fn path_get_basename>(file_name: P) -> Option { unsafe { from_glib_full(glib_sys::g_path_get_basename( file_name.as_ref().to_glib_none().0, )) } } pub fn path_get_dirname>(file_name: P) -> Option { unsafe { from_glib_full(glib_sys::g_path_get_dirname( file_name.as_ref().to_glib_none().0, )) } } pub fn path_is_absolute>(file_name: P) -> bool { unsafe { from_glib(glib_sys::g_path_is_absolute( file_name.as_ref().to_glib_none().0, )) } } pub fn path_skip_root>(file_name: P) -> Option { unsafe { from_glib_none(glib_sys::g_path_skip_root( file_name.as_ref().to_glib_none().0, )) } } //pub fn pattern_match(pspec: /*Ignored*/&mut PatternSpec, string_length: u32, string: &str, string_reversed: Option<&str>) -> bool { // unsafe { TODO: call glib_sys:g_pattern_match() } //} pub fn pattern_match_simple(pattern: &str, string: &str) -> bool { unsafe { from_glib(glib_sys::g_pattern_match_simple( pattern.to_glib_none().0, string.to_glib_none().0, )) } } //pub fn pattern_match_string(pspec: /*Ignored*/&mut PatternSpec, string: &str) -> bool { // unsafe { TODO: call glib_sys:g_pattern_match_string() } //} //pub fn pointer_bit_lock(address: /*Unimplemented*/Fundamental: Pointer, lock_bit: i32) { // unsafe { TODO: call glib_sys:g_pointer_bit_lock() } //} //pub fn pointer_bit_trylock(address: /*Unimplemented*/Fundamental: Pointer, lock_bit: i32) -> bool { // unsafe { TODO: call glib_sys:g_pointer_bit_trylock() } //} //pub fn pointer_bit_unlock(address: /*Unimplemented*/Fundamental: Pointer, lock_bit: i32) { // unsafe { TODO: call glib_sys:g_pointer_bit_unlock() } //} //pub fn poll(fds: /*Ignored*/&mut PollFD, nfds: u32, timeout: i32) -> i32 { // unsafe { TODO: call glib_sys:g_poll() } //} //pub fn prefix_error(err: /*Unimplemented*/Option, format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) { // unsafe { TODO: call glib_sys:g_prefix_error() } //} //pub fn print(format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) { // unsafe { TODO: call glib_sys:g_print() } //} //pub fn printerr(format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) { // unsafe { TODO: call glib_sys:g_printerr() } //} //pub fn printf(format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> i32 { // unsafe { TODO: call glib_sys:g_printf() } //} //pub fn printf_string_upper_bound(format: &str, args: /*Unknown conversion*//*Unimplemented*/Unsupported) -> usize { // unsafe { TODO: call glib_sys:g_printf_string_upper_bound() } //} //pub fn propagate_prefixed_error(dest: &mut Error, src: &mut Error, format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) { // unsafe { TODO: call glib_sys:g_propagate_prefixed_error() } //} //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 glib_sys:g_qsort_with_data() } //} pub fn random_double() -> f64 { unsafe { glib_sys::g_random_double() } } pub fn random_double_range(begin: f64, end: f64) -> f64 { unsafe { glib_sys::g_random_double_range(begin, end) } } pub fn random_int() -> u32 { unsafe { glib_sys::g_random_int() } } pub fn random_int_range(begin: i32, end: i32) -> i32 { unsafe { glib_sys::g_random_int_range(begin, end) } } pub fn random_set_seed(seed: u32) { unsafe { glib_sys::g_random_set_seed(seed); } } //pub fn realloc(mem: /*Unimplemented*/Option, n_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_realloc() } //} //pub fn realloc_n(mem: /*Unimplemented*/Option, n_blocks: usize, n_block_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_realloc_n() } //} pub fn reload_user_special_dirs_cache() { unsafe { glib_sys::g_reload_user_special_dirs_cache(); } } pub fn return_if_fail_warning( log_domain: Option<&str>, pretty_function: &str, expression: Option<&str>, ) { unsafe { glib_sys::g_return_if_fail_warning( log_domain.to_glib_none().0, pretty_function.to_glib_none().0, expression.to_glib_none().0, ); } } pub fn rmdir>(filename: P) -> i32 { unsafe { glib_sys::g_rmdir(filename.as_ref().to_glib_none().0) } } pub fn set_application_name(application_name: &str) { unsafe { glib_sys::g_set_application_name(application_name.to_glib_none().0); } } //pub fn set_error(domain: Quark, code: i32, format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> Error { // unsafe { TODO: call glib_sys:g_set_error() } //} //pub fn set_print_handler(func: P) -> Option> { // unsafe { TODO: call glib_sys:g_set_print_handler() } //} //pub fn set_printerr_handler(func: P) -> Option> { // unsafe { TODO: call glib_sys:g_set_printerr_handler() } //} pub fn shell_parse_argv>( command_line: P, ) -> Result, Error> { unsafe { let mut argcp = mem::uninitialized(); let mut argvp = ptr::null_mut(); let mut error = ptr::null_mut(); let _ = glib_sys::g_shell_parse_argv( command_line.as_ref().to_glib_none().0, &mut argcp, &mut argvp, &mut error, ); if error.is_null() { Ok(FromGlibContainer::from_glib_full_num(argvp, argcp as usize)) } else { Err(from_glib_full(error)) } } } pub fn shell_quote>(unquoted_string: P) -> Option { unsafe { from_glib_full(glib_sys::g_shell_quote( unquoted_string.as_ref().to_glib_none().0, )) } } pub fn shell_unquote>( quoted_string: P, ) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = glib_sys::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)) } } } //pub fn slice_alloc(block_size: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_slice_alloc() } //} //pub fn slice_alloc0(block_size: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_slice_alloc0() } //} //pub fn slice_copy(block_size: usize, mem_block: /*Unimplemented*/Option) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_slice_copy() } //} //pub fn slice_free1(block_size: usize, mem_block: /*Unimplemented*/Option) { // unsafe { TODO: call glib_sys:g_slice_free1() } //} //pub fn slice_free_chain_with_offset(block_size: usize, mem_chain: /*Unimplemented*/Option, next_offset: usize) { // unsafe { TODO: call glib_sys:g_slice_free_chain_with_offset() } //} //pub fn slice_get_config(ckey: /*Ignored*/SliceConfig) -> i64 { // unsafe { TODO: call glib_sys:g_slice_get_config() } //} //pub fn slice_get_config_state(ckey: /*Ignored*/SliceConfig, address: i64, n_values: u32) -> i64 { // unsafe { TODO: call glib_sys:g_slice_get_config_state() } //} //pub fn slice_set_config(ckey: /*Ignored*/SliceConfig, value: i64) { // unsafe { TODO: call glib_sys:g_slice_set_config() } //} //pub fn snprintf(string: &str, n: libc::c_ulong, format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> i32 { // unsafe { TODO: call glib_sys:g_snprintf() } //} pub fn spaced_primes_closest(num: u32) -> u32 { unsafe { glib_sys::g_spaced_primes_closest(num) } } //pub fn spawn_async>(working_directory: P, argv: &[&std::path::Path], envp: &[&std::path::Path], flags: SpawnFlags, child_setup: Option>) -> Result { // unsafe { TODO: call glib_sys:g_spawn_async() } //} //#[cfg(any(feature = "v2_58", feature = "dox"))] //pub fn spawn_async_with_fds>(working_directory: P, argv: &[&str], envp: &[&str], flags: SpawnFlags, child_setup: Option>, stdin_fd: i32, stdout_fd: i32, stderr_fd: i32) -> Result { // unsafe { TODO: call glib_sys:g_spawn_async_with_fds() } //} //pub fn spawn_async_with_pipes>(working_directory: P, argv: &[&std::path::Path], envp: &[&std::path::Path], flags: SpawnFlags, child_setup: Option>) -> Result<(Pid, i32, i32, i32), Error> { // unsafe { TODO: call glib_sys:g_spawn_async_with_pipes() } //} pub fn spawn_check_exit_status(exit_status: i32) -> Result<(), Error> { unsafe { let mut error = ptr::null_mut(); let _ = glib_sys::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"))] pub fn spawn_command_line_async>(command_line: P) -> Result<(), Error> { unsafe { let mut error = ptr::null_mut(); let _ = glib_sys::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)) } } } //pub fn spawn_command_line_sync>(command_line: P, standard_output: Vec, standard_error: Vec) -> Result { // unsafe { TODO: call glib_sys:g_spawn_command_line_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 glib_sys:g_spawn_sync() } //} //pub fn sprintf(string: &str, format: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> i32 { // unsafe { TODO: call glib_sys:g_sprintf() } //} pub fn stpcpy(dest: &str, src: &str) -> Option { unsafe { from_glib_full(glib_sys::g_stpcpy( dest.to_glib_none().0, src.to_glib_none().0, )) } } //pub fn try_malloc(n_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_try_malloc() } //} //pub fn try_malloc0(n_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_try_malloc0() } //} //pub fn try_malloc0_n(n_blocks: usize, n_block_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_try_malloc0_n() } //} //pub fn try_malloc_n(n_blocks: usize, n_block_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_try_malloc_n() } //} //pub fn try_realloc(mem: /*Unimplemented*/Option, n_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_try_realloc() } //} //pub fn try_realloc_n(mem: /*Unimplemented*/Option, n_blocks: usize, n_block_bytes: usize) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_try_realloc_n() } //} //pub fn unicode_script_from_iso15924(iso15924: u32) -> /*Ignored*/UnicodeScript { // unsafe { TODO: call glib_sys:g_unicode_script_from_iso15924() } //} //pub fn unicode_script_to_iso15924(script: /*Ignored*/UnicodeScript) -> u32 { // unsafe { TODO: call glib_sys:g_unicode_script_to_iso15924() } //} pub fn unlink>(filename: P) -> i32 { unsafe { glib_sys::g_unlink(filename.as_ref().to_glib_none().0) } } pub fn uri_escape_string( unescaped: &str, reserved_chars_allowed: Option<&str>, allow_utf8: bool, ) -> Option { unsafe { from_glib_full(glib_sys::g_uri_escape_string( unescaped.to_glib_none().0, reserved_chars_allowed.to_glib_none().0, allow_utf8.to_glib(), )) } } pub fn uri_list_extract_uris(uri_list: &str) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(glib_sys::g_uri_list_extract_uris( uri_list.to_glib_none().0, )) } } pub fn uri_parse_scheme(uri: &str) -> Option { unsafe { from_glib_full(glib_sys::g_uri_parse_scheme(uri.to_glib_none().0)) } } pub fn uri_unescape_segment( escaped_string: Option<&str>, escaped_string_end: Option<&str>, illegal_characters: Option<&str>, ) -> Option { unsafe { from_glib_full(glib_sys::g_uri_unescape_segment( escaped_string.to_glib_none().0, escaped_string_end.to_glib_none().0, illegal_characters.to_glib_none().0, )) } } pub fn uri_unescape_string( escaped_string: &str, illegal_characters: Option<&str>, ) -> Option { unsafe { from_glib_full(glib_sys::g_uri_unescape_string( escaped_string.to_glib_none().0, illegal_characters.to_glib_none().0, )) } } pub fn usleep(microseconds: libc::c_ulong) { unsafe { glib_sys::g_usleep(microseconds); } } #[cfg(any(feature = "v2_52", feature = "dox"))] pub fn uuid_string_is_valid(str: &str) -> bool { unsafe { from_glib(glib_sys::g_uuid_string_is_valid(str.to_glib_none().0)) } } #[cfg(any(feature = "v2_52", feature = "dox"))] pub fn uuid_string_random() -> Option { unsafe { from_glib_full(glib_sys::g_uuid_string_random()) } } pub fn variant_get_gtype() -> types::Type { unsafe { from_glib(glib_sys::g_variant_get_gtype()) } } //pub fn vasprintf(string: &str, format: &str, args: /*Unknown conversion*//*Unimplemented*/Unsupported) -> i32 { // unsafe { TODO: call glib_sys:g_vasprintf() } //} //pub fn vfprintf(file: /*Unimplemented*/Fundamental: Pointer, format: &str, args: /*Unknown conversion*//*Unimplemented*/Unsupported) -> i32 { // unsafe { TODO: call glib_sys:g_vfprintf() } //} //pub fn vprintf(format: &str, args: /*Unknown conversion*//*Unimplemented*/Unsupported) -> i32 { // unsafe { TODO: call glib_sys:g_vprintf() } //} //pub fn vsnprintf(string: &str, n: libc::c_ulong, format: &str, args: /*Unknown conversion*//*Unimplemented*/Unsupported) -> i32 { // unsafe { TODO: call glib_sys:g_vsnprintf() } //} //pub fn vsprintf(string: &str, format: &str, args: /*Unknown conversion*//*Unimplemented*/Unsupported) -> i32 { // unsafe { TODO: call glib_sys:g_vsprintf() } //} pub fn warn_message( domain: Option<&str>, file: &str, line: i32, func: &str, warnexpr: Option<&str>, ) { unsafe { glib_sys::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.8.2/src/auto/key_file.rs010066400017500001750000000406471354212555500145770ustar0000000000000000// 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 glib_sys; use std; use std::mem; use std::ptr; use translate::*; #[cfg(any(feature = "v2_50", feature = "dox"))] use Bytes; use Char; use Error; use GString; use KeyFileFlags; glib_wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct KeyFile(Shared); match fn { ref => |ptr| glib_sys::g_key_file_ref(ptr), unref => |ptr| glib_sys::g_key_file_unref(ptr), get_type => || glib_sys::g_key_file_get_type(), } } impl KeyFile { pub fn new() -> KeyFile { unsafe { from_glib_full(glib_sys::g_key_file_new()) } } pub fn get_comment(&self, group_name: Option<&str>, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = glib_sys::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)) } } } pub fn get_double(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = glib_sys::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)) } } } pub fn get_double_list(&self, group_name: &str, key: &str) -> Result, Error> { unsafe { let mut length = mem::uninitialized(); let mut error = ptr::null_mut(); let ret = glib_sys::g_key_file_get_double_list( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut length, &mut error, ); if error.is_null() { Ok(FromGlibContainer::from_glib_container_num( ret, length as usize, )) } else { Err(from_glib_full(error)) } } } pub fn get_groups(&self) -> (Vec, usize) { unsafe { let mut length = mem::uninitialized(); let ret = FromGlibPtrContainer::from_glib_full(glib_sys::g_key_file_get_groups( self.to_glib_none().0, &mut length, )); (ret, length) } } pub fn get_int64(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = glib_sys::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)) } } } pub fn get_integer(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = glib_sys::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)) } } } pub fn get_integer_list(&self, group_name: &str, key: &str) -> Result, Error> { unsafe { let mut length = mem::uninitialized(); let mut error = ptr::null_mut(); let ret = glib_sys::g_key_file_get_integer_list( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut length, &mut error, ); if error.is_null() { Ok(FromGlibContainer::from_glib_container_num( ret, length as usize, )) } else { Err(from_glib_full(error)) } } } pub fn get_keys(&self, group_name: &str) -> Result<(Vec, usize), Error> { unsafe { let mut length = mem::uninitialized(); let mut error = ptr::null_mut(); let ret = glib_sys::g_key_file_get_keys( self.to_glib_none().0, group_name.to_glib_none().0, &mut length, &mut error, ); if error.is_null() { Ok((FromGlibPtrContainer::from_glib_full(ret), length)) } else { Err(from_glib_full(error)) } } } #[cfg(any(feature = "v2_56", feature = "dox"))] pub fn get_locale_for_key( &self, group_name: &str, key: &str, locale: Option<&str>, ) -> Option { unsafe { from_glib_full(glib_sys::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, )) } } pub fn get_locale_string( &self, group_name: &str, key: &str, locale: Option<&str>, ) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = glib_sys::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 { Err(from_glib_full(error)) } } } pub fn get_locale_string_list( &self, group_name: &str, key: &str, locale: Option<&str>, ) -> Result, Error> { unsafe { let mut length = mem::uninitialized(); let mut error = ptr::null_mut(); let ret = glib_sys::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, &mut length, &mut error, ); if error.is_null() { Ok(FromGlibContainer::from_glib_full_num(ret, length as usize)) } else { Err(from_glib_full(error)) } } } pub fn get_start_group(&self) -> Option { unsafe { from_glib_full(glib_sys::g_key_file_get_start_group(self.to_glib_none().0)) } } pub fn get_string(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = glib_sys::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 { Err(from_glib_full(error)) } } } pub fn get_string_list(&self, group_name: &str, key: &str) -> Result, Error> { unsafe { let mut length = mem::uninitialized(); let mut error = ptr::null_mut(); let ret = glib_sys::g_key_file_get_string_list( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut length, &mut error, ); if error.is_null() { Ok(FromGlibContainer::from_glib_full_num(ret, length as usize)) } else { Err(from_glib_full(error)) } } } pub fn get_uint64(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = glib_sys::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)) } } } pub fn get_value(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = glib_sys::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)) } } } pub fn has_group(&self, group_name: &str) -> bool { unsafe { from_glib(glib_sys::g_key_file_has_group( self.to_glib_none().0, group_name.to_glib_none().0, )) } } #[cfg(any(feature = "v2_50", feature = "dox"))] pub fn load_from_bytes(&self, bytes: &Bytes, flags: KeyFileFlags) -> Result<(), Error> { unsafe { let mut error = ptr::null_mut(); let _ = glib_sys::g_key_file_load_from_bytes( self.to_glib_none().0, bytes.to_glib_none().0, flags.to_glib(), &mut error, ); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } pub fn load_from_data(&self, data: &str, flags: KeyFileFlags) -> Result<(), Error> { let length = data.len() as usize; unsafe { let mut error = ptr::null_mut(); let _ = glib_sys::g_key_file_load_from_data( self.to_glib_none().0, data.to_glib_none().0, length, flags.to_glib(), &mut error, ); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } pub fn load_from_file>( &self, file: P, flags: KeyFileFlags, ) -> Result<(), Error> { unsafe { let mut error = ptr::null_mut(); let _ = glib_sys::g_key_file_load_from_file( self.to_glib_none().0, file.as_ref().to_glib_none().0, flags.to_glib(), &mut error, ); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } pub fn remove_comment(&self, group_name: Option<&str>, key: Option<&str>) -> Result<(), Error> { unsafe { let mut error = ptr::null_mut(); let _ = glib_sys::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)) } } } pub fn remove_group(&self, group_name: &str) -> Result<(), Error> { unsafe { let mut error = ptr::null_mut(); let _ = glib_sys::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)) } } } pub fn remove_key(&self, group_name: &str, key: &str) -> Result<(), Error> { unsafe { let mut error = ptr::null_mut(); let _ = glib_sys::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)) } } } pub fn set_boolean(&self, group_name: &str, key: &str, value: bool) { unsafe { glib_sys::g_key_file_set_boolean( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, value.to_glib(), ); } } //pub fn set_boolean_list(&self, group_name: &str, key: &str, list: /*Unimplemented*/&CArray TypeId { ns_id: 0, id: 1 }) { // unsafe { TODO: call glib_sys:g_key_file_set_boolean_list() } //} pub fn set_comment( &self, group_name: Option<&str>, key: Option<&str>, comment: &str, ) -> Result<(), Error> { unsafe { let mut error = ptr::null_mut(); let _ = glib_sys::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)) } } } pub fn set_double(&self, group_name: &str, key: &str, value: f64) { unsafe { glib_sys::g_key_file_set_double( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, value, ); } } pub fn set_int64(&self, group_name: &str, key: &str, value: i64) { unsafe { glib_sys::g_key_file_set_int64( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, value, ); } } pub fn set_integer(&self, group_name: &str, key: &str, value: i32) { unsafe { glib_sys::g_key_file_set_integer( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, value, ); } } pub fn set_list_separator(&self, separator: Char) { unsafe { glib_sys::g_key_file_set_list_separator(self.to_glib_none().0, separator.to_glib()); } } pub fn set_locale_string(&self, group_name: &str, key: &str, locale: &str, string: &str) { unsafe { glib_sys::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, ); } } pub fn set_string(&self, group_name: &str, key: &str, string: &str) { unsafe { glib_sys::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, ); } } pub fn set_uint64(&self, group_name: &str, key: &str, value: u64) { unsafe { glib_sys::g_key_file_set_uint64( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, value, ); } } pub fn set_value(&self, group_name: &str, key: &str, value: &str) { unsafe { glib_sys::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.8.2/src/auto/main_context.rs010066400017500001750000000101211352206036300154510ustar0000000000000000// 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 glib_sys; use translate::*; glib_wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MainContext(Shared); match fn { ref => |ptr| glib_sys::g_main_context_ref(ptr), unref => |ptr| glib_sys::g_main_context_unref(ptr), get_type => || glib_sys::g_main_context_get_type(), } } impl MainContext { pub fn new() -> MainContext { unsafe { from_glib_full(glib_sys::g_main_context_new()) } } pub fn acquire(&self) -> bool { unsafe { from_glib(glib_sys::g_main_context_acquire(self.to_glib_none().0)) } } //pub fn add_poll(&self, fd: /*Ignored*/&mut PollFD, priority: i32) { // unsafe { TODO: call glib_sys:g_main_context_add_poll() } //} //pub fn check(&self, max_priority: i32, fds: /*Ignored*/&[&PollFD]) -> bool { // unsafe { TODO: call glib_sys:g_main_context_check() } //} pub fn dispatch(&self) { unsafe { glib_sys::g_main_context_dispatch(self.to_glib_none().0); } } //pub fn find_source_by_funcs_user_data(&self, funcs: /*Ignored*/&mut SourceFuncs, user_data: /*Unimplemented*/Option) -> Option { // unsafe { TODO: call glib_sys:g_main_context_find_source_by_funcs_user_data() } //} //pub fn find_source_by_user_data(&self, user_data: /*Unimplemented*/Option) -> Option { // unsafe { TODO: call glib_sys:g_main_context_find_source_by_user_data() } //} //pub fn get_poll_func(&self) -> /*Unimplemented*/Fn(/*Ignored*/PollFD, u32, i32) -> i32 { // unsafe { TODO: call glib_sys:g_main_context_get_poll_func() } //} pub fn is_owner(&self) -> bool { unsafe { from_glib(glib_sys::g_main_context_is_owner(self.to_glib_none().0)) } } pub fn iteration(&self, may_block: bool) -> bool { unsafe { from_glib(glib_sys::g_main_context_iteration( self.to_glib_none().0, may_block.to_glib(), )) } } pub fn pending(&self) -> bool { unsafe { from_glib(glib_sys::g_main_context_pending(self.to_glib_none().0)) } } pub fn pop_thread_default(&self) { unsafe { glib_sys::g_main_context_pop_thread_default(self.to_glib_none().0); } } pub fn push_thread_default(&self) { unsafe { glib_sys::g_main_context_push_thread_default(self.to_glib_none().0); } } //pub fn query(&self, max_priority: i32, fds: /*Ignored*/Vec) -> (i32, i32) { // unsafe { TODO: call glib_sys:g_main_context_query() } //} pub fn release(&self) { unsafe { glib_sys::g_main_context_release(self.to_glib_none().0); } } //pub fn remove_poll(&self, fd: /*Ignored*/&mut PollFD) { // unsafe { TODO: call glib_sys:g_main_context_remove_poll() } //} //pub fn set_poll_func(&self, func: /*Unimplemented*/Fn(/*Ignored*/PollFD, u32, i32) -> i32) { // unsafe { TODO: call glib_sys:g_main_context_set_poll_func() } //} //#[cfg_attr(feature = "v2_58", deprecated)] //pub fn wait(&self, cond: /*Ignored*/&mut Cond, mutex: /*Ignored*/&mut Mutex) -> bool { // unsafe { TODO: call glib_sys:g_main_context_wait() } //} pub fn wakeup(&self) { unsafe { glib_sys::g_main_context_wakeup(self.to_glib_none().0); } } pub fn default() -> MainContext { unsafe { from_glib_none(glib_sys::g_main_context_default()) } } pub fn get_thread_default() -> Option { unsafe { from_glib_none(glib_sys::g_main_context_get_thread_default()) } } pub fn ref_thread_default() -> MainContext { unsafe { from_glib_full(glib_sys::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.8.2/src/auto/main_loop.rs010066400017500001750000000025361352206036300147510ustar0000000000000000// 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 glib_sys; use translate::*; use MainContext; glib_wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MainLoop(Shared); match fn { ref => |ptr| glib_sys::g_main_loop_ref(ptr), unref => |ptr| glib_sys::g_main_loop_unref(ptr), get_type => || glib_sys::g_main_loop_get_type(), } } impl MainLoop { pub fn new(context: Option<&MainContext>, is_running: bool) -> MainLoop { unsafe { from_glib_full(glib_sys::g_main_loop_new( context.to_glib_none().0, is_running.to_glib(), )) } } pub fn get_context(&self) -> MainContext { unsafe { from_glib_none(glib_sys::g_main_loop_get_context(self.to_glib_none().0)) } } pub fn is_running(&self) -> bool { unsafe { from_glib(glib_sys::g_main_loop_is_running(self.to_glib_none().0)) } } pub fn quit(&self) { unsafe { glib_sys::g_main_loop_quit(self.to_glib_none().0); } } pub fn run(&self) { unsafe { glib_sys::g_main_loop_run(self.to_glib_none().0); } } } unsafe impl Send for MainLoop {} unsafe impl Sync for MainLoop {} glib-0.8.2/src/auto/mod.rs010066400017500001750000000060601354212555500135560ustar0000000000000000// 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; 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; mod flags; pub use self::flags::FileTest; pub use self::flags::FormatSizeFlags; pub use self::flags::IOCondition; pub use self::flags::KeyFileFlags; pub use self::flags::OptionFlags; pub use self::flags::SpawnFlags; 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_ACTION_GROUP_PREFIX; 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_FULLNAME; pub use self::constants::KEY_FILE_DESKTOP_KEY_GENERIC_NAME; pub use self::constants::KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN; 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_KEYWORDS; 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; 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.8.2/src/auto/source.rs010066400017500001750000000071071352206036300142730ustar0000000000000000// 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 glib_sys; use translate::*; use GString; use MainContext; glib_wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Source(Shared); match fn { ref => |ptr| glib_sys::g_source_ref(ptr), unref => |ptr| glib_sys::g_source_unref(ptr), get_type => || glib_sys::g_source_get_type(), } } impl Source { //pub fn new(source_funcs: /*Ignored*/&mut SourceFuncs, struct_size: u32) -> Source { // unsafe { TODO: call glib_sys:g_source_new() } //} pub fn add_child_source(&self, child_source: &Source) { unsafe { glib_sys::g_source_add_child_source( self.to_glib_none().0, child_source.to_glib_none().0, ); } } //pub fn add_poll(&self, fd: /*Ignored*/&mut PollFD) { // unsafe { TODO: call glib_sys:g_source_add_poll() } //} //pub fn add_unix_fd(&self, fd: i32, events: IOCondition) -> /*Unimplemented*/Option { // unsafe { TODO: call glib_sys:g_source_add_unix_fd() } //} pub fn destroy(&self) { unsafe { glib_sys::g_source_destroy(self.to_glib_none().0); } } pub fn get_can_recurse(&self) -> bool { unsafe { from_glib(glib_sys::g_source_get_can_recurse(self.to_glib_none().0)) } } pub fn get_context(&self) -> Option { unsafe { from_glib_none(glib_sys::g_source_get_context(self.to_glib_none().0)) } } pub fn get_name(&self) -> Option { unsafe { from_glib_none(glib_sys::g_source_get_name(self.to_glib_none().0)) } } pub fn get_priority(&self) -> i32 { unsafe { glib_sys::g_source_get_priority(self.to_glib_none().0) } } pub fn get_ready_time(&self) -> i64 { unsafe { glib_sys::g_source_get_ready_time(self.to_glib_none().0) } } pub fn get_time(&self) -> i64 { unsafe { glib_sys::g_source_get_time(self.to_glib_none().0) } } pub fn is_destroyed(&self) -> bool { unsafe { from_glib(glib_sys::g_source_is_destroyed(self.to_glib_none().0)) } } //pub fn modify_unix_fd(&self, tag: /*Unimplemented*/Fundamental: Pointer, new_events: IOCondition) { // unsafe { TODO: call glib_sys:g_source_modify_unix_fd() } //} //pub fn query_unix_fd(&self, tag: /*Unimplemented*/Fundamental: Pointer) -> IOCondition { // unsafe { TODO: call glib_sys:g_source_query_unix_fd() } //} pub fn remove_child_source(&self, child_source: &Source) { unsafe { glib_sys::g_source_remove_child_source( self.to_glib_none().0, child_source.to_glib_none().0, ); } } //pub fn remove_poll(&self, fd: /*Ignored*/&mut PollFD) { // unsafe { TODO: call glib_sys:g_source_remove_poll() } //} //pub fn remove_unix_fd(&self, tag: /*Unimplemented*/Fundamental: Pointer) { // unsafe { TODO: call glib_sys:g_source_remove_unix_fd() } //} //pub fn remove_by_funcs_user_data(funcs: /*Ignored*/&mut SourceFuncs, user_data: /*Unimplemented*/Option) -> bool { // unsafe { TODO: call glib_sys:g_source_remove_by_funcs_user_data() } //} //pub fn remove_by_user_data(user_data: /*Unimplemented*/Option) -> bool { // unsafe { TODO: call glib_sys:g_source_remove_by_user_data() } //} } unsafe impl Send for Source {} unsafe impl Sync for Source {} glib-0.8.2/src/auto/time_zone.rs010066400017500001750000000042071352206036300147620ustar0000000000000000// 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 glib_sys; use translate::*; use GString; use TimeType; glib_wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct TimeZone(Shared); match fn { ref => |ptr| glib_sys::g_time_zone_ref(ptr), unref => |ptr| glib_sys::g_time_zone_unref(ptr), get_type => || glib_sys::g_time_zone_get_type(), } } impl TimeZone { pub fn new(identifier: Option<&str>) -> TimeZone { unsafe { from_glib_full(glib_sys::g_time_zone_new(identifier.to_glib_none().0)) } } pub fn new_local() -> TimeZone { unsafe { from_glib_full(glib_sys::g_time_zone_new_local()) } } #[cfg(any(feature = "v2_58", feature = "dox"))] pub fn new_offset(seconds: i32) -> TimeZone { unsafe { from_glib_full(glib_sys::g_time_zone_new_offset(seconds)) } } pub fn new_utc() -> TimeZone { unsafe { from_glib_full(glib_sys::g_time_zone_new_utc()) } } pub fn find_interval(&self, type_: TimeType, time_: i64) -> i32 { unsafe { glib_sys::g_time_zone_find_interval(self.to_glib_none().0, type_.to_glib(), time_) } } pub fn get_abbreviation(&self, interval: i32) -> Option { unsafe { from_glib_none(glib_sys::g_time_zone_get_abbreviation( self.to_glib_none().0, interval, )) } } #[cfg(any(feature = "v2_58", feature = "dox"))] pub fn get_identifier(&self) -> Option { unsafe { from_glib_none(glib_sys::g_time_zone_get_identifier(self.to_glib_none().0)) } } pub fn get_offset(&self, interval: i32) -> i32 { unsafe { glib_sys::g_time_zone_get_offset(self.to_glib_none().0, interval) } } pub fn is_dst(&self, interval: i32) -> bool { unsafe { from_glib(glib_sys::g_time_zone_is_dst( self.to_glib_none().0, interval, )) } } } unsafe impl Send for TimeZone {} unsafe impl Sync for TimeZone {} glib-0.8.2/src/auto/versions.txt010066400017500001750000000001721354212555500150400ustar0000000000000000Generated by gir (https://github.com/gtk-rs/gir @ 7d51043) from gir-files (https://github.com/gtk-rs/gir-files @ 617a344) glib-0.8.2/src/boxed.rs010066400017500001750000000465461354212555500131450ustar0000000000000000// Copyright 2015-2016, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or //! `IMPL` Boxed wrapper implementation. 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; use translate::*; /// Wrapper implementations for Boxed types. See `glib_wrapper!`. #[macro_export] macro_rules! glib_boxed_wrapper { ([$($attr:meta)*] $name:ident, $ffi_name:path, @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, @get_type $get_type_expr:expr) => { glib_boxed_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name); 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); glib_boxed_wrapper!(@value_impl $name, $ffi_name, @get_type $get_type_expr); }; ([$($attr:meta)*] $name:ident, $ffi_name:path, @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) => { glib_boxed_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name); 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:path, @copy $copy_arg:ident $copy_expr:expr, @free $free_arg:ident $free_expr:expr) => { glib_boxed_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name); 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:path, @copy $copy_arg:ident $copy_expr:expr, @free $free_arg:ident $free_expr:expr, @get_type $get_type_expr:expr) => { glib_boxed_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name); glib_boxed_wrapper!(@memory_manager_impl $name, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr); glib_boxed_wrapper!(@value_impl $name, $ffi_name, @get_type $get_type_expr); }; (@generic_impl [$($attr:meta)*] $name:ident, $ffi_name:path) => { $(#[$attr])* #[derive(Clone)] pub struct $name($crate::boxed::Boxed<$ffi_name, MemoryManager>); #[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, MemoryManager>; #[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, MemoryManager>; #[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::glib_sys::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::glib_sys::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::FromGlibPtrBorrow<*mut $ffi_name> for $name { #[inline] unsafe fn from_glib_borrow(ptr: *mut $ffi_name) -> Self { $name($crate::translate::from_glib_borrow(ptr)) } } #[doc(hidden)] impl $crate::translate::FromGlibPtrBorrow<*const $ffi_name> for $name { #[inline] unsafe fn from_glib_borrow(ptr: *const $ffi_name) -> Self { $crate::translate::from_glib_borrow(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::glib_sys::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::glib_sys::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:path, @get_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<'a> $crate::value::FromValueOptional<'a> for $name { unsafe fn from_value_optional(value: &$crate::Value) -> Option { $crate::translate::from_glib_full($crate::gobject_sys::g_value_dup_boxed($crate::translate::ToGlibPtr::to_glib_none(value).0) as *mut $ffi_name) } } #[doc(hidden)] impl $crate::value::SetValue for $name { unsafe fn set_value(value: &mut $crate::Value, this: &Self) { $crate::gobject_sys::g_value_set_boxed($crate::translate::ToGlibPtrMut::to_glib_none_mut(value).0, $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(this).0 as $crate::glib_sys::gpointer) } } #[doc(hidden)] impl $crate::value::SetValueOptional for $name { unsafe fn set_value_optional(value: &mut $crate::Value, this: Option<&Self>) { $crate::gobject_sys::g_value_set_boxed($crate::translate::ToGlibPtrMut::to_glib_none_mut(value).0, $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(&this).0 as $crate::glib_sys::gpointer) } } }; (@memory_manager_impl $name:ident, $ffi_name:path, @copy $copy_arg:ident $copy_expr:expr, @free $free_arg:ident $free_expr:expr) => { #[doc(hidden)] pub struct MemoryManager; impl $crate::boxed::BoxedMemoryManager<$ffi_name> for MemoryManager { #[inline] unsafe fn copy($copy_arg: *const $ffi_name) -> *mut $ffi_name { $copy_expr } #[inline] 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:path, @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)] pub struct MemoryManager; impl $crate::boxed::BoxedMemoryManager<$ffi_name> for MemoryManager { #[inline] unsafe fn copy($copy_arg: *const $ffi_name) -> *mut $ffi_name { $copy_expr } #[inline] unsafe fn free($free_arg: *mut $ffi_name) { $free_expr } #[inline] unsafe fn init($init_arg: *mut $ffi_name) { $init_expr } #[inline] 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), ForeignOwned(ptr::NonNull), ForeignBorrowed(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(), ForeignOwned(ptr) => f.debug_tuple("ForeignOwned").field(&ptr).finish(), ForeignBorrowed(ptr) => f.debug_tuple("ForeignBorrowed").field(&ptr).finish(), } } } /// 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, } impl> Uninitialized for Boxed { #[inline] unsafe fn uninitialized() -> Self { Boxed { inner: { let mut inner = Box::::new(mem::zeroed()); MM::init(&mut *inner); AnyBox::Native(inner) }, _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, ForeignOwned(p) | ForeignBorrowed(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, ForeignOwned(p) | ForeignBorrowed(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, ForeignOwned(p) | ForeignBorrowed(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()); Boxed { inner: AnyBox::ForeignOwned(ptr::NonNull::new_unchecked(ptr)), _dummy: PhantomData, } } } impl> FromGlibPtrBorrow<*mut T> for Boxed { #[inline] unsafe fn from_glib_borrow(ptr: *mut T) -> Self { assert!(!ptr.is_null()); Boxed { inner: AnyBox::ForeignBorrowed(ptr::NonNull::new_unchecked(ptr)), _dummy: PhantomData, } } } impl> Drop for Boxed { #[inline] fn drop(&mut self) { unsafe { match self.inner { AnyBox::ForeignOwned(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.8.2/src/byte_array.rs010066400017500001750000000156411354212555500141750ustar0000000000000000// Copyright 2019, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or //! # 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 glib_sys; 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 translate::*; use Bytes; glib_wrapper! { pub struct ByteArray(Shared); match fn { ref => |ptr| glib_sys::g_byte_array_ref(ptr), unref => |ptr| glib_sys::g_byte_array_unref(ptr), get_type => || glib_sys::g_byte_array_get_type(), } } impl ByteArray { pub fn new() -> ByteArray { unsafe { from_glib_full(glib_sys::g_byte_array_new()) } } pub fn with_capacity(size: usize) -> ByteArray { unsafe { from_glib_full(glib_sys::g_byte_array_sized_new(size as u32)) } } pub fn into_gbytes(self) -> Bytes { unsafe { let ret = from_glib_full(glib_sys::g_byte_array_free_to_bytes(mut_override( self.to_glib_none().0, ))); mem::forget(self); ret } } pub fn append>(&self, data: &T) -> &Self { let bytes = data.as_ref(); unsafe { glib_sys::g_byte_array_append( self.to_glib_none().0, bytes.as_ptr() as *const _, bytes.len() as u32, ); } self } pub fn prepend>(&self, data: &T) -> &Self { let bytes = data.as_ref(); unsafe { glib_sys::g_byte_array_prepend( self.to_glib_none().0, bytes.as_ptr() as *const _, bytes.len() as u32, ); } self } pub fn remove_index(&self, index: usize) { unsafe { glib_sys::g_byte_array_remove_index(self.to_glib_none().0, index as u32); } } pub fn remove_index_fast(&self, index: usize) { unsafe { glib_sys::g_byte_array_remove_index_fast(self.to_glib_none().0, index as u32); } } pub fn remove_range(&self, index: usize, length: usize) { unsafe { glib_sys::g_byte_array_remove_range(self.to_glib_none().0, index as u32, length as u32); } } pub fn set_size(&self, size: usize) { unsafe { glib_sys::g_byte_array_set_size(self.to_glib_none().0, size as u32); } } pub fn sort Ordering>(&self, compare_func: F) { unsafe extern "C" fn compare_func_trampoline( a: glib_sys::gconstpointer, b: glib_sys::gconstpointer, func: glib_sys::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 glib_sys::gpointer; glib_sys::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) => { impl<'a, 'b> PartialEq<$rhs> for $lhs { #[inline] fn eq(&self, other: &$rhs) -> bool { self[..].eq(&other[..]) } } impl<'a, 'b> PartialEq<$lhs> for $rhs { #[inline] fn eq(&self, other: &$lhs) -> bool { self[..].eq(&other[..]) } } impl<'a, 'b> PartialOrd<$rhs> for $lhs { #[inline] fn partial_cmp(&self, other: &$rhs) -> Option { self[..].partial_cmp(&other[..]) } } 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.set_size(20); ba.sort(|a, b| a.cmp(b)); let abc: &[u8] = b"abc"; assert_eq!(ByteArray::from(abc), "abc".as_bytes()); } #[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.8.2/src/bytes.rs010066400017500001750000000150441352206036300131500ustar0000000000000000// Copyright 2013-2016, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use glib_sys; 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; use translate::*; glib_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); /// ``` pub struct Bytes(Shared); match fn { ref => |ptr| glib_sys::g_bytes_ref(ptr), unref => |ptr| glib_sys::g_bytes_unref(ptr), get_type => || glib_sys::g_bytes_get_type(), } } impl Bytes { /// Copies `data` into a new shared slice. fn new>(data: T) -> Bytes { let data = data.as_ref(); unsafe { from_glib_full(glib_sys::g_bytes_new(data.as_ptr() as *const _, data.len())) } } /// Creates a view into static `data` without copying. pub fn from_static(data: &'static [u8]) -> Bytes { unsafe { from_glib_full(glib_sys::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: glib_sys::gpointer) { let _: Box = Box::from_raw(b as *mut _); } unsafe { from_glib_full(glib_sys::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 = glib_sys::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 { fn eq(&self, other: &Self) -> bool { unsafe { from_glib(glib_sys::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 = glib_sys::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 = glib_sys::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) => { impl<'a, 'b> PartialEq<$rhs> for $lhs { #[inline] fn eq(&self, other: &$rhs) -> bool { self[..].eq(&other[..]) } } impl<'a, 'b> PartialEq<$lhs> for $rhs { #[inline] fn eq(&self, other: &$lhs) -> bool { self[..].eq(&other[..]) } } impl<'a, 'b> PartialOrd<$rhs> for $lhs { #[inline] fn partial_cmp(&self, other: &$rhs) -> Option { self[..].partial_cmp(&other[..]) } } 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!(a1 != d); assert!(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.8.2/src/char.rs010066400017500001750000000115261352206036300127400ustar0000000000000000use libc::{c_char, c_uchar}; use translate::FromGlib; use translate::ToGlib; /// 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.to_glib()`. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct Char(pub c_char); impl Char { /// Creates a `Some(Char)` if the given `char` is representable as an `libc::c_char` /// /// # Example /// ```ignore /// extern "C" fn have_a_byte(b: libc::c_char); /// /// let a = Char::new('a').unwrap(); /// assert!(a.0 == 65); /// have_a_byte(a.to_glib()); /// /// let not_representable = Char::new('☔'); /// assert!(not_representable.is_none()); /// ``` pub fn new(c: char) -> Option { if c as u32 > 255 { None } else { Some(Char(c as c_char)) } } } impl From for char { fn from(c: Char) -> char { c.0 as u8 as char } } #[doc(hidden)] impl FromGlib for Char { fn from_glib(value: c_char) -> Self { Char(value) } } #[doc(hidden)] impl ToGlib for Char { type GlibType = c_char; fn to_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.to_glib()`. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct UChar(pub c_uchar); impl UChar { /// Creates a `Some(UChar)` if the given `char` is representable as an `libc::c_uchar` /// /// # Example /// ```ignore /// extern "C" fn have_a_byte(b: libc::c_uchar); /// /// let a = Char::new('a').unwrap(); /// assert!(a.0 == 65); /// have_a_byte(a.to_glib()); /// /// let not_representable = Char::new('☔'); /// assert!(not_representable.is_none()); /// ``` pub fn new(c: char) -> Option { if c as u32 > 255 { None } else { Some(UChar(c as c_uchar)) } } } impl From for char { fn from(c: UChar) -> char { c.0 as char } } #[doc(hidden)] impl FromGlib for UChar { fn from_glib(value: c_uchar) -> Self { UChar(value) } } #[doc(hidden)] impl ToGlib for UChar { type GlibType = c_uchar; fn to_glib(&self) -> c_uchar { self.0 } } #[cfg(test)] mod tests { use super::*; use translate::from_glib; #[test] fn converts_single_byte_chars() { assert_eq!(Char::new(0 as char), Some(Char(0 as c_char))); assert_eq!(Char::new(255 as char), Some(Char(-1 as i8 as c_char))); assert_eq!(Char::new('ñ'), Some(Char(241 as u8 as c_char))); assert_eq!(UChar::new(0 as char), Some(UChar(0 as c_uchar))); assert_eq!(UChar::new(255 as char), Some(UChar(255 as c_uchar))); assert_eq!(UChar::new('ñ'), Some(UChar(241 as c_uchar))); } #[test] fn refuses_multibyte_chars() { assert_eq!(Char::new('☔'), None); // no umbrella for you assert_eq!(UChar::new('☔'), None); } #[test] fn into_i8() { assert_eq!(Char::new('A').unwrap().to_glib(), 65 as c_char); } #[test] fn into_u8() { assert_eq!(UChar::new('A').unwrap().to_glib(), 65 as c_uchar); } #[test] fn into_char() { assert_eq!(char::from(Char(65 as c_char)), 'A'); assert_eq!('ñ', UChar(241 as c_uchar).into()); } #[test] fn convert_from_glib() { assert_eq!(Char(65 as c_char), from_glib(65 as c_char)); assert_eq!(UChar(241 as c_uchar), from_glib(241 as u8 as c_uchar)); } } glib-0.8.2/src/checksum.rs010066400017500001750000000037161352206036300136270ustar0000000000000000// Copyright 2013-2016, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use glib_sys; use libc::size_t; use std::vec::Vec; use translate::*; use Checksum; impl Checksum { pub fn get_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); glib_sys::g_checksum_get_digest( mut_override(self.to_glib_none().0), vec.as_mut_ptr(), &mut digest_len, ); vec.set_len(digest_len); vec } } pub fn get_string(self) -> Option { unsafe { from_glib_none(glib_sys::g_checksum_get_string(mut_override( self.to_glib_none().0, ))) } } } #[cfg(test)] mod tests { use {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); cs.update("hello world!".as_bytes()); assert_eq!(cs.get_string().unwrap(), CS_VALUE); } #[test] fn update_multi_call() { let mut cs = Checksum::new(CS_TYPE); cs.update("hello ".as_bytes()); cs.update("world!".as_bytes()); assert_eq!(cs.get_string().unwrap(), CS_VALUE); } #[test] fn get_digest() { let mut cs = Checksum::new(CS_TYPE); cs.update("hello world!".as_bytes()); let vec = cs.get_digest(); assert_eq!(vec, CS_SLICE); } } glib-0.8.2/src/closure.rs010066400017500001750000000136301354212555500135040ustar0000000000000000// Copyright 2013-2017, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or // TODO: support marshaller. use std::mem; use std::ptr; use std::slice; use libc::{c_uint, c_void}; use gobject_sys; use translate::{from_glib_none, mut_override, ToGlibPtr, ToGlibPtrMut, Uninitialized}; use types::Type; use ToValue; use Value; glib_wrapper! { #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct Closure(Shared); match fn { ref => |ptr| { gobject_sys::g_closure_ref(ptr); gobject_sys::g_closure_sink(ptr); }, unref => |ptr| gobject_sys::g_closure_unref(ptr), get_type => || gobject_sys::g_closure_get_type(), } } impl Closure { pub fn new Option + Send + Sync + 'static>(callback: F) -> Self { unsafe { Closure::new_unsafe(callback) } } pub unsafe fn new_unsafe Option>(callback: F) -> Self { unsafe extern "C" fn marshal( _closure: *mut gobject_sys::GClosure, return_value: *mut gobject_sys::GValue, n_param_values: c_uint, param_values: *const gobject_sys::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: Box = Box::from_raw(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(); } } } mem::forget(callback); } unsafe extern "C" fn finalize( notify_data: *mut c_void, _closure: *mut gobject_sys::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_sys::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_sys::g_closure_set_meta_marshal(closure, ptr, Some(marshal::)); gobject_sys::g_closure_add_finalize_notifier(closure, ptr, Some(finalize::)); from_glib_none(closure) } #[allow(clippy::redundant_closure)] pub fn invoke(&self, values: &[&dyn ToValue]) -> Option { let mut result = unsafe { Value::uninitialized() }; let v_args: Vec; let mut s_args: [Value; 10] = unsafe { mem::zeroed() }; let values = if values.len() <= 10 { for (i, arg) in values.iter().enumerate() { s_args[i] = arg.to_value(); } &s_args[0..values.len()] } else { v_args = values.iter().map(|v| v.to_value()).collect(); v_args.as_slice() }; unsafe { gobject_sys::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_sys::GValue, ptr::null_mut(), ); } if result.type_() == Type::Invalid { None } else { Some(result) } } } 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 ToValue; use Value; fn closure_fn(values: &[Value]) -> Option { assert_eq!(values.len(), 2); let string: Option = values[0].get(); assert_eq!(string, Some("test".to_string())); let int: Option = values[1].get(); assert_eq!(int, Some(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: Option = values[0].get(); assert_eq!(string, Some("test".to_string())); let int: Option = values[1].get(); assert_eq!(int, Some(42)); None }); let result = closure.invoke(&[&"test".to_string(), &42]); assert!(result.is_none()); assert_eq!(call_count.load(Ordering::Relaxed), 1); let result = closure.invoke(&[&"test".to_string(), &42]); assert!(result.is_none()); assert_eq!(call_count.load(Ordering::Relaxed), 2); let closure = Closure::new(closure_fn); let result = closure.invoke(&[&"test".to_string(), &42]); let int: Option = result.and_then(|result| result.get()); assert_eq!(int, Some(24)); } } glib-0.8.2/src/date.rs010066400017500001750000000214571352206036300127440ustar0000000000000000// Copyright 2017, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use glib_sys; use gobject_sys; use libc; use std::cmp; use std::fmt; use std::hash; use translate::*; use DateDay; use DateMonth; use DateWeekday; use DateYear; use Time; glib_wrapper! { pub struct Date(Boxed); match fn { copy => |ptr| gobject_sys::g_boxed_copy(glib_sys::g_date_get_type(), ptr as *const _) as *mut _, free => |ptr| glib_sys::g_date_free(ptr), init => |_ptr| (), clear => |ptr| glib_sys::g_date_clear(ptr, 1), get_type => || glib_sys::g_date_get_type(), } } unsafe impl Send for Date {} unsafe impl Sync for Date {} impl Date { pub fn new() -> Date { unsafe { from_glib_full(glib_sys::g_date_new()) } } pub fn new_dmy(day: DateDay, month: DateMonth, year: DateYear) -> Date { unsafe { from_glib_full(glib_sys::g_date_new_dmy(day, month.to_glib(), year)) } } pub fn new_julian(julian_day: u32) -> Date { unsafe { from_glib_full(glib_sys::g_date_new_julian(julian_day)) } } pub fn add_days(&mut self, n_days: u32) { unsafe { glib_sys::g_date_add_days(self.to_glib_none_mut().0, n_days); } } pub fn add_months(&mut self, n_months: u32) { unsafe { glib_sys::g_date_add_months(self.to_glib_none_mut().0, n_months); } } pub fn add_years(&mut self, n_years: u32) { unsafe { glib_sys::g_date_add_years(self.to_glib_none_mut().0, n_years); } } pub fn clamp(&mut self, min_date: &Date, max_date: &Date) { unsafe { glib_sys::g_date_clamp( self.to_glib_none_mut().0, min_date.to_glib_none().0, max_date.to_glib_none().0, ); } } pub fn clear(&mut self, n_dates: u32) { unsafe { glib_sys::g_date_clear(self.to_glib_none_mut().0, n_dates); } } fn compare(&self, rhs: &Date) -> i32 { unsafe { glib_sys::g_date_compare(self.to_glib_none().0, rhs.to_glib_none().0) } } pub fn days_between(&self, date2: &Date) -> i32 { unsafe { glib_sys::g_date_days_between(self.to_glib_none().0, date2.to_glib_none().0) } } pub fn get_day(&self) -> DateDay { unsafe { glib_sys::g_date_get_day(self.to_glib_none().0) } } pub fn get_day_of_year(&self) -> u32 { unsafe { glib_sys::g_date_get_day_of_year(self.to_glib_none().0) } } pub fn get_iso8601_week_of_year(&self) -> u32 { unsafe { glib_sys::g_date_get_iso8601_week_of_year(self.to_glib_none().0) } } pub fn get_julian(&self) -> u32 { unsafe { glib_sys::g_date_get_julian(self.to_glib_none().0) } } pub fn get_monday_week_of_year(&self) -> u32 { unsafe { glib_sys::g_date_get_monday_week_of_year(self.to_glib_none().0) } } pub fn get_month(&self) -> DateMonth { unsafe { from_glib(glib_sys::g_date_get_month(self.to_glib_none().0)) } } pub fn get_sunday_week_of_year(&self) -> u32 { unsafe { glib_sys::g_date_get_sunday_week_of_year(self.to_glib_none().0) } } pub fn get_weekday(&self) -> DateWeekday { unsafe { from_glib(glib_sys::g_date_get_weekday(self.to_glib_none().0)) } } pub fn get_year(&self) -> DateYear { unsafe { glib_sys::g_date_get_year(self.to_glib_none().0) } } pub fn is_first_of_month(&self) -> bool { unsafe { from_glib(glib_sys::g_date_is_first_of_month(self.to_glib_none().0)) } } pub fn is_last_of_month(&self) -> bool { unsafe { from_glib(glib_sys::g_date_is_last_of_month(self.to_glib_none().0)) } } pub fn order(&mut self, date2: &mut Date) { unsafe { glib_sys::g_date_order(self.to_glib_none_mut().0, date2.to_glib_none_mut().0); } } pub fn set_day(&mut self, day: DateDay) { unsafe { glib_sys::g_date_set_day(self.to_glib_none_mut().0, day); } } pub fn set_dmy(&mut self, day: DateDay, month: DateMonth, y: DateYear) { unsafe { glib_sys::g_date_set_dmy(self.to_glib_none_mut().0, day, month.to_glib(), y); } } pub fn set_julian(&mut self, julian_date: u32) { unsafe { glib_sys::g_date_set_julian(self.to_glib_none_mut().0, julian_date); } } pub fn set_month(&mut self, month: DateMonth) { unsafe { glib_sys::g_date_set_month(self.to_glib_none_mut().0, month.to_glib()); } } pub fn set_parse(&mut self, str: &str) { unsafe { glib_sys::g_date_set_parse(self.to_glib_none_mut().0, str.to_glib_none().0); } } pub fn set_time(&mut self, time_: Time) { unsafe { glib_sys::g_date_set_time(self.to_glib_none_mut().0, time_); } } pub fn set_time_t(&mut self, timet: libc::c_long) { unsafe { glib_sys::g_date_set_time_t(self.to_glib_none_mut().0, timet); } } //pub fn set_time_val(&mut self, timeval: /*Ignored*/&mut TimeVal) { // unsafe { TODO: call glib_sys::g_date_set_time_val() } //} pub fn set_year(&mut self, year: DateYear) { unsafe { glib_sys::g_date_set_year(self.to_glib_none_mut().0, year); } } pub fn subtract_days(&mut self, n_days: u32) { unsafe { glib_sys::g_date_subtract_days(self.to_glib_none_mut().0, n_days); } } pub fn subtract_months(&mut self, n_months: u32) { unsafe { glib_sys::g_date_subtract_months(self.to_glib_none_mut().0, n_months); } } pub fn subtract_years(&mut self, n_years: u32) { unsafe { glib_sys::g_date_subtract_years(self.to_glib_none_mut().0, n_years); } } //pub fn to_struct_tm(&self, tm: /*Unimplemented*/Fundamental: Pointer) { // unsafe { TODO: call glib_sys::g_date_to_struct_tm() } //} pub fn valid(&self) -> bool { unsafe { from_glib(glib_sys::g_date_valid(self.to_glib_none().0)) } } pub fn get_days_in_month(month: DateMonth, year: DateYear) -> u8 { unsafe { glib_sys::g_date_get_days_in_month(month.to_glib(), year) } } pub fn get_monday_weeks_in_year(year: DateYear) -> u8 { unsafe { glib_sys::g_date_get_monday_weeks_in_year(year) } } pub fn get_sunday_weeks_in_year(year: DateYear) -> u8 { unsafe { glib_sys::g_date_get_sunday_weeks_in_year(year) } } pub fn is_leap_year(year: DateYear) -> bool { unsafe { from_glib(glib_sys::g_date_is_leap_year(year)) } } pub fn strftime(s: &str, format: &str, date: &Date) -> usize { let slen = s.len() as usize; unsafe { glib_sys::g_date_strftime( s.to_glib_none().0, slen, format.to_glib_none().0, date.to_glib_none().0, ) } } pub fn valid_day(day: DateDay) -> bool { unsafe { from_glib(glib_sys::g_date_valid_day(day)) } } pub fn valid_dmy(day: DateDay, month: DateMonth, year: DateYear) -> bool { unsafe { from_glib(glib_sys::g_date_valid_dmy(day, month.to_glib(), year)) } } pub fn valid_julian(julian_date: u32) -> bool { unsafe { from_glib(glib_sys::g_date_valid_julian(julian_date)) } } pub fn valid_month(month: DateMonth) -> bool { unsafe { from_glib(glib_sys::g_date_valid_month(month.to_glib())) } } pub fn valid_weekday(weekday: DateWeekday) -> bool { unsafe { from_glib(glib_sys::g_date_valid_weekday(weekday.to_glib())) } } pub fn valid_year(year: DateYear) -> bool { unsafe { from_glib(glib_sys::g_date_valid_year(year)) } } } impl Default for Date { fn default() -> Self { Self::new() } } 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.get_year()) .field("month", &self.get_month()) .field("day", &self.get_day()) .finish() } } impl hash::Hash for Date { fn hash(&self, state: &mut H) where H: hash::Hasher, { self.get_year().hash(state); self.get_month().hash(state); self.get_day().hash(state); } } glib-0.8.2/src/enums.rs010066400017500001750000000525731352206036300131610ustar0000000000000000// Copyright 2015-2016, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use glib_sys; use gobject_sys; use std::cmp; use translate::*; use value::Value; use CStr; use Type; #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub enum UserDirectory { Desktop, Documents, Downloads, Music, Pictures, PublicShare, Templates, Videos, #[doc(hidden)] NDirectories, } #[doc(hidden)] impl ToGlib for UserDirectory { type GlibType = glib_sys::GUserDirectory; fn to_glib(&self) -> glib_sys::GUserDirectory { match *self { UserDirectory::Desktop => glib_sys::G_USER_DIRECTORY_DESKTOP, UserDirectory::Documents => glib_sys::G_USER_DIRECTORY_DOCUMENTS, UserDirectory::Downloads => glib_sys::G_USER_DIRECTORY_DOWNLOAD, UserDirectory::Music => glib_sys::G_USER_DIRECTORY_MUSIC, UserDirectory::Pictures => glib_sys::G_USER_DIRECTORY_PICTURES, UserDirectory::PublicShare => glib_sys::G_USER_DIRECTORY_PUBLIC_SHARE, UserDirectory::Templates => glib_sys::G_USER_DIRECTORY_TEMPLATES, UserDirectory::Videos => glib_sys::G_USER_DIRECTORY_VIDEOS, UserDirectory::NDirectories => glib_sys::G_USER_N_DIRECTORIES, } } } /// Representation of an `enum` for dynamically, at runtime, querying the values of the enum and /// using them. #[derive(Debug)] pub struct EnumClass(*mut gobject_sys::GEnumClass); 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_sys::g_type_is_a( type_.to_glib(), gobject_sys::G_TYPE_ENUM, )); if !is_enum { return None; } Some(EnumClass( gobject_sys::g_type_class_ref(type_.to_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`. pub fn get_value(&self, value: i32) -> Option { unsafe { let v = gobject_sys::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`. pub fn get_value_by_name(&self, name: &str) -> Option { unsafe { let v = gobject_sys::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`. pub fn get_value_by_nick(&self, nick: &str) -> Option { unsafe { let v = gobject_sys::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`. pub fn get_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.get_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.get_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.get_value_by_nick(nick).map(|v| v.to_value()) } } impl Drop for EnumClass { fn drop(&mut self) { unsafe { gobject_sys::g_type_class_unref(self.0 as *mut _); } } } impl Clone for EnumClass { fn clone(&self) -> Self { unsafe { EnumClass(gobject_sys::g_type_class_ref(self.type_().to_glib()) as *mut _) } } } /// Representation of a single enum value of an `EnumClass`. #[derive(Debug, Clone)] pub struct EnumValue(*const gobject_sys::GEnumValue, EnumClass); impl EnumValue { /// Get integer value corresponding to the value. pub fn get_value(&self) -> i32 { unsafe { (*self.0).value } } /// Get name corresponding to the value. pub fn get_name(&self) -> &str { unsafe { CStr::from_ptr((*self.0).value_name).to_str().unwrap() } } /// Get nick corresponding to the value. pub fn get_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_sys::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.get_value(gobject_sys::g_value_get_enum(value.to_glib_none().0))) } } /// Get `EnumClass` to which the enum value belongs. pub fn get_class(&self) -> &EnumClass { &self.1 } } impl PartialEq for EnumValue { fn eq(&self, other: &Self) -> bool { self.get_value().eq(&other.get_value()) } } impl Eq for EnumValue {} impl PartialOrd for EnumValue { fn partial_cmp(&self, other: &Self) -> Option { self.get_value().partial_cmp(&other.get_value()) } } impl Ord for EnumValue { fn cmp(&self, other: &Self) -> cmp::Ordering { self.get_value().cmp(&other.get_value()) } } /// Representation of a `flags` for dynamically, at runtime, querying the values of the enum and /// using them #[derive(Debug)] pub struct FlagsClass(*mut gobject_sys::GFlagsClass); 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_sys::g_type_is_a( type_.to_glib(), gobject_sys::G_TYPE_FLAGS, )); if !is_flags { return None; } Some(FlagsClass( gobject_sys::g_type_class_ref(type_.to_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`. pub fn get_value(&self, value: u32) -> Option { unsafe { let v = gobject_sys::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`. pub fn get_value_by_name(&self, name: &str) -> Option { unsafe { let v = gobject_sys::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`. pub fn get_value_by_nick(&self, nick: &str) -> Option { unsafe { let v = gobject_sys::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`. pub fn get_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.get_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.get_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.get_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_sys::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.get_value_by_name(name) { let flags = gobject_sys::g_value_get_flags(value.to_glib_none().0); flags & f.get_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.get_value_by_nick(nick) { let flags = gobject_sys::g_value_get_flags(value.to_glib_none().0); flags & f.get_value() != 0 } else { false } } } /// Sets 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. pub fn set(&self, mut value: Value, f: u32) -> Result { unsafe { if self.type_() != value.type_() { return Err(value); } if let Some(f) = self.get_value(f) { let flags = gobject_sys::g_value_get_flags(value.to_glib_none().0); gobject_sys::g_value_set_flags(value.to_glib_none_mut().0, flags | f.get_value()); Ok(value) } else { Err(value) } } } /// Sets 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.get_value_by_name(name) { let flags = gobject_sys::g_value_get_flags(value.to_glib_none().0); gobject_sys::g_value_set_flags(value.to_glib_none_mut().0, flags | f.get_value()); Ok(value) } else { Err(value) } } } /// Sets 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.get_value_by_nick(nick) { let flags = gobject_sys::g_value_get_flags(value.to_glib_none().0); gobject_sys::g_value_set_flags(value.to_glib_none_mut().0, flags | f.get_value()); Ok(value) } else { Err(value) } } } /// Unsets 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.get_value(f) { let flags = gobject_sys::g_value_get_flags(value.to_glib_none().0); gobject_sys::g_value_set_flags(value.to_glib_none_mut().0, flags & !f.get_value()); Ok(value) } else { Err(value) } } } /// Unsets 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.get_value_by_name(name) { let flags = gobject_sys::g_value_get_flags(value.to_glib_none().0); gobject_sys::g_value_set_flags(value.to_glib_none_mut().0, flags & !f.get_value()); Ok(value) } else { Err(value) } } } /// Unsets 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.get_value_by_nick(nick) { let flags = gobject_sys::g_value_get_flags(value.to_glib_none().0); gobject_sys::g_value_set_flags(value.to_glib_none_mut().0, flags & !f.get_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::new_with_value(self, value)) } } impl Drop for FlagsClass { fn drop(&mut self) { unsafe { gobject_sys::g_type_class_unref(self.0 as *mut _); } } } impl Clone for FlagsClass { fn clone(&self) -> Self { unsafe { FlagsClass(gobject_sys::g_type_class_ref(self.type_().to_glib()) as *mut _) } } } /// Representation of a single flags value of a `FlagsClass`. #[derive(Debug, Clone)] pub struct FlagsValue(*const gobject_sys::GFlagsValue, FlagsClass); impl FlagsValue { /// Get integer value corresponding to the value. pub fn get_value(&self) -> u32 { unsafe { (*self.0).value } } /// Get name corresponding to the value. pub fn get_name(&self) -> &str { unsafe { CStr::from_ptr((*self.0).value_name).to_str().unwrap() } } /// Get nick corresponding to the value. pub fn get_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_sys::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_sys::g_value_get_flags(value.to_glib_none().0); for v in flags_class.get_values() { if v.get_value() & f != 0 { res.push(v); } } } res } } /// Get `FlagsClass` to which the flags value belongs. pub fn get_class(&self) -> &FlagsClass { &self.1 } } impl PartialEq for FlagsValue { fn eq(&self, other: &Self) -> bool { self.get_value().eq(&other.get_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.get_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 new_with_value(flags_class: &FlagsClass, value: Value) -> FlagsBuilder { FlagsBuilder(flags_class, Some(value)) } /// Sets 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 } /// Sets 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 } /// Sets 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 } /// Unsets 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 } /// Unsets 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.8.2/src/error.rs010066400017500001750000000153741352206036300131610ustar0000000000000000// Copyright 2016, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or //! `Error` binding and helper trait. use glib_sys; use std::borrow::Cow; use std::error; use std::ffi::CStr; use std::fmt; use std::str; use translate::*; use Quark; glib_wrapper! { /// A generic error capable of representing various error domains (types). #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Error(Boxed); match fn { copy => |ptr| glib_sys::g_error_copy(ptr), free => |ptr| glib_sys::g_error_free(ptr), get_type => || glib_sys::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. pub fn new(error: T, message: &str) -> Error { unsafe { from_glib_full(glib_sys::g_error_new_literal( T::domain().to_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().to_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 => ... /// ... /// } /// } /// ``` /// /// ```ignore /// match error { /// Some(FileError::Exist) => ... /// Some(FileError::Isdir) => ... /// ... /// } /// ``` pub fn kind(&self) -> Option { if self.0.domain == T::domain().to_glib() { 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()) } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.message()) } } impl error::Error for Error { fn description(&self) -> &str { self.message() } } impl fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Error") .field("domain", &::Quark::from_glib(self.0.domain)) .field("code", &self.0.code) .field("message", &self.message()) .finish() } } /// `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! glib_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! glib_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 { BoolError { message: message.into(), filename, function, line, } } pub fn from_glib>>( b: glib_sys::gboolean, message: Msg, filename: &'static str, function: &'static str, line: u32, ) -> Result<(), Self> { match b { glib_sys::GFALSE => Err(BoolError::new(message, filename, function, line)), _ => Ok(()), } } } impl fmt::Display for BoolError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "Error {:?} in {:?} at {}:{}", self.message, self.function, self.filename, self.line ) } } impl error::Error for BoolError { fn description(&self) -> &str { self.message.as_ref() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_bool_error() { use std::error::Error; let from_static_msg = glib_bool_error!("Static message"); assert_eq!(from_static_msg.description(), "Static message"); let from_dynamic_msg = glib_bool_error!("{} message", "Dynamic"); assert_eq!(from_dynamic_msg.description(), "Dynamic message"); let false_static_res = glib_result_from_gboolean!(glib_sys::GFALSE, "Static message"); assert!(false_static_res.is_err()); let static_err = false_static_res.err().unwrap(); assert_eq!(static_err.description(), "Static message"); let true_static_res = glib_result_from_gboolean!(glib_sys::GTRUE, "Static message"); assert!(true_static_res.is_ok()); let false_dynamic_res = glib_result_from_gboolean!(glib_sys::GFALSE, "{} message", "Dynamic"); assert!(false_dynamic_res.is_err()); let dynamic_err = false_dynamic_res.err().unwrap(); assert_eq!(dynamic_err.description(), "Dynamic message"); let true_dynamic_res = glib_result_from_gboolean!(glib_sys::GTRUE, "{} message", "Dynamic"); assert!(true_dynamic_res.is_ok()); } } glib-0.8.2/src/file_error.rs010066400017500001750000000103751352206036300141540ustar0000000000000000// Copyright 2016, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use error::ErrorDomain; use glib_sys; use translate::from_glib; use 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(glib_sys::g_file_error_quark()) } } fn code(self) -> i32 { use self::FileError::*; match self { Exist => glib_sys::G_FILE_ERROR_EXIST as i32, Isdir => glib_sys::G_FILE_ERROR_ISDIR as i32, Acces => glib_sys::G_FILE_ERROR_ACCES as i32, Nametoolong => glib_sys::G_FILE_ERROR_NAMETOOLONG as i32, Noent => glib_sys::G_FILE_ERROR_NOENT as i32, Notdir => glib_sys::G_FILE_ERROR_NOTDIR as i32, Nxio => glib_sys::G_FILE_ERROR_NXIO as i32, Nodev => glib_sys::G_FILE_ERROR_NODEV as i32, Rofs => glib_sys::G_FILE_ERROR_ROFS as i32, Txtbsy => glib_sys::G_FILE_ERROR_TXTBSY as i32, Fault => glib_sys::G_FILE_ERROR_FAULT as i32, Loop => glib_sys::G_FILE_ERROR_LOOP as i32, Nospc => glib_sys::G_FILE_ERROR_NOSPC as i32, Nomem => glib_sys::G_FILE_ERROR_NOMEM as i32, Mfile => glib_sys::G_FILE_ERROR_MFILE as i32, Nfile => glib_sys::G_FILE_ERROR_NFILE as i32, Badf => glib_sys::G_FILE_ERROR_BADF as i32, Inval => glib_sys::G_FILE_ERROR_INVAL as i32, Pipe => glib_sys::G_FILE_ERROR_PIPE as i32, Again => glib_sys::G_FILE_ERROR_AGAIN as i32, Intr => glib_sys::G_FILE_ERROR_INTR as i32, Io => glib_sys::G_FILE_ERROR_IO as i32, Perm => glib_sys::G_FILE_ERROR_PERM as i32, Nosys => glib_sys::G_FILE_ERROR_NOSYS as i32, Failed => glib_sys::G_FILE_ERROR_FAILED as i32, } } #[allow(clippy::cyclomatic_complexity)] fn from(code: i32) -> Option { use self::FileError::*; match code { x if x == glib_sys::G_FILE_ERROR_EXIST as i32 => Some(Exist), x if x == glib_sys::G_FILE_ERROR_ISDIR as i32 => Some(Isdir), x if x == glib_sys::G_FILE_ERROR_ACCES as i32 => Some(Acces), x if x == glib_sys::G_FILE_ERROR_NAMETOOLONG as i32 => Some(Nametoolong), x if x == glib_sys::G_FILE_ERROR_NOENT as i32 => Some(Noent), x if x == glib_sys::G_FILE_ERROR_NOTDIR as i32 => Some(Notdir), x if x == glib_sys::G_FILE_ERROR_NXIO as i32 => Some(Nxio), x if x == glib_sys::G_FILE_ERROR_NODEV as i32 => Some(Nodev), x if x == glib_sys::G_FILE_ERROR_ROFS as i32 => Some(Rofs), x if x == glib_sys::G_FILE_ERROR_TXTBSY as i32 => Some(Txtbsy), x if x == glib_sys::G_FILE_ERROR_FAULT as i32 => Some(Fault), x if x == glib_sys::G_FILE_ERROR_LOOP as i32 => Some(Loop), x if x == glib_sys::G_FILE_ERROR_NOSPC as i32 => Some(Nospc), x if x == glib_sys::G_FILE_ERROR_NOMEM as i32 => Some(Nomem), x if x == glib_sys::G_FILE_ERROR_MFILE as i32 => Some(Mfile), x if x == glib_sys::G_FILE_ERROR_NFILE as i32 => Some(Nfile), x if x == glib_sys::G_FILE_ERROR_BADF as i32 => Some(Badf), x if x == glib_sys::G_FILE_ERROR_INVAL as i32 => Some(Inval), x if x == glib_sys::G_FILE_ERROR_PIPE as i32 => Some(Pipe), x if x == glib_sys::G_FILE_ERROR_AGAIN as i32 => Some(Again), x if x == glib_sys::G_FILE_ERROR_INTR as i32 => Some(Intr), x if x == glib_sys::G_FILE_ERROR_IO as i32 => Some(Io), x if x == glib_sys::G_FILE_ERROR_PERM as i32 => Some(Perm), x if x == glib_sys::G_FILE_ERROR_NOSYS as i32 => Some(Nosys), x if x == glib_sys::G_FILE_ERROR_FAILED as i32 => Some(Failed), _ => Some(Failed), } } } glib-0.8.2/src/gobject/auto/binding.rs010066400017500001750000000031051352206036300160140ustar0000000000000000// 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 gobject_sys; use std::fmt; use translate::*; use BindingFlags; use GString; use Object; glib_wrapper! { pub struct Binding(Object); match fn { get_type => || gobject_sys::g_binding_get_type(), } } impl Binding { pub fn get_flags(&self) -> BindingFlags { unsafe { from_glib(gobject_sys::g_binding_get_flags(self.to_glib_none().0)) } } pub fn get_source(&self) -> Option { unsafe { from_glib_none(gobject_sys::g_binding_get_source(self.to_glib_none().0)) } } pub fn get_source_property(&self) -> Option { unsafe { from_glib_none(gobject_sys::g_binding_get_source_property( self.to_glib_none().0, )) } } pub fn get_target(&self) -> Option { unsafe { from_glib_none(gobject_sys::g_binding_get_target(self.to_glib_none().0)) } } pub fn get_target_property(&self) -> Option { unsafe { from_glib_none(gobject_sys::g_binding_get_target_property( self.to_glib_none().0, )) } } pub fn unbind(&self) { unsafe { gobject_sys::g_binding_unbind(self.to_glib_full()); } } } unsafe impl Send for Binding {} unsafe impl Sync for Binding {} impl fmt::Display for Binding { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Binding") } } glib-0.8.2/src/gobject/auto/flags.rs010066400017500001750000000057301352206036300155040ustar0000000000000000// 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 gobject_sys; use translate::*; use value::FromValue; use value::FromValueOptional; use value::SetValue; use value::Value; use StaticType; use Type; bitflags! { pub struct BindingFlags: u32 { const DEFAULT = 0; const BIDIRECTIONAL = 1; const SYNC_CREATE = 2; const INVERT_BOOLEAN = 4; } } #[doc(hidden)] impl ToGlib for BindingFlags { type GlibType = gobject_sys::GBindingFlags; fn to_glib(&self) -> gobject_sys::GBindingFlags { self.bits() } } #[doc(hidden)] impl FromGlib for BindingFlags { fn from_glib(value: gobject_sys::GBindingFlags) -> BindingFlags { BindingFlags::from_bits_truncate(value) } } impl StaticType for BindingFlags { fn static_type() -> Type { unsafe { from_glib(gobject_sys::g_binding_flags_get_type()) } } } impl<'a> FromValueOptional<'a> for BindingFlags { unsafe fn from_value_optional(value: &Value) -> Option { Some(FromValue::from_value(value)) } } impl<'a> FromValue<'a> for BindingFlags { unsafe fn from_value(value: &Value) -> Self { from_glib(gobject_sys::g_value_get_flags(value.to_glib_none().0)) } } impl SetValue for BindingFlags { unsafe fn set_value(value: &mut Value, this: &Self) { gobject_sys::g_value_set_flags(value.to_glib_none_mut().0, this.to_glib()) } } bitflags! { pub struct ParamFlags: u32 { const READABLE = 1; const WRITABLE = 2; const READWRITE = 3; const CONSTRUCT = 4; const CONSTRUCT_ONLY = 8; const LAX_VALIDATION = 16; const STATIC_NAME = 32; const PRIVATE = 32; const STATIC_NICK = 64; const STATIC_BLURB = 128; const EXPLICIT_NOTIFY = 1073741824; const DEPRECATED = 2147483648; } } #[doc(hidden)] impl ToGlib for ParamFlags { type GlibType = gobject_sys::GParamFlags; fn to_glib(&self) -> gobject_sys::GParamFlags { self.bits() } } #[doc(hidden)] impl FromGlib for ParamFlags { fn from_glib(value: gobject_sys::GParamFlags) -> ParamFlags { ParamFlags::from_bits_truncate(value) } } bitflags! { pub struct SignalFlags: u32 { const RUN_FIRST = 1; const RUN_LAST = 2; const RUN_CLEANUP = 4; const NO_RECURSE = 8; const DETAILED = 16; const ACTION = 32; const NO_HOOKS = 64; const MUST_COLLECT = 128; const DEPRECATED = 256; } } #[doc(hidden)] impl ToGlib for SignalFlags { type GlibType = gobject_sys::GSignalFlags; fn to_glib(&self) -> gobject_sys::GSignalFlags { self.bits() } } #[doc(hidden)] impl FromGlib for SignalFlags { fn from_glib(value: gobject_sys::GSignalFlags) -> SignalFlags { SignalFlags::from_bits_truncate(value) } } glib-0.8.2/src/gobject/auto/mod.rs010066400017500001750000000005331352206036300151630ustar0000000000000000// 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, BindingClass}; mod flags; pub use self::flags::BindingFlags; pub use self::flags::ParamFlags; pub use self::flags::SignalFlags; #[doc(hidden)] pub mod traits {} glib-0.8.2/src/gobject/mod.rs010066400017500001750000000004761352206036300142210ustar0000000000000000// Copyright 2018, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or //! GObject bindings pub mod auto; pub use self::auto::*; //pub use self::auto::functions::*; glib-0.8.2/src/gstring.rs010066400017500001750000000275361352206036300135100ustar0000000000000000// Copyright 2018, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use libc; 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; use std::ptr; use std::slice; use std::string::String; use translate::*; use types::{StaticType, Type}; use glib_sys; use gobject_sys; use value::{FromValueOptional, SetValue, SetValueOptional, Value}; #[derive(Debug)] pub enum GString { ForeignOwned(Option), Borrowed(*const c_char, usize), Owned(*mut c_char, usize), } impl GString { pub unsafe fn new(ptr: *mut c_char) -> Self { assert!(!ptr.is_null()); GString::Owned(ptr, libc::strlen(ptr)) } pub unsafe fn new_borrowed(ptr: *const c_char) -> Self { assert!(!ptr.is_null()); GString::Borrowed(ptr, libc::strlen(ptr)) } pub fn as_str(&self) -> &str { let cstr = match self { GString::Borrowed(ptr, length) => unsafe { let bytes = slice::from_raw_parts(*ptr as *const u8, length + 1); CStr::from_bytes_with_nul_unchecked(bytes) }, GString::Owned(ptr, length) => unsafe { let bytes = slice::from_raw_parts(*ptr as *const u8, length + 1); CStr::from_bytes_with_nul_unchecked(bytes) }, GString::ForeignOwned(cstring) => cstring .as_ref() .expect("ForeignOwned shouldn't be empty") .as_c_str(), }; cstr.to_str().unwrap() } } impl Drop for GString { fn drop(&mut self) { if let GString::Owned(ptr, _len) = self { unsafe { glib_sys::g_free(*ptr as *mut _); } } } } impl fmt::Display for GString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.as_str()) } } impl hash::Hash for GString { fn hash(&self, state: &mut H) { let bytes = match self { GString::Borrowed(ptr, length) => unsafe { slice::from_raw_parts(*ptr as *const u8, length + 1) }, GString::Owned(ptr, length) => unsafe { slice::from_raw_parts(*ptr as *const u8, length + 1) }, GString::ForeignOwned(cstring) => cstring .as_ref() .expect("ForeignOwned 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::ForeignOwned(ref mut cstring) = s { if let Ok(s) = cstring .take() .expect("ForeignOwned shouldn't be empty") .into_string() { return s; } } String::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 { GString::ForeignOwned(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 { GString::new(ptr as *mut _) } } #[doc(hidden)] impl FromGlibPtrFull<*mut u8> for GString { #[inline] unsafe fn from_glib_full(ptr: *mut u8) -> Self { GString::new(ptr as *mut _) } } #[doc(hidden)] impl FromGlibPtrFull<*mut i8> for GString { #[inline] unsafe fn from_glib_full(ptr: *mut i8) -> Self { GString::new(ptr as *mut _) } } #[doc(hidden)] impl FromGlibPtrNone<*const c_char> for GString { #[inline] unsafe fn from_glib_none(ptr: *const c_char) -> Self { 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 { 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 { 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) -> Self { GString::new_borrowed(ptr) } } #[doc(hidden)] impl FromGlibPtrBorrow<*mut u8> for GString { #[inline] unsafe fn from_glib_borrow(ptr: *mut u8) -> Self { GString::new_borrowed(ptr as *const c_char) } } #[doc(hidden)] impl FromGlibPtrBorrow<*mut i8> for GString { #[inline] unsafe fn from_glib_borrow(ptr: *mut i8) -> Self { GString::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 { glib_sys::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 { glib_sys::g_strndup(self.as_ptr() as *const c_char, self.len() as libc::size_t) as *mut c_char } } } impl GlibPtrDefault for GString { type GlibType = *const c_char; } impl StaticType for GString { fn static_type() -> Type { String::static_type() } } impl StaticType for Vec { fn static_type() -> Type { unsafe { from_glib(glib_sys::g_strv_get_type()) } } } impl<'a> FromValueOptional<'a> for GString { unsafe fn from_value_optional(value: &'a Value) -> Option { let val = value.to_glib_none().0; if val.is_null() { None } else { let ptr = gobject_sys::g_value_dup_string(val); Some(GString::new(ptr)) } } } impl SetValue for GString { unsafe fn set_value(value: &mut Value, this: &Self) { gobject_sys::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full()) } } impl SetValueOptional for GString { unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) { gobject_sys::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full()) } } impl_from_glib_container_as_vec_string!(GString, *const c_char); impl_from_glib_container_as_vec_string!(GString, *mut c_char); #[cfg(test)] mod tests { use glib_sys; use gstring::GString; use std::ffi::CString; #[test] fn test_gstring() { let data = CString::new("foo").unwrap(); let ptr = data.into_raw(); unsafe { let ptr_copy = glib_sys::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.into_raw(); unsafe { let ptr_copy = glib_sys::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 = "foo".as_bytes(); let s: GString = Vec::from(v).into(); assert_eq!(s.as_str(), "foo"); } #[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.8.2/src/key_file.rs010066400017500001750000000111651354212555500136200ustar0000000000000000// Copyright 2015-2016, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use auto::KeyFileFlags; use error::Error; use glib_sys; use gstring::GString; use libc; use std; use std::mem; use std::path; use std::ptr; use translate::*; use KeyFile; impl KeyFile { pub fn save_to_file>(&self, filename: T) -> Result<(), Error> { unsafe { let mut error = ptr::null_mut(); let _ = glib_sys::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)) } } } 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 _ = glib_sys::g_key_file_load_from_data_dirs( self.to_glib_none().0, file.as_ref().to_glib_none().0, &mut full_path, flags.to_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)) } } } 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 _ = glib_sys::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.to_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)) } } } pub fn to_data(&self) -> GString { unsafe { let ret = glib_sys::g_key_file_to_data( self.to_glib_none().0, ptr::null_mut(), ptr::null_mut(), ); from_glib_full(ret) } } pub fn get_boolean(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = glib_sys::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)) } } } pub fn has_key(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = glib_sys::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)) } } } pub fn get_boolean_list(&self, group_name: &str, key: &str) -> Result, Error> { unsafe { let mut length = mem::uninitialized(); let mut error = ptr::null_mut(); let ret = glib_sys::g_key_file_get_boolean_list( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut length, &mut error, ); if !error.is_null() { return Err(from_glib_full(error)); } Ok(FromGlibContainer::from_glib_container_num( ret, length as usize, )) } } } glib-0.8.2/src/lib.rs010066400017500001750000000145711354212555500126030ustar0000000000000000// Copyright 2013-2016, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or //! # **glib**, **gobject** and **gio** bindings for Rust //! //! This library contains //! //! - bindings to some essential GLib, GObject, GIO types and APIs, //! //! - 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. //! //! The library is a work in progress: expect missing functionality and breaking //! changes. //! //! # Dynamic typing //! //! Most types in the GLib family have type identifiers //! ([`Type`](types/enum.Type.html)). Their corresponding Rust types implement //! the [`StaticType`](types/trait.StaticType.html) trait. //! //! Dynamically typed [`Value`](value/index.html) can carry values of any `T: //! StaticType`. //! //! [`Variant`](variant/index.html) can carry values of `T: StaticVariantType`. //! //! # Errors //! //! Errors are represented by [`Error`](error/struct.Error.html), which can //! carry values from various [error //! domains](error/trait.ErrorDomain.html#implementors) (such as //! [`FileError`](enum.FileError.html)). //! //! # Objects //! //! Each class and interface has a corresponding smart pointer struct //! representing an instance of that type (e.g. `Object` for `GObject`, //! `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 iff they point to the same //! object. //! //! The root of the object hierarchy is [`Object`](object/struct.Object.html). //! Inheritance and subtyping is denoted with the [`IsA`](object/trait.IsA.html) //! marker trait. The [`Cast`](object/trait.Cast.html) trait enables upcasting //! and downcasting. //! //! Interfaces and non-leaf classes also have corresponding traits (e.g. //! `ObjectExt` and `gtk::WidgetExt`), which are blanketly implemented for all //! their subtypes. //! //! For creating new subclasses of `Object` or other object types this crate has to be compiled //! with the `subclassing` feature to enable the [`subclass`](subclass/index.html) module. Check //! 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 //! [`glib_wrapper!`](macro.glib_wrapper!.html) macro, which uses abstractions //! defined in the [`wrapper`](wrapper/index.html), [`boxed`](boxed/index.html), //! [`shared`](shared/index.html) and [`object`](object/index.html) modules. //! //! The [`translate`](translate/index.html) module defines and partly implements //! conversions between high level Rust types (including the aforementioned //! wrappers) and their FFI counterparts. #![allow(clippy::doc_markdown)] #![allow(clippy::unreadable_literal)] #[macro_use] extern crate bitflags; #[macro_use] extern crate lazy_static; extern crate libc; #[doc(hidden)] pub extern crate glib_sys; #[doc(hidden)] pub extern crate gobject_sys; #[cfg(feature = "futures")] pub extern crate futures; pub use byte_array::ByteArray; pub use bytes::Bytes; pub use closure::Closure; pub use error::{BoolError, Error}; pub use file_error::FileError; pub use object::{ Cast, InitiallyUnowned, InitiallyUnownedClass, IsA, IsClassFor, Object, ObjectClass, ObjectExt, ObjectType, SendWeakRef, WeakRef, }; pub use signal::{ signal_handler_block, signal_handler_disconnect, signal_handler_unblock, signal_stop_emission_by_name, SignalHandlerId, }; use std::ffi::CStr; pub use string::String; pub use enums::{EnumClass, EnumValue, FlagsBuilder, FlagsClass, FlagsValue, UserDirectory}; pub use time_val::{get_current_time, TimeVal}; pub use types::{StaticType, Type}; pub use value::{SendValue, ToSendValue, ToValue, TypedValue, Value}; pub use variant::{StaticVariantType, ToVariant, Variant}; pub use variant_type::{VariantTy, VariantType}; #[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 auto::functions::*; pub use auto::*; #[allow(clippy::let_and_return)] #[allow(clippy::let_unit_value)] #[allow(clippy::too_many_arguments)] #[allow(non_upper_case_globals)] mod auto; pub use gobject::*; mod gobject; mod byte_array; mod bytes; pub mod char; mod string; pub use char::*; mod checksum; pub mod closure; mod enums; mod file_error; mod key_file; pub mod prelude; pub mod signal; pub mod source; pub use source::*; mod time_val; #[macro_use] pub mod translate; mod gstring; pub use gstring::GString; pub mod types; mod utils; pub use utils::*; mod main_context; mod main_context_channel; pub mod value; pub mod variant; mod variant_type; pub use main_context_channel::{Receiver, Sender, SyncSender}; mod date; pub use date::Date; mod value_array; pub use value_array::ValueArray; mod param_spec; pub use param_spec::ParamSpec; mod quark; pub use quark::Quark; pub mod send_unique; pub use send_unique::{SendUnique, SendUniqueCell}; #[cfg(feature = "futures")] mod main_context_futures; #[cfg(feature = "futures")] mod source_futures; #[cfg(feature = "futures")] pub use source_futures::*; // 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) } } pub(crate) fn get_thread_id() -> usize { thread_local!(static THREAD_ID: usize = next_thread_id()); THREAD_ID.with(|&x| x) } #[macro_use] #[cfg(any(feature = "dox", feature = "subclassing"))] pub mod subclass; glib-0.8.2/src/main_context.rs010066400017500001750000000142261354212555500145220ustar0000000000000000// Copyright 2015-2016, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use glib_sys::{self, gboolean, gpointer}; use source::Priority; use std::mem; use translate::*; use MainContext; use Source; use SourceId; impl MainContext { pub fn prepare(&self) -> (bool, i32) { unsafe { let mut priority = mem::uninitialized(); let res = from_glib(glib_sys::g_main_context_prepare( self.to_glib_none().0, &mut priority, )); (res, priority) } } pub fn find_source_by_id(&self, source_id: &SourceId) -> Option { unsafe { from_glib_none(glib_sys::g_main_context_find_source_by_id( self.to_glib_none().0, source_id.to_glib(), )) } } /// Invokes `func` on the main context. pub fn invoke(&self, func: F) where F: FnOnce() + Send + 'static, { self.invoke_with_priority(::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(::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); } } 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(); glib_sys::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))); glib_sys::g_main_context_invoke_full( self.to_glib_none().0, priority.to_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() } } 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 = ::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::get_thread_default().unwrap(); assert!(is_same_context(&a, &t)); &b.with_thread_default(|| { let t = MainContext::get_thread_default().unwrap(); assert!(is_same_context(&b, &t)); }); let t = MainContext::get_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::get_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::get_thread_default().unwrap(); assert!(is_same_context(&a, &t)); }); } } glib-0.8.2/src/main_context_channel.rs010066400017500001750000000713501352206036300162040ustar0000000000000000// Copyright 2019, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use get_thread_id; use glib_sys; use std::cell::RefCell; use std::collections::VecDeque; use std::fmt; use std::mem; use std::ptr; use std::sync::mpsc; use std::sync::{Arc, Condvar, Mutex}; use translate::{mut_override, FromGlibPtrFull, FromGlibPtrNone, ToGlib, ToGlibPtr}; use Continue; use MainContext; use Priority; use Source; use SourceId; enum ChannelSourceState { NotAttached, Attached(*mut glib_sys::GSource), Destroyed, } unsafe impl Send for ChannelSourceState {} unsafe impl Sync for ChannelSourceState {} struct ChannelInner { queue: VecDeque, source: ChannelSourceState, } impl ChannelInner { fn receiver_disconnected(&self) -> bool { match self.source { ChannelSourceState::Destroyed => true, // Receiver exists but is already destroyed ChannelSourceState::Attached(source) if unsafe { glib_sys::g_source_is_destroyed(source) } != glib_sys::GFALSE => { true } // Not attached yet so the Receiver still exists ChannelSourceState::NotAttached => false, // Receiver still running ChannelSourceState::Attached(_) => false, } } fn set_ready_time(&mut self, ready_time: i64) { if let ChannelSourceState::Attached(source) = self.source { unsafe { glib_sys::g_source_set_ready_time(source, ready_time); } } } fn source(&self) -> Option { match self.source { // Receiver exists and is not destroyed yet ChannelSourceState::Attached(source) if unsafe { glib_sys::g_source_is_destroyed(source) == glib_sys::GFALSE } => { Some(unsafe { Source::from_glib_none(source) }) } _ => None, } } } 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, }), 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 Arc::strong_count(&self.0) == 1 { Err(mpsc::TryRecvError::Disconnected) } else { Err(mpsc::TryRecvError::Empty) } } } #[repr(C)] struct ChannelSource Continue + 'static> { source: glib_sys::GSource, thread_id: usize, source_funcs: Option>, channel: Option>, callback: Option>, } unsafe extern "C" fn prepare( source: *mut glib_sys::GSource, timeout: *mut i32, ) -> glib_sys::gboolean { *timeout = -1; // We're always ready when the ready time was set to 0. There // will be at least one item or the senders are disconnected now if glib_sys::g_source_get_ready_time(source) == 0 { glib_sys::GTRUE } else { glib_sys::GFALSE } } unsafe extern "C" fn check(source: *mut glib_sys::GSource) -> glib_sys::gboolean { // We're always ready when the ready time was set to 0. There // will be at least one item or the senders are disconnected now if glib_sys::g_source_get_ready_time(source) == 0 { glib_sys::GTRUE } else { glib_sys::GFALSE } } unsafe extern "C" fn dispatch Continue + 'static>( source: *mut glib_sys::GSource, callback: glib_sys::GSourceFunc, _user_data: glib_sys::gpointer, ) -> glib_sys::gboolean { let source = &mut *(source as *mut ChannelSource); assert!(callback.is_none()); glib_sys::g_source_set_ready_time(&mut source.source, -1); // Check the thread to ensure we're only ever called from the same thread assert_eq!( get_thread_id(), source.thread_id, "Source dispatched on a different thread than before" ); // 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 glib_sys::G_SOURCE_REMOVE, Ok(item) => { let callback = source .callback .as_mut() .expect("ChannelSource called before Receiver was attached"); if (&mut *callback.borrow_mut())(item) == Continue(false) { return glib_sys::G_SOURCE_REMOVE; } } } } glib_sys::G_SOURCE_CONTINUE } unsafe extern "C" fn finalize Continue + 'static>( source: *mut glib_sys::GSource, ) { let source = &mut *(source as *mut ChannelSource); // Drop all memory we own by taking it out of the Options let channel = source.channel.take().expect("Receiver without 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(); } } let _ = source.callback.take(); let _ = source.source_funcs.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(Option>); 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 { Sender(self.0.clone()) } } impl Sender { /// Sends a value to the channel. pub fn send(&self, t: T) -> Result<(), mpsc::SendError> { self.0.as_ref().expect("Sender with no channel").send(t) } } impl Drop for Sender { fn drop(&mut self) { unsafe { // Wake up the receiver after dropping our own reference to ensure // that after the last sender is dropped the receiver will see a strong // reference count of exactly 1 by itself. let channel = self.0.take().expect("Sender with no channel"); let source = { let inner = (channel.0).0.lock().unwrap(); // Get a strong reference to the source match inner.source() { None => return, Some(source) => source, } }; // Drop the channel and wake up the source/receiver drop(channel); glib_sys::g_source_set_ready_time(source.to_glib_none().0, 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(Option>); 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 { SyncSender(self.0.clone()) } } impl SyncSender { /// Sends a value to the channel and blocks if the channel is full. pub fn send(&self, t: T) -> Result<(), mpsc::SendError> { self.0.as_ref().expect("Sender with no channel").send(t) } /// Sends a value to the channel. pub fn try_send(&self, t: T) -> Result<(), mpsc::TrySendError> { self.0.as_ref().expect("Sender with no channel").try_send(t) } } impl Drop for SyncSender { fn drop(&mut self) { unsafe { // Wake up the receiver after dropping our own reference to ensure // that after the last sender is dropped the receiver will see a strong // reference count of exactly 1 by itself. let channel = self.0.take().expect("Sender with no channel"); let source = { let inner = (channel.0).0.lock().unwrap(); // Get a strong reference to the source match inner.source() { None => return, Some(source) => source, } }; // Drop the channel and wake up the source/receiver drop(channel); glib_sys::g_source_set_ready_time(source.to_glib_none().0, 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(glib_sys::GSourceFuncs { check: Some(check::), prepare: Some(prepare::), dispatch: Some(dispatch::), finalize: Some(finalize::), closure_callback: None, closure_marshal: None, }); let source = glib_sys::g_source_new( mut_override(&*source_funcs), mem::size_of::>() as u32, ) as *mut ChannelSource; assert!(!source.is_null()); // Set up the GSource { let source = &mut *source; let mut inner = (channel.0).0.lock().unwrap(); glib_sys::g_source_set_priority(mut_override(&source.source), self.1.to_glib()); // We're immediately ready if the queue is not empty or if no sender is left at this point glib_sys::g_source_set_ready_time( mut_override(&source.source), if !inner.queue.is_empty() || Arc::strong_count(&channel.0) == 1 { 0 } else { -1 }, ); inner.source = ChannelSourceState::Attached(&mut source.source); } // Store all our data inside our part of the GSource { let source = &mut *source; source.thread_id = get_thread_id(); ptr::write(&mut source.channel, Some(channel)); ptr::write(&mut source.callback, Some(RefCell::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(Some(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(Some(channel)); (sender, receiver) } } #[cfg(test)] mod tests { use super::*; use std::cell::RefCell; use std::rc::Rc; use std::thread; use std::time; use MainLoop; #[test] fn test_channel() { let c = MainContext::new(); let l = MainLoop::new(Some(&c), false); c.acquire(); 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); c.acquire(); 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(); c.acquire(); 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(); c.acquire(); let (sender, receiver) = MainContext::channel::(Priority::default()); struct Helper(Arc>); impl Drop for Helper { fn drop(&mut self) { *self.0.lock().unwrap() = true; } } let dropped = Arc::new(Mutex::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_eq!(*dropped.lock().unwrap(), true); 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); c.acquire(); 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 fills 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 let _ = wait_receiver.recv().unwrap(); 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); c.acquire(); 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 let Err(_) = sender.send(i) { 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 let _ = wait_receiver.recv().unwrap(); 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(); c.acquire(); 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 let _ = wait_receiver.recv().unwrap(); 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); c.acquire(); 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. let _ = wait_receiver.recv().unwrap(); 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. let _ = wait_receiver.recv().unwrap(); *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.8.2/src/main_context_futures.rs010066400017500001750000000323071352206043600162710ustar0000000000000000// Copyright 2018, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use futures; use futures::future::{FutureObj, LocalFutureObj}; use futures::prelude::*; use futures::task::{ Context, LocalSpawn, Poll, RawWaker, RawWakerVTable, Spawn, SpawnError, Waker, }; use get_thread_id; use glib_sys; use std::mem; use std::ptr; use std::sync::atomic::{AtomicUsize, Ordering}; use translate::{from_glib_full, from_glib_none, mut_override, ToGlib}; use MainContext; use MainLoop; use Priority; use Source; // We can't use an enum here because we want to store this in an atomic variable const INIT: usize = 0; const NOT_READY: usize = 1; const READY: usize = 2; const DONE: usize = 3; #[allow(clippy::type_complexity)] #[repr(C)] struct TaskSource { source: glib_sys::GSource, future: Option>, thread: Option, state: AtomicUsize, } static TASK_SOURCE_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new( TaskSource::clone_raw, TaskSource::wake_raw, TaskSource::wake_by_ref_raw, TaskSource::drop_raw, ); impl TaskSource { unsafe fn clone_raw(waker: *const ()) -> RawWaker { let waker = &*(waker as *const TaskSource); glib_sys::g_source_ref(mut_override(&waker.source)); RawWaker::new(waker as *const Self as *const (), &TASK_SOURCE_WAKER_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 TaskSource); if waker .state .compare_and_swap(NOT_READY, READY, Ordering::SeqCst) == NOT_READY { glib_sys::g_source_set_ready_time(mut_override(&waker.source), 0); } } unsafe fn drop_raw(waker: *const ()) { let waker = &*(waker as *const TaskSource); glib_sys::g_source_unref(mut_override(&waker.source)); } fn as_waker(&self) -> Waker { unsafe { Waker::from_raw(Self::clone_raw(self as *const Self as *const ())) } } } unsafe extern "C" fn prepare( source: *mut glib_sys::GSource, timeout: *mut i32, ) -> glib_sys::gboolean { let source = &mut *(source as *mut TaskSource); *timeout = -1; let mut cur = source .state .compare_and_swap(INIT, NOT_READY, Ordering::SeqCst); if cur == INIT { // XXX: This is not actually correct, we should not dispatch the // GSource here already but we need to know its current status so // that if it is not ready yet something can register to the waker if let Poll::Ready(()) = source.poll() { source.state.store(DONE, Ordering::SeqCst); cur = DONE; } else { cur = NOT_READY; } } if cur == READY || cur == DONE { glib_sys::GTRUE } else { glib_sys::GFALSE } } unsafe extern "C" fn check(source: *mut glib_sys::GSource) -> glib_sys::gboolean { let source = &mut *(source as *mut TaskSource); let cur = source.state.load(Ordering::SeqCst); if cur == READY || cur == DONE { glib_sys::GTRUE } else { glib_sys::GFALSE } } unsafe extern "C" fn dispatch( source: *mut glib_sys::GSource, callback: glib_sys::GSourceFunc, _user_data: glib_sys::gpointer, ) -> glib_sys::gboolean { let source = &mut *(source as *mut TaskSource); assert!(callback.is_none()); glib_sys::g_source_set_ready_time(mut_override(&source.source), -1); let mut cur = source .state .compare_and_swap(READY, NOT_READY, Ordering::SeqCst); if cur == READY { if let Poll::Ready(()) = source.poll() { source.state.store(DONE, Ordering::SeqCst); cur = DONE; } else { cur = NOT_READY; } } if cur == DONE { glib_sys::G_SOURCE_REMOVE } else { glib_sys::G_SOURCE_CONTINUE } } unsafe extern "C" fn finalize(source: *mut glib_sys::GSource) { let source = source as *mut TaskSource; let _ = (*source).future.take(); } static SOURCE_FUNCS: glib_sys::GSourceFuncs = glib_sys::GSourceFuncs { check: Some(check), prepare: Some(prepare), dispatch: Some(dispatch), finalize: Some(finalize), closure_callback: None, closure_marshal: None, }; unsafe impl Send for TaskSource {} unsafe impl Sync for TaskSource {} impl TaskSource { #[allow(clippy::new_ret_no_self)] fn new(priority: Priority, thread: Option, future: FutureObj<'static, ()>) -> Source { unsafe { let source = glib_sys::g_source_new( mut_override(&SOURCE_FUNCS), mem::size_of::() as u32, ); { let source = &mut *(source as *mut TaskSource); ptr::write(&mut source.future, Some(future)); source.thread = thread; source.state = AtomicUsize::new(INIT); } glib_sys::g_source_set_priority(source, priority.to_glib()); from_glib_full(source) } } fn poll(&mut self) -> Poll<()> { // Make sure that the first time we're polled that the current thread is remembered // and from there one we ensure that we're always polled from exactly the same thread. // // In theory a GMainContext can be first run from one thread and later from another // thread, but we allow spawning non-Send futures and must not ever use them from // any other thread. match &mut self.thread { thread @ &mut None => { *thread = Some(get_thread_id()); } &mut Some(thread_id) => { assert_eq!( get_thread_id(), thread_id, "Task polled on a different thread than before" ); } } let waker = self.as_waker(); let source = &self.source as *const _; if let Some(ref mut future) = self.future { let executor: MainContext = unsafe { from_glib_none(glib_sys::g_source_get_context(mut_override(source))) }; assert!( executor.is_owner(), "Polling futures only allowed if the thread is owning the MainContext" ); // Clone that we store in the task local data so that // it can be retrieved as needed executor.push_thread_default(); let res = { let enter = futures::executor::enter().unwrap(); let mut context = Context::from_waker(&waker); let res = future.poll_unpin(&mut context); drop(enter); res }; executor.pop_thread_default(); res } else { Poll::Ready(()) } } } 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(::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(::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, None, 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" ); unsafe { let f = LocalFutureObj::new(Box::new(f)); // We ensure here that we only ever run the future on this very task // and that the futures executor is running on this task. Otherwise // we will panic later. // As such we can add the Send impl here safely let f = f.into_future_obj(); let source = TaskSource::new(priority, Some(get_thread_id()), 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(); unsafe { let f = f.then(|r| { res = Some(r); l_clone.quit(); future::ready(()) }); // 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); // And ensure that we are only ever running on this very thread. let f = f.into_future_obj(); let source = TaskSource::new(::PRIORITY_DEFAULT, Some(get_thread_id()), f); source.attach(Some(&*self)); } l.run(); res.unwrap() } } impl Spawn for MainContext { fn spawn_obj(&mut self, f: FutureObj<'static, ()>) -> Result<(), SpawnError> { (&*self).spawn_obj(f) } } /// Implementing `Spawn` for a _reference_ of `MainContext` allows to convert it to a futures-0.1 `Executor`, /// using the futures-0.1 compatibility layer. /// /// See https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.16/src/futures_util/compat/executor.rs.html#85 impl Spawn for &MainContext { fn spawn_obj(&mut self, f: FutureObj<'static, ()>) -> Result<(), SpawnError> { let source = TaskSource::new(::PRIORITY_DEFAULT, None, f); source.attach(Some(&*self)); Ok(()) } } impl LocalSpawn for MainContext { fn spawn_local_obj(&mut self, f: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> { let source = TaskSource::new(::PRIORITY_DEFAULT, Some(get_thread_id()), unsafe { f.into_future_obj() }); source.attach(Some(&*self)); Ok(()) } } #[cfg(test)] mod tests { use super::*; use futures::channel::oneshot; use std::sync::mpsc; use std::thread; #[test] fn test_spawn() { let c = MainContext::new(); let l = ::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(); future::ok(()) }) .then(|res| future::ready(res.unwrap())), ); thread::spawn(move || { l.run(); }); o_sender.send(()).unwrap(); let _ = receiver.recv().unwrap(); } #[test] fn test_spawn_local() { let c = MainContext::new(); let l = ::MainLoop::new(Some(&c), false); c.push_thread_default(); let l_clone = l.clone(); c.spawn_local(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 = 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.8.2/src/object.rs010066400017500001750000001700631354212620200132700ustar0000000000000000// Copyright 2015-2016, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or //! `IMPL` Object wrapper implementation and `Object` binding. use glib_sys; use gobject_sys; use std::fmt; use std::hash; use std::marker::PhantomData; use std::mem; use std::ops; use std::ptr; use translate::*; use types::StaticType; use value::ToValue; use BoolError; use Closure; use SignalHandlerId; use Type; use Value; use get_thread_id; #[doc(hidden)] pub use gobject_sys::GObject; #[doc(hidden)] pub use gobject_sys::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 + 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; /// type of the Rust Class structure. type RustClassType: 'static; fn as_object_ref(&self) -> &ObjectRef; fn as_ptr(&self) -> *mut Self::GlibType; } /// Unsafe variant of the `From` trait. pub trait UnsafeFrom { 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 {} /// Trait for mapping a class struct type to its corresponding instance type. pub unsafe trait IsClassFor: Sized + 'static { /// Corresponding Rust instance type for this class. type Instance: ObjectType; /// Get the type id for this class. fn get_type(&self) -> Type { unsafe { let klass = self as *const _ as *const gobject_sys::GTypeClass; from_glib((*klass).g_type) } } /// Casts this class to a reference to a parent type's class. fn upcast_ref(&self) -> &U where Self::Instance: IsA, U::Instance: ObjectType, { unsafe { let klass = self as *const _ as *const U; &*klass } } /// Casts this class to a mutable reference to a parent type's class. fn upcast_ref_mut(&mut self) -> &mut U where Self::Instance: IsA, U::Instance: ObjectType, { unsafe { let klass = self as *mut _ as *mut U; &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. fn downcast_ref(&self) -> Option<&U> where U::Instance: IsA, Self::Instance: ObjectType, { if !self.get_type().is_a(&U::Instance::static_type()) { return None; } unsafe { let klass = self as *const _ as *const U; 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. fn downcast_ref_mut(&mut self) -> Option<&mut U> where U::Instance: IsA, Self::Instance: ObjectType, { if !self.get_type().is_a(&U::Instance::static_type()) { return None; } unsafe { let klass = self as *mut _ as *mut U; Some(&mut *klass) } } /// Gets the class struct corresponding to `type_`. /// /// This will return `None` if `type_` is not a subclass of `Self`. fn from_type(type_: Type) -> Option> { if !type_.is_a(&Self::Instance::static_type()) { return None; } unsafe { let ptr = gobject_sys::g_type_class_ref(type_.to_glib()); if ptr.is_null() { None } else { Some(ClassRef(ptr::NonNull::new_unchecked(ptr as *mut Self))) } } } } #[derive(Debug)] pub struct ClassRef(ptr::NonNull); impl ops::Deref for ClassRef { type Target = T; fn deref(&self) -> &T { unsafe { self.0.as_ref() } } } impl Drop for ClassRef { fn drop(&mut self) { unsafe { gobject_sys::g_type_class_unref(self.0.as_ptr() as *mut _); } } } /// 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 transmute 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 if compiled with `debug_assertions` and the instance doesn't implement `T`. unsafe fn unsafe_cast(self) -> T { debug_assert!(self.is::()); T::unsafe_from(self.into()) } /// Casts to `&T` unconditionally. /// /// Panics if compiled with `debug_assertions` and the instance doesn't implement `T`. unsafe fn unsafe_cast_ref(&self) -> &T { debug_assert!(self.is::()); // This transmute 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 {} glib_wrapper! { #[doc(hidden)] #[derive(Debug, Ord, PartialOrd, PartialEq, Eq, Hash)] pub struct ObjectRef(Shared); match fn { ref => |ptr| gobject_sys::g_object_ref_sink(ptr), unref => |ptr| gobject_sys::g_object_unref(ptr), } } /// ObjectType implementations for Object types. See `glib_wrapper!`. #[macro_export] macro_rules! glib_object_wrapper { (@generic_impl [$($attr:meta)*] $name:ident, $ffi_name:path, $ffi_class_name:path, $rust_class_name:path, @get_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 differeny results for the same object depending on // the type we currently know for it #[derive(Clone, Hash, Ord)] pub struct $name($crate::object::ObjectRef, ::std::marker::PhantomData<$ffi_name>); #[doc(hidden)] impl Into<$crate::object::ObjectRef> for $name { fn into(self) -> $crate::object::ObjectRef { self.0 } } #[doc(hidden)] impl $crate::object::UnsafeFrom<$crate::object::ObjectRef> for $name { unsafe fn unsafe_from(t: $crate::object::ObjectRef) -> Self { $name(t, ::std::marker::PhantomData) } } #[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; type RustClassType = $rust_class_name; fn as_object_ref(&self) -> &$crate::object::ObjectRef { &self.0 } fn as_ptr(&self) -> *mut Self::GlibType { self.0.to_glib_none().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::glib_sys::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::glib_sys::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 _), ::std::marker::PhantomData) } } #[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 _), ::std::marker::PhantomData) } } #[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 _), ::std::marker::PhantomData) } } #[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) -> Self { debug_assert!($crate::types::instance_of::(ptr as *const _)); $name($crate::translate::from_glib_borrow(ptr as *mut _), ::std::marker::PhantomData) } } #[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) -> Self { $crate::translate::from_glib_borrow(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::glib_sys::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::glib_sys::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 { $crate::translate::ToGlibPtr::to_glib_none(&self.0).0 == $crate::translate::ToGlibPtr::to_glib_none($crate::object::ObjectType::as_object_ref(other)).0 } } impl ::std::cmp::Eq for $name { } impl ::std::cmp::PartialOrd for $name { #[inline] fn partial_cmp(&self, other: &T) -> Option<::std::cmp::Ordering> { $crate::translate::ToGlibPtr::to_glib_none(&self.0).0.partial_cmp(&$crate::translate::ToGlibPtr::to_glib_none($crate::object::ObjectType::as_object_ref(other)).0) } } impl ::std::fmt::Debug for $name { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { f.debug_struct(stringify!($name)) .field("inner", &self.0) .field("type", &<$name as $crate::ObjectExt>::get_type(self)) .finish() } } #[doc(hidden)] impl<'a> $crate::value::FromValueOptional<'a> for $name { unsafe fn from_value_optional(value: &$crate::Value) -> Option { let obj = $crate::gobject_sys::g_value_get_object($crate::translate::ToGlibPtr::to_glib_none(value).0); // If the object was floating, clear the floating flag. The one and only // reference is still owned by the GValue at this point if !obj.is_null() && $crate::gobject_sys::g_object_is_floating(obj) != $crate::glib_sys::GFALSE { $crate::gobject_sys::g_object_ref_sink(obj); } // And get a new reference to the object to pass to the caller Option::<$name>::from_glib_none(obj as *mut $ffi_name).map(|o| $crate::object::Cast::unsafe_cast(o)) } } #[doc(hidden)] impl $crate::value::SetValue for $name { #[allow(clippy::cast_ptr_alignment)] unsafe fn set_value(value: &mut $crate::Value, this: &Self) { $crate::gobject_sys::g_value_set_object($crate::translate::ToGlibPtrMut::to_glib_none_mut(value).0, $crate::translate::ToGlibPtr::<*mut $ffi_name>::to_glib_none(this).0 as *mut $crate::gobject_sys::GObject) } } #[doc(hidden)] impl $crate::value::SetValueOptional for $name { #[allow(clippy::cast_ptr_alignment)] unsafe fn set_value_optional(value: &mut $crate::Value, this: Option<&Self>) { $crate::gobject_sys::g_value_set_object($crate::translate::ToGlibPtrMut::to_glib_none_mut(value).0, $crate::translate::ToGlibPtr::<*mut $ffi_name>::to_glib_none(&this).0 as *mut $crate::gobject_sys::GObject) } } }; (@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)*) => { glib_object_wrapper!(@munch_impls $name, $super_name); glib_object_wrapper!(@munch_impls $name, $($implements)*); }; // If there is no parent class, i.e. only glib::Object (@munch_first_impl $name:ident, $rust_class_name:ident, ) => { glib_object_wrapper!(@munch_impls $name, ); impl ::std::ops::Deref for $rust_class_name { type Target = <$crate::object::Object as $crate::object::ObjectType>::RustClassType; fn deref(&self) -> &Self::Target { $crate::object::IsClassFor::upcast_ref(self) } } impl ::std::ops::DerefMut for $rust_class_name { fn deref_mut(&mut self) -> &mut Self::Target { $crate::object::IsClassFor::upcast_ref_mut(self) } } }; // If there is only one parent class (@munch_first_impl $name:ident, $rust_class_name:ident, $super_name:path) => { glib_object_wrapper!(@munch_impls $name, $super_name); impl ::std::ops::Deref for $rust_class_name { type Target = <$super_name as $crate::object::ObjectType>::RustClassType; fn deref(&self) -> &Self::Target { $crate::object::IsClassFor::upcast_ref(self) } } impl ::std::ops::DerefMut for $rust_class_name { fn deref_mut(&mut self) -> &mut Self::Target { $crate::object::IsClassFor::upcast_ref_mut(self) } } }; // If there is more than one parent class (@munch_first_impl $name:ident, $rust_class_name:ident, $super_name:path, $($implements:tt)*) => { glib_object_wrapper!(@munch_impls $name, $super_name); impl ::std::ops::Deref for $rust_class_name { type Target = <$super_name as $crate::object::ObjectType>::RustClassType; fn deref(&self) -> &Self::Target { $crate::object::IsClassFor::upcast_ref(self) } } impl ::std::ops::DerefMut for $rust_class_name { fn deref_mut(&mut self) -> &mut Self::Target { $crate::object::IsClassFor::upcast_ref_mut(self) } } glib_object_wrapper!(@munch_impls $name, $($implements)*); }; (@class_impl $name:ident, $ffi_class_name:path, $rust_class_name:ident) => { #[repr(C)] pub struct $rust_class_name($ffi_class_name); unsafe impl $crate::object::IsClassFor for $rust_class_name { type Instance = $name; } unsafe impl Send for $rust_class_name { } unsafe impl Sync for $rust_class_name { } }; // 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:path, $ffi_class_name:path, $rust_class_name:ident, @get_type $get_type_expr:expr) => { glib_object_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name, $ffi_class_name, $rust_class_name, @get_type $get_type_expr); glib_object_wrapper!(@class_impl $name, $ffi_class_name, $rust_class_name); }; (@object [$($attr:meta)*] $name:ident, $ffi_name:path, $ffi_class_name:path, $rust_class_name:ident, @get_type $get_type_expr:expr, @extends [$($extends:tt)*], @implements [$($implements:tt)*]) => { glib_object_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name, $ffi_class_name, $rust_class_name, @get_type $get_type_expr); glib_object_wrapper!(@munch_first_impl $name, $rust_class_name, $($extends)*); glib_object_wrapper!(@munch_impls $name, $($implements)*); glib_object_wrapper!(@class_impl $name, $ffi_class_name, $rust_class_name); #[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 { } }; (@interface [$($attr:meta)*] $name:ident, $ffi_name:path, @get_type $get_type_expr:expr, @requires [$($requires:tt)*]) => { glib_object_wrapper!(@generic_impl [$($attr)*] $name, $ffi_name, $crate::wrapper::Void, $crate::wrapper::Void, @get_type $get_type_expr); 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 { } }; } glib_object_wrapper!(@object [doc = "The base class in the object hierarchy."] Object, GObject, GObjectClass, ObjectClass, @get_type gobject_sys::g_object_get_type() ); impl Object { pub fn new(type_: Type, properties: &[(&str, &dyn ToValue)]) -> Result { use std::ffi::CString; if !type_.is_a(&Object::static_type()) { return Err(glib_bool_error!("Can't instantiate non-GObject objects")); } let params = properties .iter() .map(|&(name, value)| (CString::new(name).unwrap(), value.to_value())) .collect::>(); let params_c = params .iter() .map(|&(ref name, ref value)| gobject_sys::GParameter { name: name.as_ptr(), value: unsafe { *value.to_glib_none().0 }, }) .collect::>(); unsafe { let ptr = gobject_sys::g_object_newv( type_.to_glib(), params_c.len() as u32, mut_override(params_c.as_ptr()), ); if ptr.is_null() { Err(glib_bool_error!("Can't instantiate object")) } else if type_.is_a(&InitiallyUnowned::static_type()) { Ok(from_glib_none(ptr)) } else { Ok(from_glib_full(ptr)) } } } } pub trait ObjectExt: ObjectType { /// Returns `true` if the object is an instance of (can be cast to) `T`. fn is(&self) -> bool; fn get_type(&self) -> Type; fn get_object_class(&self) -> &ObjectClass; fn set_property<'a, N: Into<&'a str>>( &self, property_name: N, value: &dyn ToValue, ) -> Result<(), BoolError>; fn get_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, ) -> Result<(), BoolError>; fn get_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<::ParamSpec>; fn list_properties(&self) -> Vec<::ParamSpec>; 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; 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; fn emit<'a, N: Into<&'a str>>( &self, signal_name: N, args: &[&dyn ToValue], ) -> Result, BoolError>; fn disconnect(&self, handler_id: SignalHandlerId); fn connect_notify( &self, name: Option<&str>, f: F, ) -> SignalHandlerId; unsafe fn connect_notify_unsafe( &self, name: Option<&str>, f: F, ) -> SignalHandlerId; fn notify<'a, N: Into<&'a str>>(&self, property_name: N); fn notify_by_pspec(&self, pspec: &::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.get_type().is_a(&U::static_type()) } fn get_type(&self) -> Type { self.get_object_class().get_type() } fn get_object_class(&self) -> &ObjectClass { unsafe { let obj: *mut gobject_sys::GObject = self.as_object_ref().to_glib_none().0; let klass = (*obj).g_type_instance.g_class as *const ObjectClass; &*klass } } fn set_property<'a, N: Into<&'a str>>( &self, property_name: N, value: &dyn ToValue, ) -> Result<(), BoolError> { let property_name = property_name.into(); let mut property_value = value.to_value(); let pspec = match self.find_property(property_name) { Some(pspec) => pspec, None => { return Err(glib_bool_error!("property not found")); } }; if !pspec.get_flags().contains(::ParamFlags::WRITABLE) || pspec.get_flags().contains(::ParamFlags::CONSTRUCT_ONLY) { return Err(glib_bool_error!("property is not writable")); } 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_sys::g_type_check_value_holds( mut_override(property_value.to_glib_none().0), pspec.get_value_type().to_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 type 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()) { if let Some(obj) = property_value.get::() { if obj.get_type().is_a(&pspec.get_value_type()) { property_value.0.g_type = pspec.get_value_type().to_glib(); } else { return Err(glib_bool_error!( "property can't be set from the given object type" )); } } else { // Otherwise if the value is None then the type is compatible too property_value.0.g_type = pspec.get_value_type().to_glib(); } } else if !valid_type { return Err(glib_bool_error!( "property can't be set from the given type" )); } let changed: bool = from_glib(gobject_sys::g_param_value_validate( pspec.to_glib_none().0, property_value.to_glib_none_mut().0, )); let change_allowed = pspec.get_flags().contains(::ParamFlags::LAX_VALIDATION); if changed && !change_allowed { return Err(glib_bool_error!( "property can't be set from given value, it is invalid or out of range" )); } gobject_sys::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 get_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(glib_bool_error!("property not found")); } }; if !pspec.get_flags().contains(::ParamFlags::READABLE) { return Err(glib_bool_error!("property is not readable")); } unsafe { let mut value = Value::from_type(pspec.get_value_type()); gobject_sys::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 if value.type_() == ::Type::Invalid { Err(glib_bool_error!("Failed to get property value")) } else { Ok(value) } } } fn block_signal(&self, handler_id: &SignalHandlerId) { unsafe { gobject_sys::g_signal_handler_block( self.as_object_ref().to_glib_none().0, handler_id.to_glib(), ); } } fn unblock_signal(&self, handler_id: &SignalHandlerId) { unsafe { gobject_sys::g_signal_handler_unblock( self.as_object_ref().to_glib_none().0, handler_id.to_glib(), ); } } fn stop_signal_emission(&self, signal_name: &str) { unsafe { gobject_sys::g_signal_stop_emission_by_name( self.as_object_ref().to_glib_none().0, signal_name.to_glib_none().0, ); } } fn disconnect(&self, handler_id: SignalHandlerId) { unsafe { gobject_sys::g_signal_handler_disconnect( self.as_object_ref().to_glib_none().0, handler_id.to_glib(), ); } } fn connect_notify( &self, name: Option<&str>, f: F, ) -> SignalHandlerId { unsafe { self.connect_notify_unsafe(name, f) } } unsafe fn connect_notify_unsafe( &self, name: Option<&str>, f: F, ) -> SignalHandlerId { unsafe extern "C" fn notify_trampoline( this: *mut gobject_sys::GObject, param_spec: *mut gobject_sys::GParamSpec, f: glib_sys::gpointer, ) where P: ObjectType, { let f: &F = &*(f as *const F); f( &Object::from_glib_borrow(this).unsafe_cast(), &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); ::signal::connect_raw( self.as_object_ref().to_glib_none().0, signal_name.as_ptr() as *const _, Some(mem::transmute(notify_trampoline:: as usize)), Box::into_raw(f), ) } fn notify<'a, N: Into<&'a str>>(&self, property_name: N) { let property_name = property_name.into(); unsafe { gobject_sys::g_object_notify( self.as_object_ref().to_glib_none().0, property_name.to_glib_none().0, ); } } fn notify_by_pspec(&self, pspec: &::ParamSpec) { unsafe { gobject_sys::g_object_notify_by_pspec( self.as_object_ref().to_glib_none().0, pspec.to_glib_none().0, ); } } fn has_property<'a, N: Into<&'a str>>( &self, property_name: N, type_: Option, ) -> Result<(), BoolError> { self.get_object_class().has_property(property_name, type_) } fn get_property_type<'a, N: Into<&'a str>>(&self, property_name: N) -> Option { self.get_object_class().get_property_type(property_name) } fn find_property<'a, N: Into<&'a str>>(&self, property_name: N) -> Option<::ParamSpec> { self.get_object_class().find_property(property_name) } fn list_properties(&self) -> Vec<::ParamSpec> { self.get_object_class().list_properties() } 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) } } 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.get_type(); let mut signal_id = 0; let mut signal_detail = 0; let found: bool = from_glib(gobject_sys::g_signal_parse_name( signal_name.to_glib_none().0, type_.to_glib(), &mut signal_id, &mut signal_detail, true.to_glib(), )); if !found { return Err(glib_bool_error!("Signal not found")); } let mut details = mem::zeroed(); gobject_sys::g_signal_query(signal_id, &mut details); if details.signal_id != signal_id { return Err(glib_bool_error!("Signal not found")); } // This is actually G_SIGNAL_TYPE_STATIC_SCOPE let return_type: Type = from_glib(details.return_type & (!gobject_sys::G_TYPE_FLAG_RESERVED_ID_BIT)); let closure = Closure::new_unsafe(move |values| { let ret = callback(values); if return_type == Type::Unit { if let Some(ret) = ret { panic!( "Signal required no return value but got value of type {}", ret.type_().name() ); } None } else { match ret { Some(mut ret) => { let valid_type: bool = from_glib(gobject_sys::g_type_check_value_holds( mut_override(ret.to_glib_none().0), return_type.to_glib(), )); // 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 if !valid_type && ret.type_().is_a(&Object::static_type()) { if let Some(obj) = ret.get::() { if obj.get_type().is_a(&return_type) { ret.0.g_type = return_type.to_glib(); } else { panic!("Signal required return value of type {} but got {} (actual {})", return_type.name(), ret.type_().name(), obj.get_type().name()); } } else { // Otherwise if the value is None then the type is compatible too ret.0.g_type = return_type.to_glib(); } } else if !valid_type { panic!( "Signal required return value of type {} but got {}", return_type.name(), ret.type_().name() ); } Some(ret) } None => { panic!( "Signal required return value of type {} but got None", return_type.name() ); } } } }); let handler = gobject_sys::g_signal_connect_closure_by_id( self.as_object_ref().to_glib_none().0, signal_id, signal_detail, closure.to_glib_none().0, after.to_glib(), ); if handler == 0 { Err(glib_bool_error!("Failed to connect to signal")) } else { Ok(from_glib(handler)) } } fn emit<'a, N: Into<&'a str>>( &self, signal_name: N, args: &[&dyn ToValue], ) -> Result, BoolError> { let signal_name: &str = signal_name.into(); unsafe { let type_ = self.get_type(); let mut signal_id = 0; let mut signal_detail = 0; let found: bool = from_glib(gobject_sys::g_signal_parse_name( signal_name.to_glib_none().0, type_.to_glib(), &mut signal_id, &mut signal_detail, true.to_glib(), )); if !found { return Err(glib_bool_error!("Signal not found")); } let mut details = mem::zeroed(); gobject_sys::g_signal_query(signal_id, &mut details); if details.signal_id != signal_id { return Err(glib_bool_error!("Signal not found")); } if details.n_params != args.len() as u32 { return Err(glib_bool_error!("Incompatible number of arguments")); } for (i, item) in args.iter().enumerate() { let arg_type = *(details.param_types.add(i)) & (!gobject_sys::G_TYPE_FLAG_RESERVED_ID_BIT); if arg_type != item.to_value_type().to_glib() { return Err(glib_bool_error!("Incompatible argument types")); } } let mut v_args: Vec; let mut s_args: [Value; 10] = mem::zeroed(); let self_v = { let mut v = Value::uninitialized(); gobject_sys::g_value_init(v.to_glib_none_mut().0, self.get_type().to_glib()); gobject_sys::g_value_set_object( v.to_glib_none_mut().0, self.as_object_ref().to_glib_none().0, ); v }; let args = if args.len() < 10 { s_args[0] = self_v; for (i, arg) in args.iter().enumerate() { s_args[i + 1] = arg.to_value(); } &s_args[0..=args.len()] } else { v_args = Vec::with_capacity(args.len() + 1); v_args.push(self_v); for arg in args { v_args.push(arg.to_value()); } v_args.as_slice() }; let mut return_value = Value::uninitialized(); if details.return_type != gobject_sys::G_TYPE_NONE { gobject_sys::g_value_init(return_value.to_glib_none_mut().0, details.return_type); } gobject_sys::g_signal_emitv( mut_override(args.as_ptr()) as *mut gobject_sys::GValue, signal_id, signal_detail, return_value.to_glib_none_mut().0, ); if return_value.type_() != Type::Unit && return_value.type_() != Type::Invalid { Ok(Some(return_value)) } else { Ok(None) } } } fn downgrade(&self) -> WeakRef { unsafe { let w = WeakRef(Box::new(mem::uninitialized()), PhantomData); gobject_sys::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_sys::GObject = stash.0; unsafe { glib_sys::g_atomic_int_get(&(*ptr).ref_count as *const u32 as *const i32) as u32 } } } impl ObjectClass { pub fn has_property<'a, N: Into<&'a str>>( &self, property_name: N, type_: Option, ) -> Result<(), BoolError> { let property_name = property_name.into(); let ptype = self.get_property_type(property_name); match (ptype, type_) { (None, _) => Err(glib_bool_error!("Invalid property name")), (Some(_), None) => Ok(()), (Some(ptype), Some(type_)) => { if ptype == type_ { Ok(()) } else { Err(glib_bool_error!("Invalid property type")) } } } } pub fn get_property_type<'a, N: Into<&'a str>>(&self, property_name: N) -> Option { self.find_property(property_name) .map(|pspec| pspec.get_value_type()) } pub fn find_property<'a, N: Into<&'a str>>(&self, property_name: N) -> Option<::ParamSpec> { let property_name = property_name.into(); unsafe { let klass = self as *const _ as *const gobject_sys::GObjectClass; from_glib_none(gobject_sys::g_object_class_find_property( klass as *mut _, property_name.to_glib_none().0, )) } } pub fn list_properties(&self) -> Vec<::ParamSpec> { unsafe { let klass = self as *const _ as *const gobject_sys::GObjectClass; let mut n_properties = 0; let props = gobject_sys::g_object_class_list_properties(klass as *mut _, &mut n_properties); FromGlibContainer::from_glib_none_num(props, n_properties as usize) } } } glib_wrapper! { pub struct InitiallyUnowned(Object); match fn { get_type => || gobject_sys::g_initially_unowned_get_type(), } } pub struct WeakRef(Box, PhantomData<*const T>); impl WeakRef { pub fn new() -> WeakRef { unsafe { let w = WeakRef(Box::new(mem::uninitialized()), PhantomData); gobject_sys::g_weak_ref_init(mut_override(&*w.0), ptr::null_mut()); w } } pub fn upgrade(&self) -> Option { unsafe { let ptr = gobject_sys::g_weak_ref_get(mut_override(&*self.0)); 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_sys::g_weak_ref_clear(mut_override(&*self.0)); } } } impl Clone for WeakRef { fn clone(&self) -> Self { unsafe { let c = WeakRef(Box::new(mem::uninitialized()), PhantomData); let o = gobject_sys::g_weak_ref_get(mut_override(&*self.0)); gobject_sys::g_weak_ref_init(mut_override(&*c.0), o); if !o.is_null() { gobject_sys::g_object_unref(o); } 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. 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(get_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(get_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 { SendWeakRef(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(get_thread_id())) } } unsafe impl Sync for SendWeakRef {} unsafe impl Send for SendWeakRef {} pub struct BindingBuilder<'a> { source: &'a ObjectRef, source_property: &'a str, target: &'a ObjectRef, target_property: &'a str, flags: ::BindingFlags, transform_to: Option<::Closure>, transform_from: Option<::Closure>, } 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: ::BindingFlags::DEFAULT, transform_to: None, transform_from: None, } } fn transform_closure Option + Send + Sync + 'static>( func: F, ) -> ::Closure { ::Closure::new(move |values| { assert_eq!(values.len(), 3); let binding = values[0].get::<::Binding>().unwrap(); let from = unsafe { let ptr = gobject_sys::g_value_get_boxed(mut_override( &values[1] as *const Value as *const gobject_sys::GValue, )); assert!(!ptr.is_null()); &*(ptr as *const gobject_sys::GValue as *const Value) }; match func(&binding, &from) { None => Some(false.to_value()), Some(value) => { unsafe { gobject_sys::g_value_set_boxed( mut_override(&values[2] as *const Value as *const gobject_sys::GValue), &value as *const Value as *const _, ); } Some(true.to_value()) } } }) } pub fn transform_from 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: ::BindingFlags) -> Self { Self { flags, ..self } } pub fn build(self) -> Option<::Binding> { unsafe { from_glib_none(gobject_sys::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.to_glib(), self.transform_to.to_glib_none().0, self.transform_from.to_glib_none().0, )) } } } glib-0.8.2/src/param_spec.rs010066400017500001750000000342521352206036300141360ustar0000000000000000// Copyright 2018, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or // // TODO: Implement custom subtyping here for things like GParamSpecInt to get // default/min/max values and similar use gobject_sys; use libc; use translate::*; use ParamFlags; use Value; glib_wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ParamSpec(Shared); match fn { ref => |ptr| gobject_sys::g_param_spec_ref_sink(ptr), unref => |ptr| gobject_sys::g_param_spec_unref(ptr), get_type => || gobject_sys::G_TYPE_PARAM, } } unsafe impl Send for ParamSpec {} unsafe impl Sync for ParamSpec {} impl ParamSpec { pub fn get_value_type(&self) -> ::Type { unsafe { from_glib((*self.to_glib_none().0).value_type) } } pub fn get_owner_type(&self) -> ::Type { unsafe { from_glib((*self.to_glib_none().0).owner_type) } } pub fn get_flags(&self) -> ParamFlags { unsafe { from_glib((*self.to_glib_none().0).flags) } } pub fn get_blurb(&self) -> String { unsafe { from_glib_none(gobject_sys::g_param_spec_get_blurb(self.to_glib_none().0)) } } pub fn get_default_value(&self) -> Option { unsafe { from_glib_none(gobject_sys::g_param_spec_get_default_value( self.to_glib_none().0, )) } } pub fn get_name(&self) -> String { unsafe { from_glib_none(gobject_sys::g_param_spec_get_name(self.to_glib_none().0)) } } #[cfg(any(feature = "v2_46", feature = "dox"))] pub fn get_name_quark(&self) -> ::Quark { unsafe { from_glib(gobject_sys::g_param_spec_get_name_quark( self.to_glib_none().0, )) } } pub fn get_nick(&self) -> String { unsafe { from_glib_none(gobject_sys::g_param_spec_get_nick(self.to_glib_none().0)) } } //pub fn get_qdata(&self, quark: /*Ignored*/glib::Quark) -> /*Unimplemented*/Option { // unsafe { TODO: call gobject_sys::g_param_spec_get_qdata() } //} pub fn get_redirect_target(&self) -> Option { unsafe { from_glib_none(gobject_sys::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_sys::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_sys::g_param_spec_set_qdata_full() } //} //pub fn steal_qdata(&self, quark: /*Ignored*/glib::Quark) -> /*Unimplemented*/Option { // unsafe { TODO: call gobject_sys::g_param_spec_steal_qdata() } //} pub fn boolean( name: &str, nick: &str, blurb: &str, default_value: bool, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_boolean( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, default_value.to_glib(), flags.to_glib(), )) } } pub fn boxed( name: &str, nick: &str, blurb: &str, boxed_type: ::Type, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_boxed( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, boxed_type.to_glib(), flags.to_glib(), )) } } pub fn char( name: &str, nick: &str, blurb: &str, minimum: i8, maximum: i8, default_value: i8, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_char( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib(), )) } } pub fn double( name: &str, nick: &str, blurb: &str, minimum: f64, maximum: f64, default_value: f64, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_double( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib(), )) } } pub fn enum_( name: &str, nick: &str, blurb: &str, enum_type: ::Type, default_value: i32, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_enum( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, enum_type.to_glib(), default_value, flags.to_glib(), )) } } pub fn flags( name: &str, nick: &str, blurb: &str, flags_type: ::Type, default_value: u32, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_flags( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, flags_type.to_glib(), default_value, flags.to_glib(), )) } } pub fn float( name: &str, nick: &str, blurb: &str, minimum: f32, maximum: f32, default_value: f32, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_float( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib(), )) } } pub fn gtype( name: &str, nick: &str, blurb: &str, is_a_type: ::Type, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_gtype( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, is_a_type.to_glib(), flags.to_glib(), )) } } pub fn int( name: &str, nick: &str, blurb: &str, minimum: i32, maximum: i32, default_value: i32, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_int( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib(), )) } } pub fn int64( name: &str, nick: &str, blurb: &str, minimum: i64, maximum: i64, default_value: i64, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_int64( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib(), )) } } pub fn long( name: &str, nick: &str, blurb: &str, minimum: libc::c_long, maximum: libc::c_long, default_value: libc::c_long, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_long( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib(), )) } } pub fn object( name: &str, nick: &str, blurb: &str, object_type: ::Type, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_object( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, object_type.to_glib(), flags.to_glib(), )) } } pub fn override_(name: &str, overridden: &ParamSpec) -> ParamSpec { unsafe { from_glib_none(gobject_sys::g_param_spec_override( name.to_glib_none().0, overridden.to_glib_none().0, )) } } pub fn param( name: &str, nick: &str, blurb: &str, param_type: ::Type, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_param( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, param_type.to_glib(), flags.to_glib(), )) } } pub fn pointer(name: &str, nick: &str, blurb: &str, flags: ParamFlags) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_pointer( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, flags.to_glib(), )) } } pub fn string( name: &str, nick: &str, blurb: &str, default_value: Option<&str>, flags: ParamFlags, ) -> ParamSpec { let default_value = default_value.to_glib_none(); unsafe { from_glib_full(gobject_sys::g_param_spec_string( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, default_value.0, flags.to_glib(), )) } } pub fn uchar( name: &str, nick: &str, blurb: &str, minimum: u8, maximum: u8, default_value: u8, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_uchar( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib(), )) } } pub fn uint( name: &str, nick: &str, blurb: &str, minimum: u32, maximum: u32, default_value: u32, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_uint( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib(), )) } } pub fn uint64( name: &str, nick: &str, blurb: &str, minimum: u64, maximum: u64, default_value: u64, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_uint64( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib(), )) } } pub fn ulong( name: &str, nick: &str, blurb: &str, minimum: libc::c_ulong, maximum: libc::c_ulong, default_value: libc::c_ulong, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_ulong( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, minimum, maximum, default_value, flags.to_glib(), )) } } pub fn unichar( name: &str, nick: &str, blurb: &str, default_value: char, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_full(gobject_sys::g_param_spec_unichar( name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, default_value.to_glib(), flags.to_glib(), )) } } pub fn value_array( name: &str, nick: &str, blurb: &str, element_spec: &ParamSpec, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_none(gobject_sys::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.to_glib(), )) } } pub fn variant( name: &str, nick: &str, blurb: &str, type_: &::VariantTy, default_value: Option<&::Variant>, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_none(gobject_sys::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.to_glib(), )) } } } glib-0.8.2/src/prelude.rs010066400017500001750000000003131352206036300134530ustar0000000000000000//! Traits and essential types intended for blanket imports. pub use { Cast, Continue, IsA, IsClassFor, ObjectExt, ObjectType, StaticType, StaticVariantType, ToSendValue, ToValue, ToVariant, }; glib-0.8.2/src/quark.rs010066400017500001750000000027011352206036300131410ustar0000000000000000// Copyright 2018, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use glib_sys; use std::ffi::CStr; use std::fmt; use translate::*; #[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[repr(C)] pub struct Quark(glib_sys::GQuark); impl Quark { pub fn from_string(s: &str) -> Quark { unsafe { from_glib(glib_sys::g_quark_from_static_string(s.to_glib_full())) } } #[allow(clippy::trivially_copy_pass_by_ref)] pub fn to_string(&self) -> &'static str { unsafe { CStr::from_ptr(glib_sys::g_quark_to_string(self.to_glib())) .to_str() .unwrap() } } pub fn try_string(s: &str) -> Option { unsafe { match glib_sys::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 { fn from_glib(value: glib_sys::GQuark) -> Self { Quark(value) } } #[doc(hidden)] impl ToGlib for Quark { type GlibType = glib_sys::GQuark; fn to_glib(&self) -> glib_sys::GQuark { self.0 } } glib-0.8.2/src/send_unique.rs010066400017500001750000000106431352206036300143410ustar0000000000000000// Copyright 2018, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or 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((::get_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 != ::get_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 extracing 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.8.2/src/shared.rs010066400017500001750000000354611352206036300132750ustar0000000000000000// Copyright 2015-2016, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or //! `IMPL` Shared (reference counted) wrapper implementation. use std::cmp; use std::fmt; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::ptr; use translate::*; /// Wrapper implementations for shared types. See `glib_wrapper!`. #[macro_export] macro_rules! glib_shared_wrapper { ([$($attr:meta)*] $name:ident, $ffi_name:path, @ref $ref_arg:ident $ref_expr:expr, @unref $unref_arg:ident $unref_expr:expr, @get_type $get_type_expr:expr) => { 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<'a> $crate::value::FromValueOptional<'a> for $name { unsafe fn from_value_optional(value: &$crate::Value) -> Option { $crate::translate::from_glib_full($crate::gobject_sys::g_value_dup_boxed($crate::translate::ToGlibPtr::to_glib_none(value).0) as *mut $ffi_name) } } #[doc(hidden)] impl $crate::value::SetValue for $name { unsafe fn set_value(value: &mut $crate::Value, this: &Self) { $crate::gobject_sys::g_value_set_boxed($crate::translate::ToGlibPtrMut::to_glib_none_mut(value).0, $crate::translate::ToGlibPtr::<*mut $ffi_name>::to_glib_none(this).0 as $crate::glib_sys::gpointer) } } #[doc(hidden)] impl $crate::value::SetValueOptional for $name { unsafe fn set_value_optional(value: &mut $crate::Value, this: Option<&Self>) { $crate::gobject_sys::g_value_set_boxed($crate::translate::ToGlibPtrMut::to_glib_none_mut(value).0, $crate::translate::ToGlibPtr::<*mut $ffi_name>::to_glib_none(&this).0 as $crate::glib_sys::gpointer) } } }; ([$($attr:meta)*] $name:ident, $ffi_name:path, @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, MemoryManager>); #[doc(hidden)] pub struct MemoryManager; impl $crate::shared::SharedMemoryManager<$ffi_name> for MemoryManager { #[inline] unsafe fn ref_($ref_arg: *mut $ffi_name) { $ref_expr; } #[inline] 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, MemoryManager>; #[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::glib_sys::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::glib_sys::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) -> Self { $name($crate::translate::from_glib_borrow(ptr)) } } #[doc(hidden)] impl $crate::translate::FromGlibPtrBorrow<*const $ffi_name> for $name { #[inline] unsafe fn from_glib_borrow(ptr: *const $ffi_name) -> Self { $crate::translate::from_glib_borrow(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::glib_sys::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::glib_sys::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 { unsafe fn ref_(ptr: *mut T); unsafe fn unref(ptr: *mut T); } /// Encapsulates memory management logic for shared types. pub struct Shared> { inner: ptr::NonNull, borrowed: bool, mm: PhantomData<*const MM>, } impl> Drop for Shared { fn drop(&mut self) { if !self.borrowed { unsafe { MM::unref(self.inner.as_ptr()); } } } } impl> Clone for Shared { fn clone(&self) -> Self { unsafe { MM::ref_(self.inner.as_ptr()); } Shared { inner: self.inner, borrowed: false, mm: PhantomData, } } } impl> fmt::Debug for Shared { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Shared") .field("inner", &self.inner) .field("borrowed", &self.borrowed) .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); Shared { inner: ptr::NonNull::new_unchecked(ptr), borrowed: false, 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 _); Shared { inner: ptr::NonNull::new_unchecked(ptr as *mut _), borrowed: false, mm: PhantomData, } } } impl> FromGlibPtrFull<*mut T> for Shared { #[inline] unsafe fn from_glib_full(ptr: *mut T) -> Self { assert!(!ptr.is_null()); Shared { inner: ptr::NonNull::new_unchecked(ptr), borrowed: false, mm: PhantomData, } } } impl> FromGlibPtrBorrow<*mut T> for Shared { #[inline] unsafe fn from_glib_borrow(ptr: *mut T) -> Self { assert!(!ptr.is_null()); Shared { inner: ptr::NonNull::new_unchecked(ptr), borrowed: true, mm: PhantomData, } } } glib-0.8.2/src/signal.rs010066400017500001750000000057651352206043600133110ustar0000000000000000// Copyright 2015, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or //! `IMPL` Low level signal support. use glib_sys::{gboolean, gpointer}; use gobject_sys::{self, GCallback}; use libc::{c_char, c_ulong, c_void}; use object::ObjectType; use std::mem; use translate::{from_glib, FromGlib, ToGlib, ToGlibPtr}; /// The id of a signal that is returned by `connect`. #[derive(Debug, Eq, PartialEq)] pub struct SignalHandlerId(c_ulong); impl ToGlib for SignalHandlerId { type GlibType = c_ulong; #[inline] fn to_glib(&self) -> c_ulong { self.0 } } impl FromGlib for SignalHandlerId { #[inline] fn from_glib(val: c_ulong) -> SignalHandlerId { assert_ne!(val, 0); SignalHandlerId(val) } } /// 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 ToGlib for Inhibit { type GlibType = gboolean; #[inline] fn to_glib(&self) -> gboolean { self.0.to_glib() } } pub unsafe fn connect_raw( receiver: *mut gobject_sys::GObject, signal_name: *const c_char, trampoline: GCallback, closure: *mut F, ) -> SignalHandlerId { unsafe extern "C" fn destroy_closure(ptr: *mut c_void, _: *mut gobject_sys::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_sys::g_signal_connect_data( receiver, signal_name, trampoline, closure as *mut _, Some(destroy_closure::), 0, ); assert!(handle > 0); from_glib(handle) } pub fn signal_handler_block(instance: &T, handler_id: &SignalHandlerId) { unsafe { gobject_sys::g_signal_handler_block( instance.as_object_ref().to_glib_none().0, handler_id.to_glib(), ); } } pub fn signal_handler_unblock(instance: &T, handler_id: &SignalHandlerId) { unsafe { gobject_sys::g_signal_handler_unblock( instance.as_object_ref().to_glib_none().0, handler_id.to_glib(), ); } } #[allow(clippy::needless_pass_by_value)] pub fn signal_handler_disconnect(instance: &T, handler_id: SignalHandlerId) { unsafe { gobject_sys::g_signal_handler_disconnect( instance.as_object_ref().to_glib_none().0, handler_id.to_glib(), ); } } pub fn signal_stop_emission_by_name(instance: &T, signal_name: &str) { unsafe { gobject_sys::g_signal_stop_emission_by_name( instance.as_object_ref().to_glib_none().0, signal_name.to_glib_none().0, ); } } glib-0.8.2/src/source.rs010066400017500001750000000543371354212555500133410ustar0000000000000000// Copyright 2013-2018, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use glib_sys::{self, gboolean, gpointer}; #[cfg(all(not(unix), feature = "dox"))] use libc::c_int as RawFd; use std::cell::RefCell; use std::mem::transmute; #[cfg(unix)] use std::os::unix::io::RawFd; use std::process; use std::thread; use translate::{from_glib, from_glib_full, FromGlib, ToGlib, ToGlibPtr}; #[cfg(any(unix, feature = "dox"))] use IOCondition; use MainContext; use Source; /// The id of a source that is returned by `idle_add` and `timeout_add`. #[derive(Debug, Eq, PartialEq)] pub struct SourceId(u32); #[doc(hidden)] impl ToGlib for SourceId { type GlibType = u32; #[inline] fn to_glib(&self) -> u32 { self.0 } } #[doc(hidden)] impl FromGlib for SourceId { #[inline] fn from_glib(val: u32) -> SourceId { assert_ne!(val, 0); SourceId(val) } } /// Process identificator #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct Pid(pub glib_sys::GPid); unsafe impl Send for Pid {} unsafe impl Sync for Pid {} /// 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 ToGlib for Continue { type GlibType = gboolean; #[inline] fn to_glib(&self) -> gboolean { self.0.to_glib() } } /// Unwinding propagation guard. Aborts the process if destroyed while /// panicking. #[deprecated(note = "Rustc has this functionality built-in since 1.26.0")] pub struct CallbackGuard(()); #[allow(deprecated)] impl CallbackGuard { pub fn new() -> CallbackGuard { CallbackGuard(()) } } #[allow(deprecated)] impl Default for CallbackGuard { fn default() -> Self { Self::new() } } #[allow(deprecated)] impl Drop for CallbackGuard { fn drop(&mut self) { use std::io::stderr; use std::io::Write; if thread::panicking() { let _ = stderr().write(b"Uncaught panic, exiting\n"); process::abort(); } } } unsafe extern "C" fn trampoline Continue + 'static>(func: gpointer) -> gboolean { let func: &RefCell = &*(func as *const RefCell); (&mut *func.borrow_mut())().to_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: glib_sys::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"))] unsafe extern "C" fn trampoline_unix_fd Continue + 'static>( fd: i32, condition: glib_sys::GIOCondition, func: gpointer, ) -> gboolean { let func: &RefCell = &*(func as *const RefCell); (&mut *func.borrow_mut())(fd, from_glib(condition)).to_glib() } #[cfg(any(unix, feature = "dox"))] unsafe extern "C" fn destroy_closure_unix_fd Continue + 'static>( ptr: gpointer, ) { Box::>::from_raw(ptr as *mut _); } #[cfg(any(unix, feature = "dox"))] fn into_raw_unix_fd Continue + 'static>(func: F) -> gpointer { let func: Box> = Box::new(RefCell::new(func)); Box::into_raw(func) as gpointer } /// 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. pub fn idle_add(func: F) -> SourceId where F: FnMut() -> Continue + Send + 'static, { unsafe { from_glib(glib_sys::g_idle_add_full( glib_sys::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. pub fn idle_add_local(func: F) -> SourceId where F: FnMut() -> Continue + 'static, { unsafe { assert!(MainContext::default().is_owner()); from_glib(glib_sys::g_idle_add_full( glib_sys::G_PRIORITY_DEFAULT_IDLE, 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. pub fn timeout_add(interval: u32, func: F) -> SourceId where F: FnMut() -> Continue + Send + 'static, { unsafe { from_glib(glib_sys::g_timeout_add_full( glib_sys::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 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. pub fn timeout_add_local(interval: u32, func: F) -> SourceId where F: FnMut() -> Continue + 'static, { unsafe { assert!(MainContext::default().is_owner()); from_glib(glib_sys::g_timeout_add_full( glib_sys::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. pub fn timeout_add_seconds(interval: u32, func: F) -> SourceId where F: FnMut() -> Continue + Send + 'static, { unsafe { from_glib(glib_sys::g_timeout_add_seconds_full( glib_sys::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. pub fn timeout_add_seconds_local(interval: u32, func: F) -> SourceId where F: FnMut() -> Continue + 'static, { unsafe { assert!(MainContext::default().is_owner()); from_glib(glib_sys::g_timeout_add_seconds_full( glib_sys::G_PRIORITY_DEFAULT, interval, Some(trampoline::), into_raw(func), Some(destroy_closure::), )) } } /// 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 pub fn child_watch_add(pid: Pid, func: F) -> SourceId where F: FnMut(Pid, i32) + Send + 'static, { unsafe { from_glib(glib_sys::g_child_watch_add_full( glib_sys::G_PRIORITY_DEFAULT, pid.0, Some(transmute(trampoline_child_watch:: as usize)), 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. 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(glib_sys::g_child_watch_add_full( glib_sys::G_PRIORITY_DEFAULT, pid.0, Some(transmute(trampoline_child_watch:: as usize)), into_raw_child_watch(func), Some(destroy_closure_child_watch::), )) } } #[cfg(any(unix, feature = "dox"))] /// 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. pub fn unix_signal_add(signum: i32, func: F) -> SourceId where F: FnMut() -> Continue + Send + 'static, { unsafe { from_glib(glib_sys::g_unix_signal_add_full( glib_sys::G_PRIORITY_DEFAULT, signum, Some(trampoline::), into_raw(func), Some(destroy_closure::), )) } } #[cfg(any(unix, feature = "dox"))] /// 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. pub fn unix_signal_add_local(signum: i32, func: F) -> SourceId where F: FnMut() -> Continue + 'static, { unsafe { assert!(MainContext::default().is_owner()); from_glib(glib_sys::g_unix_signal_add_full( glib_sys::G_PRIORITY_DEFAULT, signum, Some(trampoline::), into_raw(func), Some(destroy_closure::), )) } } #[cfg(any(unix, feature = "dox"))] /// 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. pub fn unix_fd_add(fd: RawFd, condition: IOCondition, func: F) -> SourceId where F: FnMut(RawFd, IOCondition) -> Continue + Send + 'static, { unsafe { from_glib(glib_sys::g_unix_fd_add_full( glib_sys::G_PRIORITY_DEFAULT, fd, condition.to_glib(), Some(transmute(trampoline_unix_fd:: as usize)), into_raw_unix_fd(func), Some(destroy_closure_unix_fd::), )) } } #[cfg(any(unix, feature = "dox"))] /// 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. 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(glib_sys::g_unix_fd_add_full( glib_sys::G_PRIORITY_DEFAULT, fd, condition.to_glib(), Some(transmute(trampoline_unix_fd:: as usize)), 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)] pub fn source_remove(source_id: SourceId) { unsafe { glib_sys::g_source_remove(source_id.to_glib()); } } /// The priority of sources /// #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct Priority(i32); #[doc(hidden)] impl ToGlib for Priority { type GlibType = i32; #[inline] fn to_glib(&self) -> i32 { self.0 } } #[doc(hidden)] impl FromGlib for Priority { #[inline] fn from_glib(val: i32) -> Priority { Priority(val) } } impl Default for Priority { fn default() -> Priority { PRIORITY_DEFAULT } } pub const PRIORITY_HIGH: Priority = Priority(glib_sys::G_PRIORITY_HIGH); pub const PRIORITY_DEFAULT: Priority = Priority(glib_sys::G_PRIORITY_DEFAULT); pub const PRIORITY_HIGH_IDLE: Priority = Priority(glib_sys::G_PRIORITY_HIGH_IDLE); pub const PRIORITY_DEFAULT_IDLE: Priority = Priority(glib_sys::G_PRIORITY_DEFAULT_IDLE); pub const PRIORITY_LOW: Priority = Priority(glib_sys::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)`. pub fn idle_source_new(name: Option<&str>, priority: Priority, func: F) -> Source where F: FnMut() -> Continue + Send + 'static, { unsafe { let source = glib_sys::g_idle_source_new(); glib_sys::g_source_set_callback( source, Some(trampoline::), into_raw(func), Some(destroy_closure::), ); glib_sys::g_source_set_priority(source, priority.to_glib()); if let Some(name) = name { glib_sys::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. pub fn timeout_source_new( interval: u32, name: Option<&str>, priority: Priority, func: F, ) -> Source where F: FnMut() -> Continue + Send + 'static, { unsafe { let source = glib_sys::g_timeout_source_new(interval); glib_sys::g_source_set_callback( source, Some(trampoline::), into_raw(func), Some(destroy_closure::), ); glib_sys::g_source_set_priority(source, priority.to_glib()); if let Some(name) = name { glib_sys::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. 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 = glib_sys::g_timeout_source_new_seconds(interval); glib_sys::g_source_set_callback( source, Some(trampoline::), into_raw(func), Some(destroy_closure::), ); glib_sys::g_source_set_priority(source, priority.to_glib()); if let Some(name) = name { glib_sys::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 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 = glib_sys::g_child_watch_source_new(pid.0); glib_sys::g_source_set_callback( source, Some(transmute(trampoline_child_watch:: as usize)), into_raw_child_watch(func), Some(destroy_closure_child_watch::), ); glib_sys::g_source_set_priority(source, priority.to_glib()); if let Some(name) = name { glib_sys::g_source_set_name(source, name.to_glib_none().0); } from_glib_full(source) } } #[cfg(any(unix, feature = "dox"))] /// 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)`. 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 = glib_sys::g_unix_signal_source_new(signum); glib_sys::g_source_set_callback( source, Some(trampoline::), into_raw(func), Some(destroy_closure::), ); glib_sys::g_source_set_priority(source, priority.to_glib()); if let Some(name) = name { glib_sys::g_source_set_name(source, name.to_glib_none().0); } from_glib_full(source) } } #[cfg(any(unix, feature = "dox"))] /// 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)`. 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 = glib_sys::g_unix_fd_source_new(fd, condition.to_glib()); glib_sys::g_source_set_callback( source, Some(transmute(trampoline_unix_fd:: as usize)), into_raw_unix_fd(func), Some(destroy_closure_unix_fd::), ); glib_sys::g_source_set_priority(source, priority.to_glib()); if let Some(name) = name { glib_sys::g_source_set_name(source, name.to_glib_none().0); } from_glib_full(source) } } impl Source { pub fn attach(&self, context: Option<&MainContext>) -> SourceId { unsafe { from_glib(glib_sys::g_source_attach( self.to_glib_none().0, context.to_glib_none().0, )) } } pub fn remove(tag: SourceId) -> Result<(), ::BoolError> { unsafe { glib_result_from_gboolean!( glib_sys::g_source_remove(tag.to_glib()), "Failed to remove source" ) } } } glib-0.8.2/src/source_futures.rs010066400017500001750000000335471352206036300151070ustar0000000000000000// Copyright 2018, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use futures::channel::{mpsc, oneshot}; use futures::prelude::*; use futures::task; use futures::task::Poll; use std::marker::Unpin; use std::pin; use Continue; use MainContext; use Priority; use 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 + Send + '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 + Send + '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(); receiver.poll_unpin(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: u32) -> Box + std::marker::Unpin + Send> { timeout_future_with_priority(::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: u32, ) -> Box + std::marker::Unpin + Send> { Box::new(SourceFuture::new(move |send| { let mut send = Some(send); ::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, ) -> Box + std::marker::Unpin + Send> { timeout_future_seconds_with_priority(::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, ) -> Box + std::marker::Unpin + Send> { Box::new(SourceFuture::new(move |send| { let mut send = Some(send); ::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: ::Pid, ) -> Box + std::marker::Unpin + Send> { child_watch_future_with_priority(::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: ::Pid, ) -> Box + std::marker::Unpin + Send> { Box::new(SourceFuture::new(move |send| { let mut send = Some(send); ::child_watch_source_new(pid, None, priority, move |pid, code| { let _ = send.take().unwrap().send((pid, code)); }) })) } #[cfg(any(unix, feature = "dox"))] /// 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) -> Box + std::marker::Unpin + Send> { unix_signal_future_with_priority(::PRIORITY_DEFAULT, signum) } #[cfg(any(unix, feature = "dox"))] /// 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, ) -> Box + std::marker::Unpin + Send> { Box::new(SourceFuture::new(move |send| { let mut send = Some(send); ::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 + Send + '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 + Send + '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(); receiver.poll_next_unpin(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: u32) -> Box + std::marker::Unpin + Send> { interval_stream_with_priority(::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: u32, ) -> Box + std::marker::Unpin + Send> { Box::new(SourceStream::new(move |send| { ::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, ) -> Box + std::marker::Unpin + Send> { interval_stream_seconds_with_priority(::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, ) -> Box + std::marker::Unpin + Send> { Box::new(SourceStream::new(move |send| { ::timeout_source_new_seconds(value, None, priority, move || { if send.unbounded_send(()).is_err() { Continue(false) } else { Continue(true) } }) })) } #[cfg(any(unix, feature = "dox"))] /// 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) -> Box + std::marker::Unpin + Send> { unix_signal_stream_with_priority(::PRIORITY_DEFAULT, signum) } #[cfg(any(unix, feature = "dox"))] /// 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, ) -> Box + std::marker::Unpin + Send> { Box::new(SourceStream::new(move |send| { ::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 std::thread; #[test] fn test_timeout() { let c = MainContext::new(); let res = c.block_on(timeout_future(20)); assert_eq!(res, ()); } #[test] fn test_timeout_send() { let c = MainContext::new(); let l = ::MainLoop::new(Some(&c), false); let l_clone = l.clone(); c.spawn(timeout_future(20).then(move |()| { l_clone.quit(); future::ready(()) })); l.run(); } #[test] fn test_interval() { let c = MainContext::new(); let mut count = 0; { let count = &mut count; let res = c.block_on( interval_stream(20) .take(2) .for_each(|()| { *count = *count + 1; future::ready(()) }) .map(|_| ()), ); assert_eq!(res, ()); } assert_eq!(count, 2); } #[test] fn test_timeout_and_channel() { let c = MainContext::default(); let res = c.block_on(timeout_future(20).then(|()| { let (sender, receiver) = oneshot::channel(); thread::spawn(move || { sender.send(1).unwrap(); }); receiver.then(|i| future::ready(i.unwrap())) })); assert_eq!(res, 1); } } glib-0.8.2/src/string.rs010066400017500001750000000140351352206036300133270ustar0000000000000000// Copyright 2018, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use glib_sys; use gobject_sys; 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; use translate::*; glib_wrapper! { /// A mutable text buffer that grows automatically. pub struct String(Boxed); match fn { copy => |ptr| gobject_sys::g_boxed_copy(glib_sys::g_gstring_get_type(), ptr as *mut _) as *mut glib_sys::GString, free => |ptr| gobject_sys::g_boxed_free(glib_sys::g_gstring_get_type(), ptr as *mut _), get_type => || glib_sys::g_gstring_get_type(), } } unsafe impl Send for String {} unsafe impl Sync for String {} impl String { pub fn new>(data: T) -> String { let bytes = data.as_ref(); unsafe { from_glib_full(glib_sys::g_string_new_len( bytes.as_ptr() as *const _, bytes.len() as isize, )) } } pub fn append(&mut self, val: &str) -> &mut Self { unsafe { glib_sys::g_string_append_len( self.to_glib_none_mut().0, val.to_glib_none().0, val.len() as isize, ); } self } pub fn insert(&mut self, pos: isize, val: &str) -> &mut Self { unsafe { glib_sys::g_string_insert_len( self.to_glib_none_mut().0, pos, val.to_glib_none().0, val.len() as isize, ); } self } pub fn overwrite(&mut self, pos: usize, val: &str) -> &mut Self { unsafe { glib_sys::g_string_overwrite_len( self.to_glib_none_mut().0, pos, val.to_glib_none().0, val.len() as isize, ); } self } pub fn prepend(&mut self, val: &str) -> &mut Self { unsafe { glib_sys::g_string_prepend_len( self.to_glib_none_mut().0, val.to_glib_none().0, val.len() as isize, ); } self } pub fn truncate(&mut self, len: usize) -> &mut Self { unsafe { glib_sys::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() -> String { unsafe { from_glib_full(glib_sys::g_string_new(ptr::null())) } } } impl fmt::Debug for String { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.to_string_lossy()) } } impl fmt::Display for String { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.to_string_lossy()) } } impl PartialEq for String { fn eq(&self, other: &Self) -> bool { unsafe { from_glib(glib_sys::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 = ::String::new(""); s.append("Hello").append(" ").append("there!"); assert_eq!(&*s, b"Hello there!"); } #[test] fn insert() { let mut s = ::String::new("foobaz"); s.insert(3, "bar"); assert_eq!(&*s, b"foobarbaz"); } #[test] fn overwrite() { let mut s = ::String::new("abc"); s.overwrite(2, "de"); assert_eq!(&*s, b"abde"); } #[test] fn prepend() { let mut s = ::String::new("456"); s.prepend("123"); assert_eq!(&*s, b"123456"); } #[test] fn truncate() { let mut s = ::String::new("12345"); s.truncate(10); assert_eq!(&*s, b"12345"); s.truncate(2); assert_eq!(&*s, b"12"); } #[test] fn default() { let s1: ::String = Default::default(); assert_eq!(&*s1, b""); } #[test] fn display() { let s: ::String = ::String::new("This is a string."); assert_eq!(&format!("{}", s), "This is a string."); } #[test] fn eq() { let a1 = ::String::new("a"); let a2 = ::String::new("a"); let b = ::String::new("b"); assert_eq!(a1, a1); assert_eq!(a1, a2); assert_ne!(a1, b); assert_ne!(a2, b); } #[test] fn invalid_utf8() { let s = ::String::new(b"Hello \xF0\x90\x80World"); assert!(s.to_str().is_err()); assert_eq!(s.to_string_lossy(), "Hello �World"); } } glib-0.8.2/src/subclass/boxed.rs010066400017500001750000000173431354212555500147550ustar0000000000000000// Copyright 2018, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or //! Module for registering boxed types for Rust types. use glib_sys; use gobject_sys; use std::ops; use translate::*; use value::*; /// 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: Clone + Sized + 'static { /// Boxed type name. /// /// This must be unique in the whole process. const NAME: &'static str; /// Returns the type ID. /// /// This is usually defined via the [`glib_boxed_type!`] macro. /// /// [`glib_boxed_type!`]: ../../macro.glib_boxed_type.html fn get_type() -> ::Type; } /// Register a boxed `glib::Type` ID for `T`. /// /// This must be called only once and will panic on a second call. /// /// See [`glib_boxed_type!`] for defining a function that ensures that /// this is only called once and returns the type id. /// /// [`glib_boxed_type!`]: ../../macro.glib_boxed_type.html pub fn register_boxed_type() -> ::Type { unsafe extern "C" fn boxed_copy(v: glib_sys::gpointer) -> glib_sys::gpointer { let v = &*(v as *mut T); let copy = Box::new(v.clone()); Box::into_raw(copy) as glib_sys::gpointer } unsafe extern "C" fn boxed_free(v: glib_sys::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_sys::g_type_from_name(type_name.as_ptr()) != gobject_sys::G_TYPE_INVALID { panic!( "Type {} has already been registered", type_name.to_str().unwrap() ); } from_glib(gobject_sys::g_boxed_type_register_static( type_name.as_ptr(), Some(boxed_copy::), Some(boxed_free::), )) } } #[macro_export] /// Macro for defining a `get_type` function. /// /// This returns a `glib::Type` and registers `Self` via [`register_boxed_type`] /// the first time it is called. /// /// [`register_boxed_type`]: subclass/boxed/fn.register_boxed_type.html macro_rules! glib_boxed_type { () => { fn get_type() -> $crate::Type { static mut TYPE_: $crate::Type = $crate::Type::Invalid; static ONCE: ::std::sync::Once = ::std::sync::Once::new(); ONCE.call_once(|| { let type_ = $crate::subclass::register_boxed_type::(); unsafe { TYPE_ = type_; } }); unsafe { TYPE_ } } }; } #[macro_export] /// Macro for deriving the `glib::Value` traits for a [`BoxedType`]. /// /// [`BoxedType`]: trait.BoxedType.html macro_rules! glib_boxed_derive_traits { ($name:ident) => { impl $crate::StaticType for $name { fn static_type() -> $crate::Type { <$name as $crate::subclass::boxed::BoxedType>::get_type() } } impl $crate::value::SetValue for $name { unsafe fn set_value(value: &mut $crate::value::Value, this: &Self) { let ptr: *mut $name = Box::into_raw(Box::new(this.clone())); $crate::gobject_sys::g_value_take_boxed( $crate::translate::ToGlibPtrMut::to_glib_none_mut(value).0, ptr as *mut _, ); } } impl $crate::value::SetValueOptional for $name { unsafe fn set_value_optional(value: &mut $crate::value::Value, this: Option<&Self>) { let this = this.expect("None not allowed"); let ptr: *mut $name = Box::into_raw(Box::new(this.clone())); $crate::gobject_sys::g_value_take_boxed( $crate::translate::ToGlibPtrMut::to_glib_none_mut(value).0, ptr as *mut _, ); } } impl<'a> $crate::value::FromValueOptional<'a> for &'a $name { unsafe fn from_value_optional(value: &'a $crate::value::Value) -> Option { let ptr = $crate::gobject_sys::g_value_get_boxed( $crate::translate::ToGlibPtr::to_glib_none(value).0, ); assert!(!ptr.is_null()); Some(&*(ptr as *mut $name)) } } impl<'a> $crate::value::FromValue<'a> for &'a $name { unsafe fn from_value(value: &'a $crate::value::Value) -> Self { let ptr = $crate::gobject_sys::g_value_get_boxed( $crate::translate::ToGlibPtr::to_glib_none(value).0, ); assert!(!ptr.is_null()); &*(ptr as *mut $name) } } }; } /// Wrapper struct for storing any `BoxedType` in `glib::Value`. /// /// Instead of this the [`glib_boxed_derive_traits!`] macro can be used to /// directly implement the relevant traits on the type itself. /// /// [`glib_boxed_derive_traits!`]: ../../macro.glib_boxed_derive_traits.html #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Boxed(pub T); impl ops::Deref for Boxed { type Target = T; fn deref(&self) -> &T { &self.0 } } impl ops::DerefMut for Boxed { fn deref_mut(&mut self) -> &mut T { &mut self.0 } } impl ::StaticType for Boxed { fn static_type() -> ::Type { T::get_type() } } impl SetValue for Boxed { unsafe fn set_value(value: &mut Value, this: &Self) { let ptr: *mut Boxed = Box::into_raw(Box::new(this.clone())); gobject_sys::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *mut _); } } impl SetValueOptional for Boxed { unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) { let this = this.expect("None not allowed"); let ptr: *mut Boxed = Box::into_raw(Box::new(this.clone())); gobject_sys::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *mut _); } } impl<'a, T: BoxedType> FromValueOptional<'a> for &'a Boxed { unsafe fn from_value_optional(value: &'a Value) -> Option { let ptr = gobject_sys::g_value_get_boxed(value.to_glib_none().0); assert!(!ptr.is_null()); Some(&*(ptr as *mut Boxed)) } } impl<'a, T: BoxedType> FromValue<'a> for &'a Boxed { unsafe fn from_value(value: &'a Value) -> Self { let ptr = gobject_sys::g_value_get_boxed(value.to_glib_none().0); assert!(!ptr.is_null()); &*(ptr as *mut Boxed) } } #[cfg(test)] mod test { use super::*; #[derive(Clone, Debug, PartialEq, Eq)] struct MyBoxed(String); impl BoxedType for MyBoxed { const NAME: &'static str = "MyBoxed"; glib_boxed_type!(); } glib_boxed_derive_traits!(MyBoxed); #[test] fn test_register() { assert_ne!(::Type::Invalid, MyBoxed::get_type()); } #[test] fn test_value_boxed() { assert_ne!(::Type::Invalid, MyBoxed::get_type()); let b = Boxed(MyBoxed(String::from("abc"))); let v = b.to_value(); let b2 = v.get::<&Boxed>().unwrap(); assert_eq!(&b, b2); } #[test] fn test_value() { assert_ne!(::Type::Invalid, MyBoxed::get_type()); let b = MyBoxed(String::from("abc")); let v = b.to_value(); let b2 = v.get::<&MyBoxed>().unwrap(); assert_eq!(&b, b2); } } glib-0.8.2/src/subclass/guard.rs010066400017500001750000000033451352206036300147440ustar0000000000000000// Copyright 2017-2018, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use glib_sys; use gobject_sys; use std::ptr; #[macro_export] /// Macro for creating a [`FloatingReferenceGuard`]. /// /// This is creating a guard type for keeping the `GObject` floating reference flag intact inside /// virtual method implementations. /// /// Pass a valid, C `GObject` pointer to the macro. It can only be used inside `unsafe` blocks. /// /// [`FloatingReferenceGuard`]: subclass/guard/struct.FloatingReferenceGuard.html macro_rules! glib_floating_reference_guard { ($obj:ident) => { let _guard = $crate::subclass::guard::FloatingReferenceGuard::new($obj as *mut _); }; } /// Guard type for keeping the `GObject` floating reference flag intact /// inside virtual method implementations. /// /// This should be created via the [`floating_reference_guard!`] macro. /// /// [`floating_reference_guard!`]: ../../macro.floating_reference_guard.html pub struct FloatingReferenceGuard(ptr::NonNull); impl FloatingReferenceGuard { #[doc(hidden)] pub unsafe fn new(obj: *mut gobject_sys::GObject) -> Option { assert!(!obj.is_null()); if gobject_sys::g_object_is_floating(obj) != glib_sys::GFALSE { gobject_sys::g_object_ref_sink(obj); Some(FloatingReferenceGuard(ptr::NonNull::new_unchecked(obj))) } else { None } } } impl Drop for FloatingReferenceGuard { fn drop(&mut self) { unsafe { gobject_sys::g_object_force_floating(self.0.as_ptr()); } } } glib-0.8.2/src/subclass/interface.rs010066400017500001750000000240071352206036300156000ustar0000000000000000// Copyright 2019, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use super::{InitializingType, Property}; use glib_sys; use gobject_sys; use std::borrow::Borrow; use std::marker; use std::mem; use std::ptr; use translate::*; use {IsA, Object, ObjectExt, SignalFlags, StaticType, Type, Value}; impl InitializingType { /// Adds an interface prerequisite for `I` to the type. /// /// All implementors of the interface must be a subclass of `I` or implement the interface `I`. pub fn add_prerequisite(&mut self) { unsafe { gobject_sys::g_type_interface_add_prerequisite( self.0.to_glib(), I::static_type().to_glib(), ) } } } /// Macro for boilerplate of [`ObjectInterface`] implementations. /// /// [`ObjectInterface`]: subclass/types/trait.ObjectInterface.html #[macro_export] macro_rules! glib_object_interface { () => { fn get_type() -> $crate::Type { static ONCE: ::std::sync::Once = ::std::sync::Once::new(); static mut TYPE: $crate::Type = $crate::Type::Invalid; ONCE.call_once(|| { let type_ = $crate::subclass::register_interface::(); unsafe { TYPE = type_; } }); unsafe { assert_ne!(TYPE, $crate::Type::Invalid); TYPE } } }; } /// The central trait for defining a `GObject` interface. /// /// Links together the type name and the interface struct for type registration and allows to hook /// into various steps of the type registration and initialization. /// /// This must only be implemented on `#[repr(C)]` structs and have `gobject_sys::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 trait ObjectInterface: Sized + 'static { /// `GObject` type name. /// /// This must be unique in the whole process. const NAME: &'static str; /// Returns the `glib::Type` ID of the interface. /// /// This will register the type with the type system on the first call and is usually generated /// by the [`glib_object_interface!`] macro. /// /// [`glib_object_interface!`]: ../../macro.glib_object_interface.html fn get_type() -> Type; /// Additional type initialization. /// /// This is called right after the type was registered and allows /// interfaces to do additional type-specific initialization, e.g. /// for adding prerequisites. /// /// 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 properties or signals /// on the interface, and for setting default implementations of interface /// functions. /// /// Optional fn interface_init(&mut self) {} } 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().get_type().is_a(&Self::get_type())); unsafe { let klass = (*(obj.as_ptr() as *const gobject_sys::GTypeInstance)).g_class; let interface = gobject_sys::g_type_interface_peek(klass as *mut _, Self::get_type().to_glib()); assert!(!interface.is_null()); &*(interface as *const Self) } } /// Install properties on the interface. /// /// All implementors of the interface must provide these properties. fn install_properties<'a, T: Borrow>>(&mut self, properties: &[T]) { if properties.is_empty() { return; } for property in properties { let property = property.borrow(); let pspec = (property.1)(property.0); unsafe { gobject_sys::g_object_interface_install_property( self as *mut Self as *mut _, pspec.to_glib_none().0, ); } } } /// Add a new signal to the interface. /// /// This can be emitted later by `glib::Object::emit` and external code /// can connect to the signal to get notified about emissions. fn add_signal(&mut self, name: &str, flags: SignalFlags, arg_types: &[Type], ret_type: Type) { unsafe { super::types::add_signal( *(self as *mut _ as *mut glib_sys::GType), name, flags, arg_types, ret_type, ); } } /// Add a new signal with class handler to the interface. /// /// This can be emitted later by `glib::Object::emit` and external code /// can connect to the signal to get notified about emissions. /// /// The class handler will be called during the signal emission at the corresponding stage. fn add_signal_with_class_handler( &mut self, name: &str, flags: SignalFlags, arg_types: &[Type], ret_type: Type, class_handler: F, ) where F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option + Send + Sync + 'static, { unsafe { super::types::add_signal_with_class_handler( *(self as *mut _ as *mut glib_sys::GType), name, flags, arg_types, ret_type, class_handler, ); } } /// Add a new signal with accumulator to the interface. /// /// This can be emitted later by `glib::Object::emit` and external code /// can connect to the signal to get notified about emissions. /// /// The accumulator function is used for accumulating the return values of /// multiple signal handlers. The new value is passed as second argument and /// should be combined with the old value in the first argument. If no further /// signal handlers should be called, `false` should be returned. fn add_signal_with_accumulator( &mut self, name: &str, flags: SignalFlags, arg_types: &[Type], ret_type: Type, accumulator: F, ) where F: Fn(&super::SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static, { unsafe { super::types::add_signal_with_accumulator( *(self as *mut _ as *mut glib_sys::GType), name, flags, arg_types, ret_type, accumulator, ); } } /// Add a new signal with accumulator and class handler to the interface. /// /// This can be emitted later by `glib::Object::emit` and external code /// can connect to the signal to get notified about emissions. /// /// The accumulator function is used for accumulating the return values of /// multiple signal handlers. The new value is passed as second argument and /// should be combined with the old value in the first argument. If no further /// signal handlers should be called, `false` should be returned. /// /// The class handler will be called during the signal emission at the corresponding stage. fn add_signal_with_class_handler_and_accumulator( &mut self, name: &str, flags: SignalFlags, arg_types: &[Type], ret_type: Type, class_handler: F, accumulator: G, ) where F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option + Send + Sync + 'static, G: Fn(&super::SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static, { unsafe { super::types::add_signal_with_class_handler_and_accumulator( *(self as *mut _ as *mut glib_sys::GType), name, flags, arg_types, ret_type, class_handler, accumulator, ); } } } impl ObjectInterfaceExt for T {} unsafe extern "C" fn interface_init( klass: glib_sys::gpointer, _klass_data: glib_sys::gpointer, ) { let iface = &mut *(klass as *mut T); iface.interface_init(); } /// Register a `glib::Type` ID for `T`. /// /// This must be called only once and will panic on a second call. /// /// The [`glib_object_interface!`] macro will create a `get_type()` function around this, which will /// ensure that it's only ever called once. /// /// [`glib_object_interface!`]: ../../macro.glib_object_interface.html pub fn register_interface() -> Type { unsafe { use std::ffi::CString; let type_info = gobject_sys::GTypeInfo { class_size: mem::size_of::() as u16, base_init: None, base_finalize: None, class_init: Some(interface_init::), class_finalize: None, class_data: ptr::null_mut(), instance_size: 0, n_preallocs: 0, instance_init: None, value_table: ptr::null(), }; let type_name = CString::new(T::NAME).unwrap(); assert_eq!( gobject_sys::g_type_from_name(type_name.as_ptr()), gobject_sys::G_TYPE_INVALID ); let type_ = from_glib(gobject_sys::g_type_register_static( Type::BaseInterface.to_glib(), type_name.as_ptr(), &type_info, 0, )); T::type_init(&mut InitializingType::(type_, marker::PhantomData)); type_ } } glib-0.8.2/src/subclass/mod.rs010066400017500001750000000147261354212555500144350ustar0000000000000000// Copyright 2017-2018, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or //! 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 //! #[macro_use] //! extern crate glib; //! use glib::prelude::*; //! use glib::subclass; //! use glib::subclass::prelude::*; //! //! use std::cell::RefCell; //! //! // Static array for defining the properties of the new type. //! static PROPERTIES: [subclass::Property; 1] = [subclass::Property("name", |name| { //! glib::ParamSpec::string( //! name, //! "Name", //! "Name of this object", //! None, //! glib::ParamFlags::READWRITE, //! ) //! })]; //! //! // This is the struct containing all state carried with //! // the new type. Generally this has to make use of //! // interior mutability. //! pub struct SimpleObject { //! name: 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. //! 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 ParentType = glib::Object; //! //! // The C/FFI instance and class structs. The simple ones //! // are enough in most cases and more is only needed to //! // expose public instance fields to C APIs or to provide //! // new virtual methods for subclasses of this type. //! type Instance = subclass::simple::InstanceStruct; //! type Class = subclass::simple::ClassStruct; //! //! // This macro defines some boilerplate. //! glib_object_subclass!(); //! //! // Called right before the first time an instance of the new //! // type is created. Here class specific settings can be performed, //! // including installation of properties and registration of signals //! // for the new type. //! fn class_init(klass: &mut subclass::simple::ClassStruct) { //! klass.install_properties(&PROPERTIES); //! } //! //! // Called every time a new instance is created. This should return //! // a new instance of our type with its basic values. //! fn new() -> Self { //! Self { //! name: RefCell::new(None), //! } //! } //! } //! //! // Trait that is used to override virtual methods of glib::Object. //! impl ObjectImpl for SimpleObject { //! // This macro defines some boilerplate. //! glib_object_impl!(); //! //! // 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: &glib::Object, id: usize, value: &glib::Value) { //! let prop = &PROPERTIES[id]; //! //! match *prop { //! subclass::Property("name", ..) => { //! let name = value.get(); //! self.name.replace(name); //! } //! _ => 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 get_property(&self, _obj: &glib::Object, id: usize) -> Result { //! let prop = &PROPERTIES[id]; //! //! match *prop { //! subclass::Property("name", ..) => Ok(self.name.borrow().to_value()), //! _ => unimplemented!(), //! } //! } //! //! // Called right after construction of the instance. //! fn constructed(&self, obj: &glib::Object) { //! // Chain up to the parent type's implementation of this virtual //! // method. //! self.parent_constructed(obj); //! //! // And here we could do our own initialization. //! } //! } //! //! pub fn main() { //! // Create an object instance of the new type. //! let obj = glib::Object::new(SimpleObject::get_type(), &[]).unwrap(); //! //! // Get the name property and change its value. //! assert_eq!(obj.get_property("name").unwrap().get::<&str>(), None); //! obj.set_property("name", &"test").unwrap(); //! assert_eq!( //! obj.get_property("name").unwrap().get::<&str>(), //! Some("test") //! ); //! } //! ``` //! //! # 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 //! #[macro_use] //! extern crate glib; //! use glib::prelude::*; //! use glib::subclass; //! use glib::subclass::prelude::*; //! //! #[derive(Clone, Debug, PartialEq, Eq)] //! struct MyBoxed(String); //! //! impl BoxedType for MyBoxed { //! // This type name must be unique per process. //! const NAME: &'static str = "MyBoxed"; //! //! // This macro defines a //! // fn get_type() -> glib::Type //! // function //! glib_boxed_type!(); //! } //! //! // This macro derives some traits on the struct //! glib_boxed_derive_traits!(MyBoxed); //! //! pub fn main() { //! assert_ne!(glib::Type::Invalid, MyBoxed::get_type()); //! //! let b = MyBoxed(String::from("abc")); //! let v = b.to_value(); //! let b2 = v.get::<&MyBoxed>().unwrap(); //! assert_eq!(&b, b2); //! } //! ``` #[macro_use] #[doc(hidden)] pub mod guard; pub mod simple; #[macro_use] pub mod types; #[macro_use] pub mod interface; #[macro_use] pub mod object; #[macro_use] pub mod boxed; pub mod prelude { //! Prelude that re-exports all important traits from this crate. pub use super::boxed::BoxedType; pub use super::interface::{ObjectInterface, ObjectInterfaceExt}; pub use super::object::{ObjectClassSubclassExt, ObjectImpl, ObjectImplExt}; pub use super::types::{ ClassStruct, InstanceStruct, IsImplementable, IsSubclassable, ObjectSubclass, }; } pub use self::boxed::register_boxed_type; pub use self::interface::register_interface; pub use self::object::Property; pub use self::types::{ register_type, InitializingType, SignalClassHandlerToken, SignalInvocationHint, TypeData, }; glib-0.8.2/src/subclass/object.rs010066400017500001750000000431631354212555500151210ustar0000000000000000// Copyright 2017-2018, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or //! Module that contains all types needed for creating a direct subclass of `GObject` //! or implementing virtual methods of it. use super::prelude::*; use super::types; use glib_sys; use gobject_sys; use std::borrow::Borrow; use std::fmt; use std::mem; use std::ptr; use translate::*; use {Object, ObjectClass, ObjectType, SignalFlags, Type, Value}; #[macro_export] /// Macro for boilerplate of [`ObjectImpl`] implementations. /// /// [`ObjectImpl`]: subclass/object/trait.ObjectImpl.html macro_rules! glib_object_impl { () => { fn get_type_data(&self) -> ::std::ptr::NonNull<$crate::subclass::TypeData> { Self::type_data() } }; } /// Trait for implementors of `glib::Object` subclasses. /// /// This allows overriding the virtual methods of `glib::Object`. pub trait ObjectImpl: ObjectImplExt + 'static { /// Storage for the type-specific data used during registration. /// /// This is usually generated by the [`glib_object_impl!`] macro. /// /// [`glib_object_impl!`]: ../../macro.glib_object_impl.html fn get_type_data(&self) -> ptr::NonNull; /// 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: &Object, _id: usize, _value: &Value) { unimplemented!() } /// Property getter. /// /// This is called whenever the property value of the specific subclass with the /// given index should be returned. fn get_property(&self, _obj: &Object, _id: usize) -> Result { unimplemented!() } /// Constructed. /// /// This is called once construction of the instance is finished. /// /// Should chain up to the parent class' implementation. fn constructed(&self, obj: &Object) { self.parent_constructed(obj); } } unsafe extern "C" fn get_property( obj: *mut gobject_sys::GObject, id: u32, value: *mut gobject_sys::GValue, _pspec: *mut gobject_sys::GParamSpec, ) { glib_floating_reference_guard!(obj); let instance = &*(obj as *mut T::Instance); let imp = instance.get_impl(); match imp.get_property(&from_glib_borrow(obj), (id - 1) as usize) { Ok(v) => { // 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_sys::g_value_unset(value); ptr::write(value, ptr::read(v.to_glib_none().0)); mem::forget(v); } Err(()) => eprintln!("Failed to get property"), } } unsafe extern "C" fn set_property( obj: *mut gobject_sys::GObject, id: u32, value: *mut gobject_sys::GValue, _pspec: *mut gobject_sys::GParamSpec, ) { glib_floating_reference_guard!(obj); let instance = &*(obj as *mut T::Instance); let imp = instance.get_impl(); imp.set_property( &from_glib_borrow(obj), (id - 1) as usize, &*(value as *mut Value), ); } unsafe extern "C" fn constructed(obj: *mut gobject_sys::GObject) { glib_floating_reference_guard!(obj); let instance = &*(obj as *mut T::Instance); let imp = instance.get_impl(); imp.constructed(&from_glib_borrow(obj)); } /// Definition of a property. #[derive(Clone)] pub struct Property<'a>(pub &'a str, pub fn(&str) -> ::ParamSpec); impl<'a> fmt::Debug for Property<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.debug_tuple("Property").field(&self.0).finish() } } /// Extension trait for `glib::Object`'s class struct. /// /// This contains various class methods and allows subclasses to override the virtual methods. pub unsafe trait ObjectClassSubclassExt: Sized + 'static { /// Install properties on the subclass. /// /// The index in the properties array is going to be the index passed to the /// property setters and getters. fn install_properties<'a, T: Borrow>>(&mut self, properties: &[T]) { if properties.is_empty() { return; } let mut pspecs = Vec::with_capacity(properties.len()); for property in properties { let property = property.borrow(); let pspec = (property.1)(property.0); pspecs.push(pspec); } unsafe { let mut pspecs_ptrs = Vec::with_capacity(properties.len()); pspecs_ptrs.push(ptr::null_mut()); for pspec in &pspecs { pspecs_ptrs.push(pspec.to_glib_none().0); } gobject_sys::g_object_class_install_properties( self as *mut _ as *mut gobject_sys::GObjectClass, pspecs_ptrs.len() as u32, pspecs_ptrs.as_mut_ptr(), ); } } /// Add a new signal to the subclass. /// /// This can be emitted later by `glib::Object::emit` and external code /// can connect to the signal to get notified about emissions. fn add_signal(&mut self, name: &str, flags: SignalFlags, arg_types: &[Type], ret_type: Type) { unsafe { super::types::add_signal( *(self as *mut _ as *mut glib_sys::GType), name, flags, arg_types, ret_type, ); } } /// Add a new signal with class handler to the subclass. /// /// This can be emitted later by `glib::Object::emit` and external code /// can connect to the signal to get notified about emissions. /// /// The class handler will be called during the signal emission at the corresponding stage. fn add_signal_with_class_handler( &mut self, name: &str, flags: SignalFlags, arg_types: &[Type], ret_type: Type, class_handler: F, ) where F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option + Send + Sync + 'static, { unsafe { super::types::add_signal_with_class_handler( *(self as *mut _ as *mut glib_sys::GType), name, flags, arg_types, ret_type, class_handler, ); } } /// Add a new signal with accumulator to the subclass. /// /// This can be emitted later by `glib::Object::emit` and external code /// can connect to the signal to get notified about emissions. /// /// The accumulator function is used for accumulating the return values of /// multiple signal handlers. The new value is passed as second argument and /// should be combined with the old value in the first argument. If no further /// signal handlers should be called, `false` should be returned. fn add_signal_with_accumulator( &mut self, name: &str, flags: SignalFlags, arg_types: &[Type], ret_type: Type, accumulator: F, ) where F: Fn(&super::SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static, { unsafe { super::types::add_signal_with_accumulator( *(self as *mut _ as *mut glib_sys::GType), name, flags, arg_types, ret_type, accumulator, ); } } /// Add a new signal with accumulator and class handler to the subclass. /// /// This can be emitted later by `glib::Object::emit` and external code /// can connect to the signal to get notified about emissions. /// /// The accumulator function is used for accumulating the return values of /// multiple signal handlers. The new value is passed as second argument and /// should be combined with the old value in the first argument. If no further /// signal handlers should be called, `false` should be returned. /// /// The class handler will be called during the signal emission at the corresponding stage. fn add_signal_with_class_handler_and_accumulator( &mut self, name: &str, flags: SignalFlags, arg_types: &[Type], ret_type: Type, class_handler: F, accumulator: G, ) where F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option + Send + Sync + 'static, G: Fn(&super::SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static, { unsafe { super::types::add_signal_with_class_handler_and_accumulator( *(self as *mut _ as *mut glib_sys::GType), name, flags, arg_types, ret_type, class_handler, accumulator, ); } } 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 glib_sys::GType), class_handler, ); } } } unsafe impl ObjectClassSubclassExt for ObjectClass {} unsafe impl IsSubclassable for ObjectClass { fn override_vfuncs(&mut self) { unsafe { let klass = &mut *(self as *mut Self as *mut gobject_sys::GObjectClass); klass.set_property = Some(set_property::); klass.get_property = Some(get_property::); klass.constructed = Some(constructed::); } } } pub trait ObjectImplExt { /// Chain up to the parent class' implementation of `glib::Object::constructed()`. fn parent_constructed(&self, obj: &Object); fn signal_chain_from_overridden( &self, token: &super::SignalClassHandlerToken, values: &[Value], ) -> Option; } impl ObjectImplExt for T { fn parent_constructed(&self, obj: &Object) { unsafe { let data = self.get_type_data(); let parent_class = data.as_ref().get_parent_class() as *mut gobject_sys::GObjectClass; if let Some(ref func) = (*parent_class).constructed { func(obj.to_glib_none().0); } } } fn signal_chain_from_overridden( &self, token: &super::SignalClassHandlerToken, values: &[Value], ) -> Option { unsafe { super::types::signal_chain_from_overridden( self.get_instance().as_ptr() as *mut _, token, values, ) } } } #[cfg(test)] mod test { use super::super::super::object::ObjectExt; use super::super::super::subclass; use super::super::super::value::{ToValue, Value}; use super::*; use prelude::*; use std::cell::RefCell; static PROPERTIES: [Property; 2] = [ Property("name", |name| { ::ParamSpec::string( name, "Name", "Name of this object", None, ::ParamFlags::READWRITE, ) }), Property("constructed", |name| { ::ParamSpec::boolean( name, "Constructed", "True if the constructed() virtual method was called", false, ::ParamFlags::READABLE, ) }), ]; pub struct SimpleObject { name: RefCell>, constructed: RefCell, } impl ObjectSubclass for SimpleObject { const NAME: &'static str = "SimpleObject"; type ParentType = Object; type Instance = subclass::simple::InstanceStruct; type Class = subclass::simple::ClassStruct; glib_object_subclass!(); fn type_init(type_: &mut subclass::InitializingType) { type_.add_interface::(); } fn class_init(klass: &mut subclass::simple::ClassStruct) { klass.install_properties(&PROPERTIES); klass.add_signal( "name-changed", SignalFlags::RUN_LAST, &[String::static_type()], ::Type::Unit, ); klass.add_signal_with_class_handler( "change-name", SignalFlags::RUN_LAST | SignalFlags::ACTION, &[String::static_type()], String::static_type(), |_, args| { let obj = args[0].get::().unwrap(); let new_name = args[1].get::().unwrap(); let imp = Self::from_instance(&obj); let old_name = imp.name.borrow_mut().take(); *imp.name.borrow_mut() = Some(new_name); obj.emit("name-changed", &[&*imp.name.borrow()]).unwrap(); Some(old_name.to_value()) }, ); } fn new() -> Self { Self { name: RefCell::new(None), constructed: RefCell::new(false), } } } impl ObjectImpl for SimpleObject { glib_object_impl!(); fn set_property(&self, obj: &Object, id: usize, value: &Value) { let prop = &PROPERTIES[id]; match *prop { Property("name", ..) => { let name = value.get(); self.name.replace(name); obj.emit("name-changed", &[&*self.name.borrow()]).unwrap(); } _ => unimplemented!(), } } fn get_property(&self, _obj: &Object, id: usize) -> Result { let prop = &PROPERTIES[id]; match *prop { Property("name", ..) => Ok(self.name.borrow().to_value()), Property("constructed", ..) => Ok(self.constructed.borrow().to_value()), _ => unimplemented!(), } } fn constructed(&self, obj: &Object) { self.parent_constructed(obj); assert_eq!(obj, &self.get_instance()); assert_eq!(self as *const _, Self::from_instance(obj) as *const _); *self.constructed.borrow_mut() = true; } } #[repr(C)] pub struct DummyInterface { parent: gobject_sys::GTypeInterface, } impl ObjectInterface for DummyInterface { const NAME: &'static str = "DummyInterface"; glib_object_interface!(); fn type_init(type_: &mut subclass::InitializingType) { type_.add_prerequisite::(); } } // Usually this would be implemented on a Rust wrapper type defined // with glib_wrapper!() but for the test the following is susyscient impl StaticType for DummyInterface { fn static_type() -> Type { DummyInterface::get_type() } } // Usually this would be implemented on a Rust wrapper type defined // with glib_wrapper!() but for the test the following is susyscient unsafe impl IsImplementable for DummyInterface { unsafe extern "C" fn interface_init( _iface: glib_sys::gpointer, _iface_data: glib_sys::gpointer, ) { } } #[test] fn test_create() { let type_ = SimpleObject::get_type(); let obj = Object::new(type_, &[]).unwrap(); assert!(obj.get_type().is_a(&DummyInterface::static_type())); assert_eq!( obj.get_property("constructed").unwrap().get::(), Some(true) ); assert_eq!(obj.get_property("name").unwrap().get::<&str>(), None); obj.set_property("name", &"test").unwrap(); assert_eq!( obj.get_property("name").unwrap().get::<&str>(), Some("test") ); let weak = obj.downgrade(); drop(obj); assert!(weak.upgrade().is_none()); } #[test] fn test_signals() { use std::sync::{Arc, Mutex}; let type_ = SimpleObject::get_type(); let obj = Object::new(type_, &[("name", &"old-name")]).unwrap(); let name_changed_triggered = Arc::new(Mutex::new(false)); let name_changed_clone = name_changed_triggered.clone(); obj.connect("name-changed", false, move |args| { let _obj = args[0].get::().unwrap(); let name = args[1].get::<&str>().unwrap(); assert_eq!(name, "new-name"); *name_changed_clone.lock().unwrap() = true; None }) .unwrap(); assert_eq!( obj.get_property("name").unwrap().get::<&str>(), Some("old-name") ); assert!(!*name_changed_triggered.lock().unwrap()); let old_name = obj .emit("change-name", &[&"new-name"]) .unwrap() .unwrap() .get::(); assert_eq!(old_name, Some(String::from("old-name"))); assert!(*name_changed_triggered.lock().unwrap()); } } glib-0.8.2/src/subclass/simple.rs010066400017500001750000000027701352206036300151340ustar0000000000000000// Copyright 2017-2018, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or //! This module contains simple 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 object::ObjectType; use std::ops; /// A simple instance struct that does not store any additional data. #[repr(C)] pub struct InstanceStruct { parent: ::GlibType, } unsafe impl super::types::InstanceStruct for InstanceStruct { type Type = T; } /// A simple class struct that does not store any additional data /// or virtual methods. #[repr(C)] pub struct ClassStruct { parent_class: ::GlibClassType, } unsafe impl super::types::ClassStruct for ClassStruct { type Type = T; } impl ops::Deref for ClassStruct { type Target = <::ParentType as ObjectType>::RustClassType; 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.8.2/src/subclass/types.rs010066400017500001750000000574321352206036300150140ustar0000000000000000// Copyright 2017-2018, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or //! Module that contains the basic infrastructure for subclassing `GObject`. use super::object::ObjectImpl; use glib_sys; use gobject_sys; use object::{ObjectExt, ObjectType}; use std::fmt; use std::marker; use std::mem; use std::ptr; use translate::*; use {Closure, IsA, IsClassFor, SignalFlags, StaticType, Type, Value}; /// A newly registered `glib::Type` that is currently still being initialized. /// /// This allows running additional type-setup functions, e.g. for implementing /// interfaces on the type. #[derive(Debug, PartialEq, Eq)] pub struct InitializingType(pub(crate) Type, pub(crate) marker::PhantomData); impl InitializingType { /// Adds an interface implementation for `I` to the type. pub fn add_interface>(&mut self) { unsafe { let iface_info = gobject_sys::GInterfaceInfo { interface_init: Some(I::interface_init), interface_finalize: None, interface_data: ptr::null_mut(), }; gobject_sys::g_type_add_interface_static( self.0.to_glib(), I::static_type().to_glib(), &iface_info, ); } } } impl ToGlib for InitializingType { type GlibType = glib_sys::GType; fn to_glib(&self) -> glib_sys::GType { self.0.to_glib() } } /// 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 [`simple::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. /// /// [`simple::InstanceStruct`]: ../simple/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 fn get_impl(&self) -> &Self::Type { unsafe { let data = Self::Type::type_data(); let private_offset = data.as_ref().private_offset; let ptr: *const u8 = self as *const _ as *const u8; let priv_ptr = ptr.offset(private_offset); let imp = priv_ptr as *const Option; (*imp).as_ref().expect("No private struct") } } /// Returns the class struct for this specific instance. fn get_class(&self) -> &::Class { unsafe { &**(self as *const _ as *const *const ::Class) } } } /// 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 [`simple::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. /// /// [`simple::ClassStruct`]: ../simple/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 override_vfuncs(&mut self) where <::ParentType as ObjectType>::RustClassType: IsSubclassable, { unsafe { let base = &mut *(self as *mut _ as *mut <::ParentType as ObjectType>::RustClassType); base.override_vfuncs(); } } } /// Trait for subclassable class structs. pub unsafe trait IsSubclassable: IsClassFor { /// Override the virtual methods of this class for the given subclass. /// /// This is automatically called during type initialization. fn override_vfuncs(&mut self); } /// Trait for implementable interfaces. pub unsafe trait IsImplementable: StaticType { /// Initializes the interface's virtual methods. unsafe extern "C" fn interface_init(iface: glib_sys::gpointer, _iface_data: glib_sys::gpointer); } /// Type-specific data that is filled in during type creation. pub struct TypeData { #[doc(hidden)] pub type_: Type, #[doc(hidden)] pub parent_class: glib_sys::gpointer, #[doc(hidden)] pub interface_data: *const Vec<(glib_sys::GType, glib_sys::gpointer)>, #[doc(hidden)] pub private_offset: isize, } unsafe impl Send for TypeData {} unsafe impl Sync for TypeData {} impl TypeData { /// Returns the type ID. pub fn get_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. pub fn get_parent_class(&self) -> glib_sys::gpointer { self.parent_class } /// Returns a pointer to the interface implementation specific data. /// /// This is used for interface implementations to store additional data. pub fn get_interface_data(&self, type_: glib_sys::GType) -> glib_sys::gpointer { unsafe { if self.interface_data.is_null() { return ptr::null_mut(); } for &(t, p) in &(*self.interface_data) { if t == type_ { return p; } } ptr::null_mut() } } /// Returns the offset of the private struct in bytes relative to the /// beginning of the instance struct. pub fn get_private_offset(&self) -> isize { self.private_offset } } #[macro_export] /// Macro for boilerplate of [`ObjectSubclass`] implementations. /// /// [`ObjectSubclass`]: subclass/types/trait.ObjectSubclass.html macro_rules! glib_object_subclass { () => { fn type_data() -> ::std::ptr::NonNull<$crate::subclass::TypeData> { static mut DATA: $crate::subclass::TypeData = $crate::subclass::TypeData { type_: $crate::Type::Invalid, parent_class: ::std::ptr::null_mut(), interface_data: ::std::ptr::null_mut(), private_offset: 0, }; unsafe { ::std::ptr::NonNull::new_unchecked(&mut DATA) } } fn get_type() -> $crate::Type { static ONCE: ::std::sync::Once = ::std::sync::Once::new(); ONCE.call_once(|| { $crate::subclass::register_type::(); }); unsafe { let data = Self::type_data(); let type_ = data.as_ref().get_type(); assert_ne!(type_, $crate::Type::Invalid); 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: ObjectImpl + 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; /// Parent Rust type to inherit from. type ParentType: ObjectType + FromGlibPtrBorrow<*mut ::GlibType> + FromGlibPtrNone<*mut ::GlibType>; /// The C instance struct. /// /// See [`simple::InstanceStruct`] for an basic instance struct that should be /// used in most cases. /// /// [`simple::InstanceStruct`]: ../simple/struct.InstanceStruct.html // TODO: Should default to simple::InstanceStruct once associated // type defaults are stabilized https://github.com/rust-lang/rust/issues/29661 type Instance: InstanceStruct; /// The C class struct. /// /// See [`simple::ClassStruct`] for an basic instance struct that should be /// used in most cases. /// /// [`simple::ClassStruct`]: ../simple/struct.ClassStruct.html // TODO: Should default to simple::ClassStruct once associated // type defaults are stabilized https://github.com/rust-lang/rust/issues/29661 type Class: ClassStruct; /// Storage for the type-specific data used during registration. /// /// This is usually generated by the [`glib_object_subclass!`] macro. /// /// [`glib_object_subclass!`]: ../../macro.glib_object_subclass.html 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 and is usually generated /// by the [`glib_object_subclass!`] macro. /// /// [`glib_object_subclass!`]: ../../macro.glib_object_subclass.html fn get_type() -> Type; /// Returns the corresponding object instance. fn get_instance(&self) -> Self::ParentType { unsafe { let data = Self::type_data(); let type_ = data.as_ref().get_type(); assert_ne!(type_, Type::Invalid); let offset = -data.as_ref().private_offset; assert_ne!(offset, 0); let ptr = self as *const Self as *const u8; let ptr = ptr.offset(offset); let ptr = ptr as *mut u8 as *mut ::GlibType; from_glib_none(ptr) } } /// Returns the implementation from an instance. /// /// Panics if called on an object of the wrong type. fn from_instance>(obj: &T) -> &Self { unsafe { let data = Self::type_data(); let type_ = data.as_ref().get_type(); assert_ne!(type_, Type::Invalid); assert!(obj.get_type().is_a(&type_)); let ptr = obj.as_ptr() as *const Self::Instance; (*ptr).get_impl() } } /// 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 installing properties or 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 `new_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 new_with_class(_klass: &Self::Class) -> Self { Self::new() } } unsafe extern "C" fn class_init( klass: glib_sys::gpointer, _klass_data: glib_sys::gpointer, ) where <::ParentType as ObjectType>::RustClassType: IsSubclassable, { 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_sys::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_sys::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_sys::g_type_class_peek_parent(klass as *mut _ as glib_sys::gpointer) as *mut ::GlibClassType; assert!(!parent_class.is_null()); (*data.as_mut()).parent_class = parent_class as glib_sys::gpointer; klass.override_vfuncs(); T::class_init(klass); } } unsafe extern "C" fn instance_init( obj: *mut gobject_sys::GTypeInstance, klass: glib_sys::gpointer, ) { glib_floating_reference_guard!(obj); // 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: *mut u8 = obj as *mut _ as *mut u8; let priv_ptr = ptr.offset(private_offset); let imp_storage = priv_ptr as *mut Option; let klass = &*(klass as *const T::Class); let imp = T::new_with_class(klass); ptr::write(imp_storage, Some(imp)); } unsafe extern "C" fn finalize(obj: *mut gobject_sys::GObject) { // Retrieve the private struct, take it out of its storage and // drop it for freeing all associated memory. let mut data = T::type_data(); let private_offset = (*data.as_mut()).private_offset; let ptr: *mut u8 = obj as *mut _ as *mut u8; let priv_ptr = ptr.offset(private_offset); let imp_storage = priv_ptr as *mut Option; let imp = (*imp_storage).take().expect("No private struct"); drop(imp); // Chain up to the parent class' finalize implementation, if any. let parent_class = &*(data.as_ref().get_parent_class() as *const gobject_sys::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 [`glib_object_subclass!`] macro will create a `get_type()` function around this, which will /// ensure that it's only ever called once. /// /// [`glib_object_subclass!`]: ../../macro.glib_object_subclass.html pub fn register_type() -> Type where <::ParentType as ObjectType>::RustClassType: IsSubclassable, { unsafe { use std::ffi::CString; let type_info = gobject_sys::GTypeInfo { class_size: mem::size_of::() as u16, base_init: None, base_finalize: None, class_init: Some(class_init::), class_finalize: None, class_data: ptr::null_mut(), instance_size: mem::size_of::() as u16, n_preallocs: 0, instance_init: Some(instance_init::), value_table: ptr::null(), }; let type_name = CString::new(T::NAME).unwrap(); if gobject_sys::g_type_from_name(type_name.as_ptr()) != gobject_sys::G_TYPE_INVALID { panic!( "Type {} has already been registered", type_name.to_str().unwrap() ); } let type_ = from_glib(gobject_sys::g_type_register_static( ::static_type().to_glib(), type_name.as_ptr(), &type_info, if T::ABSTRACT { gobject_sys::G_TYPE_FLAG_ABSTRACT } else { 0 }, )); let mut data = T::type_data(); (*data.as_mut()).type_ = type_; let private_offset = gobject_sys::g_type_add_instance_private(type_.to_glib(), mem::size_of::>()); (*data.as_mut()).private_offset = private_offset as isize; T::type_init(&mut InitializingType::(type_, marker::PhantomData)); type_ } } pub(crate) unsafe fn add_signal( type_: glib_sys::GType, name: &str, flags: SignalFlags, arg_types: &[Type], ret_type: Type, ) { let arg_types = arg_types.iter().map(ToGlib::to_glib).collect::>(); gobject_sys::g_signal_newv( name.to_glib_none().0, type_, flags.to_glib(), ptr::null_mut(), None, ptr::null_mut(), None, ret_type.to_glib(), arg_types.len() as u32, arg_types.as_ptr() as *mut _, ); } #[repr(C)] pub struct SignalInvocationHint(gobject_sys::GSignalInvocationHint); impl SignalInvocationHint { pub fn detail(&self) -> ::Quark { from_glib(self.0.detail) } pub fn run_type(&self) -> SignalFlags { 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() } } pub(crate) unsafe fn add_signal_with_accumulator( type_: glib_sys::GType, name: &str, flags: SignalFlags, arg_types: &[Type], ret_type: Type, accumulator: F, ) where F: Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static, { let arg_types = arg_types.iter().map(ToGlib::to_glib).collect::>(); let accumulator: Box = Box::new(accumulator); unsafe extern "C" fn accumulator_trampoline< F: Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static, >( ihint: *mut gobject_sys::GSignalInvocationHint, return_accu: *mut gobject_sys::GValue, handler_return: *const gobject_sys::GValue, data: glib_sys::gpointer, ) -> glib_sys::gboolean { let accumulator: &F = &*(data as *const &F); accumulator( &SignalInvocationHint(*ihint), &mut *(return_accu as *mut Value), &*(handler_return as *const Value), ) .to_glib() } gobject_sys::g_signal_newv( name.to_glib_none().0, type_, flags.to_glib(), ptr::null_mut(), Some(accumulator_trampoline::), Box::into_raw(accumulator) as glib_sys::gpointer, None, ret_type.to_glib(), arg_types.len() as u32, arg_types.as_ptr() as *mut _, ); } pub struct SignalClassHandlerToken(*mut gobject_sys::GTypeInstance); impl fmt::Debug for SignalClassHandlerToken { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.debug_tuple("SignalClassHandlerToken") .field(&unsafe { ::Object::from_glib_borrow(self.0 as *mut gobject_sys::GObject) }) .finish() } } pub(crate) unsafe fn add_signal_with_class_handler( type_: glib_sys::GType, name: &str, flags: SignalFlags, arg_types: &[Type], ret_type: Type, class_handler: F, ) where F: Fn(&SignalClassHandlerToken, &[Value]) -> Option + Send + Sync + 'static, { let arg_types = arg_types.iter().map(ToGlib::to_glib).collect::>(); let class_handler = Closure::new(move |values| { let instance = gobject_sys::g_value_get_object(values[0].to_glib_none().0); class_handler(&SignalClassHandlerToken(instance as *mut _), values) }); gobject_sys::g_signal_newv( name.to_glib_none().0, type_, flags.to_glib(), class_handler.to_glib_none().0, None, ptr::null_mut(), None, ret_type.to_glib(), arg_types.len() as u32, arg_types.as_ptr() as *mut _, ); } pub(crate) unsafe fn add_signal_with_class_handler_and_accumulator( type_: glib_sys::GType, name: &str, flags: SignalFlags, arg_types: &[Type], ret_type: Type, class_handler: F, accumulator: G, ) where F: Fn(&SignalClassHandlerToken, &[Value]) -> Option + Send + Sync + 'static, G: Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static, { let arg_types = arg_types.iter().map(ToGlib::to_glib).collect::>(); let class_handler = Closure::new(move |values| { let instance = gobject_sys::g_value_get_object(values[0].to_glib_none().0); class_handler(&SignalClassHandlerToken(instance as *mut _), values) }); let accumulator: Box = Box::new(accumulator); unsafe extern "C" fn accumulator_trampoline< G: Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static, >( ihint: *mut gobject_sys::GSignalInvocationHint, return_accu: *mut gobject_sys::GValue, handler_return: *const gobject_sys::GValue, data: glib_sys::gpointer, ) -> glib_sys::gboolean { let accumulator: &G = &*(data as *const &G); accumulator( &SignalInvocationHint(*ihint), &mut *(return_accu as *mut Value), &*(handler_return as *const Value), ) .to_glib() } gobject_sys::g_signal_newv( name.to_glib_none().0, type_, flags.to_glib(), class_handler.to_glib_none().0, Some(accumulator_trampoline::), Box::into_raw(accumulator) as glib_sys::gpointer, None, ret_type.to_glib(), arg_types.len() as u32, arg_types.as_ptr() as *mut _, ); } pub(crate) unsafe fn signal_override_class_handler( name: &str, type_: glib_sys::GType, class_handler: F, ) where F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option + Send + Sync + 'static, { let class_handler = Closure::new(move |values| { let instance = gobject_sys::g_value_get_object(values[0].to_glib_none().0); class_handler(&SignalClassHandlerToken(instance as *mut _), values) }); let mut signal_id = 0; let found: bool = from_glib(gobject_sys::g_signal_parse_name( name.to_glib_none().0, type_, &mut signal_id, ptr::null_mut(), false.to_glib(), )); if !found { panic!("Signal '{}' not found", name); } gobject_sys::g_signal_override_class_closure(signal_id, type_, class_handler.to_glib_none().0); } pub(crate) unsafe fn signal_chain_from_overridden( instance: *mut gobject_sys::GTypeInstance, token: &SignalClassHandlerToken, values: &[Value], ) -> Option { assert_eq!(instance, token.0); let mut result = Value::uninitialized(); gobject_sys::g_signal_chain_from_overridden( values.as_ptr() as *mut Value as *mut gobject_sys::GValue, result.to_glib_none_mut().0, ); if result.type_() != Type::Unit && result.type_() != Type::Invalid { Some(result) } else { None } } glib-0.8.2/src/time_val.rs010066400017500001750000000015571354212555500136350ustar0000000000000000// Copyright 2013-2015, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use glib_sys; use std::mem; use translate::{StashMut, ToGlibPtrMut, Uninitialized}; pub use glib_sys::GTimeVal as TimeVal; pub fn get_current_time() -> TimeVal { unsafe { let mut ret = mem::uninitialized(); glib_sys::g_get_current_time(&mut ret); ret } } #[doc(hidden)] impl<'a> ToGlibPtrMut<'a, *mut glib_sys::GTimeVal> for TimeVal { type Storage = &'a mut Self; fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut glib_sys::GTimeVal, Self> { StashMut(self as *mut _, self) } } impl Uninitialized for TimeVal { unsafe fn uninitialized() -> TimeVal { mem::uninitialized() } } glib-0.8.2/src/translate.rs010066400017500001750000001734111352206043600140230ustar0000000000000000// Copyright 2015, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or //! 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 `ToGlib` translate simple types like `bool`. //! //! ```ignore //! pub fn set_accept_focus(&self, accept_focus: bool) { //! unsafe { gdk_sys::gdk_window_set_accept_focus(self.pointer, accept_focus.to_glib()) } //! } //! //! pub fn get_accept_focus(&self) -> bool { //! unsafe { from_glib(gdk_sys::gdk_window_get_accept_focus(self.pointer)) } //! } //! ``` //! //! `ToGlibPtr`, `FromGlibPtrNone`, `FromGlibPtrFull` and `FromGlibPtrBorrow` work on `gpointer`s //! and support different modes of ownership transfer. //! //! ```ignore //! fn get_title(&self) -> Option { //! unsafe { //! let title = gtk_sys::gtk_window_get_title(self.pointer); //! from_glib_none(title) //! } //! } //! ``` //! //! 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_sys::gdk_window_set_icon_name(self.pointer, name.to_glib_none().0) //! } //! } //! ``` use glib_sys; use libc::{c_char, size_t}; use std::char; use std::cmp::Ordering; use std::collections::HashMap; use std::ffi::{CStr, CString}; use std::ffi::{OsStr, OsString}; 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 usaly 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() } pub trait ToBool: Copy { fn to_bool(self) -> bool; } impl ToBool for bool { #[inline] fn to_bool(self) -> bool { self } } impl ToBool for glib_sys::gboolean { #[inline] fn to_bool(self) -> bool { self != glib_sys::GFALSE } } /// Returns `Some(val)` if the condition is true and `None` otherwise. #[inline] pub fn some_if T>(cond: B, f: F) -> Option { if cond.to_bool() { Some(f()) } else { None } } /// 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 glib_sys::GdkWindowAttr> for WindowAttr { /// type Storage = (Box, Stash<'a, *const c_char, Option>); /// /// fn to_glib_none(&'a self) -> Stash<*mut glib_sys::GdkWindowAttr, WindowAttr> { /// let title = self.title.to_glib_none(); /// /// let mut attrs = Box::new(glib_sys::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>; /// Translate a simple type. pub trait ToGlib { type GlibType; fn to_glib(&self) -> Self::GlibType; } impl ToGlib for bool { type GlibType = glib_sys::gboolean; #[inline] fn to_glib(&self) -> glib_sys::gboolean { if *self { glib_sys::GTRUE } else { glib_sys::GFALSE } } } impl ToGlib for char { type GlibType = u32; #[inline] fn to_glib(&self) -> u32 { *self as u32 } } impl ToGlib for Option { type GlibType = u32; #[inline] fn to_glib(&self) -> u32 { self.as_ref().map(|&c| c as u32).unwrap_or(0) } } impl ToGlib for Ordering { type GlibType = i32; #[inline] fn to_glib(&self) -> i32 { match *self { Ordering::Less => -1, Ordering::Equal => 0, Ordering::Greater => 1, } } } /// 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`. 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 { glib_sys::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 { glib_sys::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 { glib_sys::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 { glib_sys::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; fn to_glib_none_from_slice(t: &'a [Self]) -> (P, Self::Storage); fn to_glib_container_from_slice(t: &'a [Self]) -> (P, Self::Storage); 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 = glib_sys::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 = glib_sys::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 = glib_sys::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 = glib_sys::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 = glib_sys::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<'a, T> ToGlibContainerFromSlice<'a, *mut glib_sys::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 glib_sys::GList, Self::Storage) { let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect(); let mut list: *mut glib_sys::GList = ptr::null_mut(); unsafe { for stash in &stash_vec { list = glib_sys::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 glib_sys::GList, Self::Storage) { let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect(); let mut list: *mut glib_sys::GList = ptr::null_mut(); unsafe { for stash in &stash_vec { list = glib_sys::g_list_prepend(list, Ptr::to(stash.0)); } } (list, (None, stash_vec)) } #[inline] fn to_glib_full_from_slice(t: &[T]) -> *mut glib_sys::GList { let mut list: *mut glib_sys::GList = ptr::null_mut(); unsafe { for ptr in t.iter().rev().map(ToGlibPtr::to_glib_full) { list = glib_sys::g_list_prepend(list, Ptr::to(ptr)); } } list } } impl<'a, T> ToGlibContainerFromSlice<'a, *const glib_sys::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 glib_sys::GList, Self::Storage) { let (list, stash) = ToGlibContainerFromSlice::<*mut glib_sys::GList>::to_glib_none_from_slice(t); (list as *const glib_sys::GList, stash) } #[inline] fn to_glib_container_from_slice(_t: &'a [T]) -> (*const glib_sys::GList, Self::Storage) { unimplemented!() } #[inline] fn to_glib_full_from_slice(_t: &[T]) -> *const glib_sys::GList { unimplemented!() } } pub struct List(*mut glib_sys::GList); impl Drop for List { fn drop(&mut self) { unsafe { glib_sys::g_list_free(self.0) } } } impl<'a, T> ToGlibContainerFromSlice<'a, *mut glib_sys::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 glib_sys::GSList, Self::Storage) { let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect(); let mut list: *mut glib_sys::GSList = ptr::null_mut(); unsafe { for stash in &stash_vec { list = glib_sys::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 glib_sys::GSList, Self::Storage) { let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect(); let mut list: *mut glib_sys::GSList = ptr::null_mut(); unsafe { for stash in &stash_vec { list = glib_sys::g_slist_prepend(list, Ptr::to(stash.0)); } } (list, (None, stash_vec)) } #[inline] fn to_glib_full_from_slice(t: &[&'a T]) -> *mut glib_sys::GSList { let mut list: *mut glib_sys::GSList = ptr::null_mut(); unsafe { for ptr in t.iter().rev().map(ToGlibPtr::to_glib_full) { list = glib_sys::g_slist_prepend(list, Ptr::to(ptr)); } } list } } impl<'a, T> ToGlibContainerFromSlice<'a, *const glib_sys::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 glib_sys::GSList, Self::Storage) { let (list, stash) = ToGlibContainerFromSlice::<*mut glib_sys::GSList>::to_glib_none_from_slice(t); (list as *const glib_sys::GSList, stash) } #[inline] fn to_glib_container_from_slice(_t: &'a [&'a T]) -> (*const glib_sys::GSList, Self::Storage) { unimplemented!() } #[inline] fn to_glib_full_from_slice(_t: &[&'a T]) -> *const glib_sys::GSList { unimplemented!() } } pub struct SList(*mut glib_sys::GSList); impl Drop for SList { fn drop(&mut self) { unsafe { glib_sys::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 glib_sys::GHashTable> for HashMap { type Storage = (HashTable); #[inline] fn to_glib_none(&self) -> Stash<'a, *mut glib_sys::GHashTable, Self> { let ptr = self.to_glib_full(); Stash(ptr, HashTable(ptr)) } #[inline] fn to_glib_full(&self) -> *mut glib_sys::GHashTable { unsafe { let ptr = glib_sys::g_hash_table_new_full( Some(glib_sys::g_str_hash), Some(glib_sys::g_str_equal), Some(glib_sys::g_free), Some(glib_sys::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(); glib_sys::g_hash_table_insert(ptr, k as *mut _, v as *mut _); } ptr } } } pub struct HashTable(*mut glib_sys::GHashTable); impl Drop for HashTable { fn drop(&mut self) { unsafe { glib_sys::g_hash_table_unref(self.0) } } } impl<'a, T> ToGlibContainerFromSlice<'a, *const glib_sys::GArray> 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 glib_sys::GArray, Self::Storage) { let (list, stash) = ToGlibContainerFromSlice::<*mut glib_sys::GArray>::to_glib_none_from_slice(t); (list as *const glib_sys::GArray, stash) } #[inline] fn to_glib_container_from_slice(_t: &'a [&'a T]) -> (*const glib_sys::GArray, Self::Storage) { unimplemented!() } #[inline] fn to_glib_full_from_slice(_t: &[&'a T]) -> *const glib_sys::GArray { unimplemented!() } } pub struct Array(*mut glib_sys::GArray); impl Drop for Array { fn drop(&mut self) { unsafe { glib_sys::g_array_free(self.0, false.to_glib()); } } } impl<'a, T> ToGlibContainerFromSlice<'a, *mut glib_sys::GArray> 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 glib_sys::GArray, Self::Storage) { let stash_vec: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect(); let mut arr: *mut glib_sys::GArray = ptr::null_mut(); unsafe { for stash in &stash_vec { arr = glib_sys::g_array_append_vals(arr, Ptr::to(stash.0), 1); } } (arr, (Some(Array(arr)), stash_vec)) } #[inline] fn to_glib_container_from_slice(t: &'a [T]) -> (*mut glib_sys::GArray, Self::Storage) { let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect(); let mut arr: *mut glib_sys::GArray = ptr::null_mut(); unsafe { for stash in &stash_vec { arr = glib_sys::g_array_append_vals(arr, Ptr::to(stash.0), 1); } } (arr, (None, stash_vec)) } #[inline] fn to_glib_full_from_slice(t: &[T]) -> *mut glib_sys::GArray { let mut arr: *mut glib_sys::GArray = ptr::null_mut(); unsafe { for ptr in t.iter().map(ToGlibPtr::to_glib_full) { arr = glib_sys::g_array_append_vals(arr, Ptr::to(ptr), 1); } } arr } } /// Translate a simple type. pub trait FromGlib: Sized { fn from_glib(val: T) -> Self; } /// Translate a simple type. #[inline] pub fn from_glib>(val: G) -> T { FromGlib::from_glib(val) } impl FromGlib for bool { #[inline] fn from_glib(val: glib_sys::gboolean) -> bool { val != glib_sys::GFALSE } } impl FromGlib for char { #[inline] fn from_glib(val: u32) -> char { char::from_u32(val).expect("Valid Unicode character expected") } } impl FromGlib for Ordering { #[inline] fn from_glib(val: i32) -> Ordering { if val < 0 { Ordering::Less } else if val > 0 { Ordering::Greater } else { Ordering::Equal } } } impl FromGlib for Option { #[inline] fn from_glib(val: u32) -> Option { match val { 0 => None, _ => char::from_u32(val), } } } impl FromGlib for Option { #[inline] fn from_glib(val: i32) -> Option { if val >= 0 { Some(val as u32) } else { None } } } impl FromGlib for Option { #[inline] fn from_glib(val: i64) -> Option { if val >= 0 { Some(val as u64) } else { None } } } impl FromGlib for Option { #[inline] fn from_glib(val: i32) -> Option { FromGlib::from_glib(i64::from(val)) } } /// Translate from a pointer type without taking ownership, transfer: none. pub trait FromGlibPtrNone: Sized { unsafe fn from_glib_none(ptr: P) -> Self; } /// Translate from a pointer type taking ownership, transfer: full. pub trait FromGlibPtrFull: Sized { unsafe fn from_glib_full(ptr: P) -> Self; } /// Translate from a pointer type by borrowing. Don't increase the refcount pub trait FromGlibPtrBorrow: Sized { unsafe fn from_glib_borrow(_ptr: P) -> Self { unimplemented!(); } } /// Translate from a pointer type, transfer: none. #[inline] pub unsafe fn from_glib_none>(ptr: P) -> T { FromGlibPtrNone::from_glib_none(ptr) } /// Translate from a pointer type, transfer: full (assume ownership). #[inline] pub unsafe fn from_glib_full>(ptr: P) -> T { FromGlibPtrFull::from_glib_full(ptr) } /// Translate from a pointer type, borrowing the pointer. #[inline] pub unsafe fn from_glib_borrow>(ptr: P) -> T { 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) -> Option { if ptr.is_null() { None } else { Some(from_glib_borrow(ptr)) } } } 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()); String::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); glib_sys::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()); String::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); glib_sys::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); glib_sys::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); glib_sys::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); glib_sys::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); glib_sys::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 glib_sys::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 glib_sys::gboolean, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } unsafe fn from_glib_full_num_as_vec(_: *const glib_sys::gboolean, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } } impl FromGlibContainerAsVec for bool { unsafe fn from_glib_none_num_as_vec(ptr: *mut glib_sys::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 glib_sys::gboolean, num: usize, ) -> Vec { let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); glib_sys::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut glib_sys::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); glib_sys::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); glib_sys::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)))); } glib_sys::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 glib_sys::GSList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_num_as_vec(mut ptr: *mut glib_sys::GSList, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for _ in 0..num { 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 glib_sys::GSList, num: usize) -> Vec { let res = FromGlibContainer::from_glib_none_num(ptr, num); if !ptr.is_null() { glib_sys::g_slist_free(ptr as *mut _); } res } unsafe fn from_glib_full_num_as_vec(mut ptr: *mut glib_sys::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 { let item_ptr: ::GlibType = Ptr::from((*ptr).data); if !item_ptr.is_null() { res.push(from_glib_full(item_ptr)); } ptr = (*ptr).next; } glib_sys::g_slist_free(orig_ptr as *mut _); res } } impl FromGlibPtrArrayContainerAsVec<::GlibType, *mut glib_sys::GSList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_as_vec(ptr: *mut glib_sys::GSList) -> Vec { let num = glib_sys::g_slist_length(ptr) as usize; FromGlibContainer::from_glib_none_num(ptr, num) } unsafe fn from_glib_container_as_vec(ptr: *mut glib_sys::GSList) -> Vec { let num = glib_sys::g_slist_length(ptr) as usize; FromGlibContainer::from_glib_container_num(ptr, num) } unsafe fn from_glib_full_as_vec(ptr: *mut glib_sys::GSList) -> Vec { let num = glib_sys::g_slist_length(ptr) as usize; FromGlibContainer::from_glib_full_num(ptr, num) } } impl FromGlibContainerAsVec<::GlibType, *mut glib_sys::GList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_num_as_vec(mut ptr: *mut glib_sys::GList, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for _ in 0..num { 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 glib_sys::GList, num: usize) -> Vec { let res = FromGlibContainer::from_glib_none_num(ptr, num); if !ptr.is_null() { glib_sys::g_list_free(ptr as *mut _); } res } unsafe fn from_glib_full_num_as_vec(mut ptr: *mut glib_sys::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 { let item_ptr: ::GlibType = Ptr::from((*ptr).data); if !item_ptr.is_null() { res.push(from_glib_full(item_ptr)); } ptr = (*ptr).next; } glib_sys::g_list_free(orig_ptr as *mut _); res } } impl FromGlibPtrArrayContainerAsVec<::GlibType, *mut glib_sys::GList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_as_vec(ptr: *mut glib_sys::GList) -> Vec { let num = glib_sys::g_list_length(ptr) as usize; FromGlibContainer::from_glib_none_num(ptr, num) } unsafe fn from_glib_container_as_vec(ptr: *mut glib_sys::GList) -> Vec { let num = glib_sys::g_list_length(ptr) as usize; FromGlibContainer::from_glib_container_num(ptr, num) } unsafe fn from_glib_full_as_vec(ptr: *mut glib_sys::GList) -> Vec { let num = glib_sys::g_list_length(ptr) as usize; FromGlibContainer::from_glib_full_num(ptr, num) } } impl FromGlibContainerAsVec<::GlibType, *const glib_sys::GList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_num_as_vec(ptr: *const glib_sys::GList, num: usize) -> Vec { FromGlibContainer::from_glib_none_num(mut_override(ptr), num) } unsafe fn from_glib_container_num_as_vec(_: *const glib_sys::GList, _: usize) -> Vec { // Can't really free a *const unimplemented!() } unsafe fn from_glib_full_num_as_vec(_: *const glib_sys::GList, _: usize) -> Vec { // Can't really free a *const unimplemented!() } } impl FromGlibPtrArrayContainerAsVec<::GlibType, *const glib_sys::GList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_as_vec(ptr: *const glib_sys::GList) -> Vec { FromGlibPtrContainer::from_glib_none(mut_override(ptr)) } unsafe fn from_glib_container_as_vec(_: *const glib_sys::GList) -> Vec { // Can't really free a *const unimplemented!() } unsafe fn from_glib_full_as_vec(_: *const glib_sys::GList) -> Vec { // Can't really free a *const unimplemented!() } } impl FromGlibContainerAsVec<::GlibType, *const glib_sys::GSList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_num_as_vec(ptr: *const glib_sys::GSList, num: usize) -> Vec { FromGlibContainer::from_glib_none_num(mut_override(ptr), num) } unsafe fn from_glib_container_num_as_vec(_: *const glib_sys::GSList, _: usize) -> Vec { // Can't really free a *const unimplemented!() } unsafe fn from_glib_full_num_as_vec(_: *const glib_sys::GSList, _: usize) -> Vec { // Can't really free a *const unimplemented!() } } impl FromGlibPtrArrayContainerAsVec<::GlibType, *const glib_sys::GSList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_as_vec(ptr: *const glib_sys::GSList) -> Vec { FromGlibPtrContainer::from_glib_none(mut_override(ptr)) } unsafe fn from_glib_container_as_vec(_: *const glib_sys::GSList) -> Vec { // Can't really free a *const unimplemented!() } unsafe fn from_glib_full_as_vec(_: *const glib_sys::GSList) -> Vec { // Can't really free a *const unimplemented!() } } #[allow(clippy::implicit_hasher)] impl FromGlibContainer<*const c_char, *mut glib_sys::GHashTable> for HashMap { unsafe fn from_glib_none_num(ptr: *mut glib_sys::GHashTable, _: usize) -> Self { FromGlibPtrContainer::from_glib_none(ptr) } unsafe fn from_glib_container_num(ptr: *mut glib_sys::GHashTable, _: usize) -> Self { FromGlibPtrContainer::from_glib_full(ptr) } unsafe fn from_glib_full_num(ptr: *mut glib_sys::GHashTable, _: usize) -> Self { FromGlibPtrContainer::from_glib_full(ptr) } } #[allow(clippy::implicit_hasher)] impl FromGlibPtrContainer<*const c_char, *mut glib_sys::GHashTable> for HashMap { unsafe fn from_glib_none(ptr: *mut glib_sys::GHashTable) -> Self { unsafe extern "C" fn read_string_hash_table( key: glib_sys::gpointer, value: glib_sys::gpointer, hash_map: glib_sys::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(); glib_sys::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 glib_sys::GHashTable) -> Self { FromGlibPtrContainer::from_glib_full(ptr) } unsafe fn from_glib_full(ptr: *mut glib_sys::GHashTable) -> Self { let map = FromGlibPtrContainer::from_glib_none(ptr); glib_sys::g_hash_table_unref(ptr); map } } #[cfg(test)] mod tests { extern crate tempfile; use self::tempfile::tempdir; use std::fs; use super::*; use glib_sys; use gstring::GString; use std::collections::HashMap; #[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 glib_sys::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 { glib_sys::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 { glib_sys::g_strdupv(ptr) }; let actual: Vec = unsafe { FromGlibPtrContainer::from_glib_full(ptr_copy) }; assert_eq!(v, actual); } #[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!(::functions::path_get_basename(&dir_1), Some("abcd".into())); assert_eq!( ::functions::path_get_basename(dir_1.canonicalize().unwrap()), Some("abcd".into()) ); assert_eq!( ::functions::path_get_dirname(dir_1.canonicalize().unwrap()), Some(tmp_dir.path().into()) ); assert!(::functions::file_test( &dir_1, ::FileTest::EXISTS | ::FileTest::IS_DIR )); assert!(::functions::file_test( &dir_1.canonicalize().unwrap(), ::FileTest::EXISTS | ::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!( ::functions::path_get_basename(&dir_2), Some("øäöü".into()) ); assert_eq!( ::functions::path_get_basename(dir_2.canonicalize().unwrap()), Some("øäöü".into()) ); assert_eq!( ::functions::path_get_dirname(dir_2.canonicalize().unwrap()), Some(tmp_dir.path().into()) ); assert!(::functions::file_test( &dir_2, ::FileTest::EXISTS | ::FileTest::IS_DIR )); assert!(::functions::file_test( &dir_2.canonicalize().unwrap(), ::FileTest::EXISTS | ::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!(::functions::path_get_basename(&dir_1), Some("abcd".into())); assert_eq!( ::functions::path_get_basename(dir_1.canonicalize().unwrap()), Some("abcd".into()) ); assert_eq!( ::functions::path_get_dirname(dir_1.canonicalize().unwrap()), Some(tmp_dir) ); assert!(::functions::file_test( &dir_1, ::FileTest::EXISTS | ::FileTest::IS_DIR )); assert!(::functions::file_test( &dir_1.canonicalize().unwrap(), ::FileTest::EXISTS | ::FileTest::IS_DIR )); } } glib-0.8.2/src/types.rs010066400017500001750000000262351352206036300131720ustar0000000000000000// Copyright 2015-2016, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or //! Runtime type information. use glib_sys; use gobject_sys; use translate::{ from_glib, from_glib_none, FromGlib, FromGlibContainerAsVec, ToGlib, ToGlibContainerFromSlice, ToGlibPtr, ToGlibPtrMut, }; use value::{FromValue, FromValueOptional, SetValue, Value}; use std::fmt; use std::mem; use std::ptr; /// A GLib or GLib-based library type #[derive(Clone, Copy, PartialEq, Eq)] pub enum Type { /// An invalid `Type` used as error return value in some functions Invalid, /// The fundamental type corresponding to the unit type `()` Unit, /// The fundamental type corresponding to `i8` I8, /// The fundamental type corresponding to `u8` U8, /// The fundamental type corresponding to `bool` Bool, /// The fundamental type corresponding to `i32` I32, /// The fundamental type corresponding to `u32` U32, /// The fundamental type corresponding to C `long` ILong, /// The fundamental type corresponding to C `unsigned long` ULong, /// The fundamental type corresponding to `i64` I64, /// The fundamental type corresponding to `u64` U64, /// The fundamental type corresponding to `f32` F32, /// The fundamental type corresponding to `f64` F64, /// The fundamental type corresponding to `String` String, /// The fundamental type corresponding to a pointer Pointer, /// The fundamental type of GVariant Variant, /// The fundamental type from which all interfaces are derived BaseInterface, /// The fundamental type from which all enumeration types are derived BaseEnum, /// The fundamental type from which all flags types are derived BaseFlags, /// The fundamental type from which all boxed types are derived BaseBoxed, /// The fundamental type from which all `GParamSpec` types are derived BaseParamSpec, /// The fundamental type from which all objects are derived BaseObject, /// A non-fundamental type identified by value of type `usize` Other(usize), } impl Type { pub fn name(&self) -> String { unsafe { from_glib_none(gobject_sys::g_type_name(self.to_glib())) } } pub fn qname(&self) -> ::Quark { unsafe { from_glib(gobject_sys::g_type_qname(self.to_glib())) } } pub fn is_a(&self, other: &Type) -> bool { unsafe { from_glib(gobject_sys::g_type_is_a(self.to_glib(), other.to_glib())) } } pub fn parent(&self) -> Option { unsafe { let parent = gobject_sys::g_type_parent(self.to_glib()); if parent == gobject_sys::G_TYPE_INVALID { None } else { Some(from_glib(parent)) } } } pub fn children(&self) -> Vec { unsafe { let mut n_children = 0u32; let children = gobject_sys::g_type_children(self.to_glib(), &mut n_children); FromGlibContainerAsVec::from_glib_full_num_as_vec(children, n_children as usize) } } pub fn interfaces(&self) -> Vec { unsafe { let mut n_interfaces = 0u32; let interfaces = gobject_sys::g_type_interfaces(self.to_glib(), &mut n_interfaces); FromGlibContainerAsVec::from_glib_full_num_as_vec(interfaces, n_interfaces as usize) } } pub fn interface_prerequisites(&self) -> Vec { unsafe { let mut n_prereqs = 0u32; let prereqs = gobject_sys::g_type_interface_prerequisites(self.to_glib(), &mut n_prereqs); FromGlibContainerAsVec::from_glib_full_num_as_vec(prereqs, n_prereqs as usize) } } pub fn from_name<'a, P: Into<&'a str>>(name: P) -> Option { unsafe { let type_ = gobject_sys::g_type_from_name(name.into().to_glib_none().0); if type_ == gobject_sys::G_TYPE_INVALID { None } else { Some(from_glib(type_)) } } } } 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 { fn static_type() -> Type { unsafe { from_glib(gobject_sys::g_gtype_get_type()) } } } impl<'a> FromValueOptional<'a> for Type { unsafe fn from_value_optional(value: &'a Value) -> Option { Some(from_glib(gobject_sys::g_value_get_gtype( value.to_glib_none().0, ))) } } impl<'a> FromValue<'a> for Type { unsafe fn from_value(value: &'a Value) -> Self { from_glib(gobject_sys::g_value_get_gtype(value.to_glib_none().0)) } } impl SetValue for Type { unsafe fn set_value(value: &mut Value, this: &Self) { gobject_sys::g_value_set_gtype(value.to_glib_none_mut().0, this.to_glib()) } } 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:ident, $val:ident) => { impl StaticType for $name { fn static_type() -> Type { Type::$val } } }; } builtin!(bool, Bool); builtin!(i8, I8); builtin!(u8, U8); builtin!(i32, I32); builtin!(u32, U32); builtin!(i64, I64); builtin!(u64, U64); 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(glib_sys::g_strv_get_type()) } } } impl StaticType for Vec { fn static_type() -> Type { unsafe { from_glib(glib_sys::g_strv_get_type()) } } } #[inline] pub unsafe fn instance_of(ptr: glib_sys::gconstpointer) -> bool { from_glib(gobject_sys::g_type_check_instance_is_a( ptr as *mut _, ::static_type().to_glib(), )) } impl FromGlib for Type { #[inline] fn from_glib(val: glib_sys::GType) -> Type { use self::Type::*; match val { gobject_sys::G_TYPE_INVALID => Invalid, gobject_sys::G_TYPE_NONE => Unit, gobject_sys::G_TYPE_INTERFACE => BaseInterface, gobject_sys::G_TYPE_CHAR => I8, gobject_sys::G_TYPE_UCHAR => U8, gobject_sys::G_TYPE_BOOLEAN => Bool, gobject_sys::G_TYPE_INT => I32, gobject_sys::G_TYPE_UINT => U32, gobject_sys::G_TYPE_LONG => ILong, gobject_sys::G_TYPE_ULONG => ULong, gobject_sys::G_TYPE_INT64 => I64, gobject_sys::G_TYPE_UINT64 => U64, gobject_sys::G_TYPE_ENUM => BaseEnum, gobject_sys::G_TYPE_FLAGS => BaseFlags, gobject_sys::G_TYPE_FLOAT => F32, gobject_sys::G_TYPE_DOUBLE => F64, gobject_sys::G_TYPE_STRING => String, gobject_sys::G_TYPE_POINTER => Pointer, gobject_sys::G_TYPE_BOXED => BaseBoxed, gobject_sys::G_TYPE_PARAM => BaseParamSpec, gobject_sys::G_TYPE_OBJECT => BaseObject, gobject_sys::G_TYPE_VARIANT => Variant, x => Other(x as usize), } } } impl ToGlib for Type { type GlibType = glib_sys::GType; fn to_glib(&self) -> glib_sys::GType { use self::Type::*; match *self { Invalid => gobject_sys::G_TYPE_INVALID, Unit => gobject_sys::G_TYPE_NONE, BaseInterface => gobject_sys::G_TYPE_INTERFACE, I8 => gobject_sys::G_TYPE_CHAR, U8 => gobject_sys::G_TYPE_UCHAR, Bool => gobject_sys::G_TYPE_BOOLEAN, I32 => gobject_sys::G_TYPE_INT, U32 => gobject_sys::G_TYPE_UINT, ILong => gobject_sys::G_TYPE_LONG, ULong => gobject_sys::G_TYPE_ULONG, I64 => gobject_sys::G_TYPE_INT64, U64 => gobject_sys::G_TYPE_UINT64, BaseEnum => gobject_sys::G_TYPE_ENUM, BaseFlags => gobject_sys::G_TYPE_FLAGS, F32 => gobject_sys::G_TYPE_FLOAT, F64 => gobject_sys::G_TYPE_DOUBLE, String => gobject_sys::G_TYPE_STRING, Pointer => gobject_sys::G_TYPE_POINTER, BaseBoxed => gobject_sys::G_TYPE_BOXED, BaseParamSpec => gobject_sys::G_TYPE_PARAM, BaseObject => gobject_sys::G_TYPE_OBJECT, Variant => gobject_sys::G_TYPE_VARIANT, Other(x) => x as glib_sys::GType, } } } impl<'a> ToGlibContainerFromSlice<'a, *mut glib_sys::GType> for Type { type Storage = Option>; fn to_glib_none_from_slice(t: &'a [Type]) -> (*mut glib_sys::GType, Self::Storage) { let mut vec = t.iter().map(ToGlib::to_glib).collect::>(); (vec.as_mut_ptr(), Some(vec)) } fn to_glib_container_from_slice(t: &'a [Type]) -> (*mut glib_sys::GType, Self::Storage) { (Self::to_glib_full_from_slice(t), None) } fn to_glib_full_from_slice(t: &[Type]) -> *mut glib_sys::GType { if t.is_empty() { return ptr::null_mut(); } unsafe { let res = glib_sys::g_malloc0(mem::size_of::() * (t.len() + 1)) as *mut glib_sys::GType; for (i, v) in t.iter().enumerate() { *res.add(i) = v.to_glib(); } res } } } impl FromGlibContainerAsVec for Type { unsafe fn from_glib_none_num_as_vec(ptr: *const glib_sys::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 glib_sys::GType, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } unsafe fn from_glib_full_num_as_vec(_: *const glib_sys::GType, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } } impl FromGlibContainerAsVec for Type { unsafe fn from_glib_none_num_as_vec(ptr: *mut glib_sys::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 glib_sys::GType, num: usize) -> Vec { let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); glib_sys::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut glib_sys::GType, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num) } } glib-0.8.2/src/utils.rs010066400017500001750000000161101352206036300131550ustar0000000000000000// Copyright 2015-2016, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use error::BoolError; use glib_sys; use gstring::GString; use std; use std::ffi::{OsStr, OsString}; use std::path::{Path, PathBuf}; use std::ptr; use translate::*; use Error; /// Same as [`get_prgname()`]. /// /// [`get_prgname()`]: fn.get_prgname.html pub fn get_program_name() -> Option { get_prgname() } pub fn get_prgname() -> Option { unsafe { from_glib_none(glib_sys::g_get_prgname()) } } /// Same as [`set_prgname()`]. /// /// [`set_prgname()`]: fn.set_prgname.html pub fn set_program_name(name: Option<&str>) { set_prgname(name) } pub fn set_prgname(name: Option<&str>) { unsafe { glib_sys::g_set_prgname(name.to_glib_none().0) } } pub fn getenv>(variable_name: K) -> Option { #[cfg(not(windows))] use glib_sys::g_getenv; #[cfg(windows)] use glib_sys::g_getenv_utf8 as g_getenv; unsafe { from_glib_none(g_getenv(variable_name.as_ref().to_glib_none().0)) } } pub fn setenv, V: AsRef>( variable_name: K, value: V, overwrite: bool, ) -> Result<(), BoolError> { #[cfg(not(windows))] use glib_sys::g_setenv; #[cfg(windows)] use glib_sys::g_setenv_utf8 as g_setenv; unsafe { glib_result_from_gboolean!( g_setenv( variable_name.as_ref().to_glib_none().0, value.as_ref().to_glib_none().0, overwrite.to_glib(), ), "Failed to set environment variable" ) } } pub fn unsetenv>(variable_name: K) { #[cfg(not(windows))] use glib_sys::g_unsetenv; #[cfg(windows)] use glib_sys::g_unsetenv_utf8 as g_unsetenv; unsafe { g_unsetenv(variable_name.as_ref().to_glib_none().0) } } pub fn environ_getenv>(envp: &[OsString], variable: K) -> Option { unsafe { from_glib_none(glib_sys::g_environ_getenv( envp.to_glib_none().0, variable.as_ref().to_glib_none().0, )) } } pub fn get_user_name() -> Option { #[cfg(not(all(windows, target_arch = "x86")))] use glib_sys::g_get_user_name; #[cfg(all(windows, target_arch = "x86"))] use glib_sys::g_get_user_name_utf8 as g_get_user_name; unsafe { from_glib_none(g_get_user_name()) } } pub fn get_real_name() -> Option { #[cfg(not(all(windows, target_arch = "x86")))] use glib_sys::g_get_real_name; #[cfg(all(windows, target_arch = "x86"))] use glib_sys::g_get_real_name_utf8 as g_get_real_name; unsafe { from_glib_none(g_get_real_name()) } } pub fn get_current_dir() -> Option { #[cfg(not(windows))] use glib_sys::g_get_current_dir; #[cfg(windows)] use glib_sys::g_get_current_dir_utf8 as g_get_current_dir; unsafe { from_glib_full(g_get_current_dir()) } } pub fn filename_to_uri>( filename: P, hostname: Option<&str>, ) -> Result { #[cfg(not(windows))] use glib_sys::g_filename_to_uri; #[cfg(windows)] use glib_sys::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)) } } } pub fn filename_from_uri(uri: &str) -> Result<(std::path::PathBuf, Option), Error> { #[cfg(not(windows))] use glib_sys::g_filename_from_uri; #[cfg(windows)] use glib_sys::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)) } } } pub fn find_program_in_path>(program: P) -> Option { #[cfg(not(all(windows, target_arch = "x86")))] use glib_sys::g_find_program_in_path; #[cfg(all(windows, target_arch = "x86"))] use glib_sys::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)) } } pub fn get_home_dir() -> Option { #[cfg(not(all(windows, target_arch = "x86")))] use glib_sys::g_get_home_dir; #[cfg(all(windows, target_arch = "x86"))] use glib_sys::g_get_home_dir_utf8 as g_get_home_dir; unsafe { from_glib_none(g_get_home_dir()) } } pub fn get_tmp_dir() -> Option { #[cfg(not(all(windows, target_arch = "x86")))] use glib_sys::g_get_tmp_dir; #[cfg(all(windows, target_arch = "x86"))] use glib_sys::g_get_tmp_dir_utf8 as g_get_tmp_dir; unsafe { from_glib_none(g_get_tmp_dir()) } } pub fn mkstemp>(tmpl: P) -> i32 { #[cfg(not(windows))] use glib_sys::g_mkstemp; #[cfg(windows)] use glib_sys::g_mkstemp_utf8 as g_mkstemp; unsafe { g_mkstemp(tmpl.as_ref().to_glib_none().0) } } #[cfg(test)] mod tests { use std::env; use std::sync::Mutex; //Mutex to prevent run environment tests parallel lazy_static! { static ref LOCK: Mutex<()> = 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!(::getenv(VAR_NAME), Some(val.into())); let environ = ::get_environ(); assert_eq!(::environ_getenv(&environ, VAR_NAME), Some(val.into())); } fn check_setenv(val: &str) { let _data = LOCK.lock().unwrap(); ::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 gstring::GString; use std::path::PathBuf; let uri: GString = "file:///foo/bar.txt".into(); if let Ok((filename, hostname)) = ::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)) = ::filename_from_uri(&uri) { assert_eq!(filename, PathBuf::from(r"/foo/bar.txt")); assert_eq!(hostname, Some(GString::from("host"))); } else { unreachable!(); } } } glib-0.8.2/src/value.rs010066400017500001750000000761571354212555500131610ustar0000000000000000// Copyright 2013-2016, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or //! `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. //! //! [`TypedValue`](struct.TypedValue.html) has a statically known type and //! dereferences to `Value` so it can be used everywhere `Value` references are //! accepted. //! //! [`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::{TypedValue, Value}; //! //! // Value and TypedValue 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 = Value::from(none.clone()); //! let typed_str_none = TypedValue::from(none); //! //! // `is` tests the type of the value. //! assert!(num.is::()); //! assert!(hello.is::()); //! //! // `get` tries to get a value of specific type and returns None //! // if the type doesn't match or the value is None. //! assert_eq!(num.get(), Some(10)); //! assert_eq!(num.get::(), None); //! assert_eq!(hello.get(), Some(String::from("Hello!"))); //! assert_eq!(hello.get::(), Some(String::from("Hello!"))); //! assert_eq!(str_none.get::(), None); //! //! // `typed` tries to convert a `Value` to `TypedValue`. //! let mut typed_num = num.downcast::().unwrap(); //! let mut typed_hello = hello.downcast::().unwrap(); //! //! // `str_none` is not an `i32` //! assert!(str_none.downcast::().is_err()); //! //! // `get` //! assert!(typed_hello.get().unwrap() == "Hello!"); //! assert!(typed_str_none.get() == None); //! //! // Numeric types can't have value `None`, `get` always returns `Some`. //! // Such types have `get_some`, which avoids unnecessary `unwrap`ping. //! assert_eq!(typed_num.get().unwrap(), 10); //! assert_eq!(typed_num.get_some(), 10); //! //! // `set_none` sets the value to `None` if the type supports it. //! typed_hello.set_none(); //! assert!(typed_hello.get().is_none()); //! //! // `set` takes an optional reference for types that support `None`. //! typed_hello.set(Some("Hello again!")); //! assert!(typed_hello.get().unwrap() == "Hello again!"); //! //! // `set_some` is the only setter for types that don't support `None`. //! typed_num.set_some(&20); //! assert_eq!(typed_num.get_some(), 20); //! ``` use libc::{c_char, c_void}; use std::borrow::Borrow; use std::ffi::CStr; use std::fmt; use std::marker::PhantomData; use std::mem; use std::ops::Deref; use std::ptr; use glib_sys; use gobject_sys; use gstring::GString; use translate::*; use types::{StaticType, Type}; /// 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(C)] pub struct Value(pub(crate) gobject_sys::GValue, PhantomData<*const c_void>); impl Value { /// Creates a new `Value` that is initialized with `type_` pub fn from_type(type_: Type) -> Self { unsafe { assert_eq!( gobject_sys::g_type_check_is_value_type(type_.to_glib()), glib_sys::GTRUE ); let mut value = Value::uninitialized(); gobject_sys::g_value_init(value.to_glib_none_mut().0, type_.to_glib()); value } } /// Tries to downcast to a `TypedValue`. /// /// Returns `Ok(TypedValue)` if the value carries a type corresponding /// to `T` and `Err(self)` otherwise. pub fn downcast<'a, T: FromValueOptional<'a> + SetValue>(self) -> Result, Self> { unsafe { let ok = from_glib(gobject_sys::g_type_check_value_holds( mut_override(self.to_glib_none().0), T::static_type().to_glib(), )); if ok { Ok(TypedValue(self, PhantomData)) } else { Err(self) } } } /// Tries to downcast to a `&TypedValue`. /// /// Returns `Some(&TypedValue)` if the value carries a type corresponding /// to `T` and `None` otherwise. pub fn downcast_ref<'a, T: FromValueOptional<'a> + SetValue>(&self) -> Option<&TypedValue> { unsafe { let ok = from_glib(gobject_sys::g_type_check_value_holds( mut_override(self.to_glib_none().0), T::static_type().to_glib(), )); if ok { // This transmute is safe because Value and TypedValue have the same // representation: the only difference is the zero-sized phantom data Some(&*(self as *const Value as *const TypedValue)) } else { None } } } /// Tries to get a value of type `T`. /// /// Returns `Some` if the type is correct and the value is not `None`. /// /// This function doesn't distinguish between type mismatches and correctly /// typed `None` values. Use `downcast` or `is` for that. pub fn get<'a, T: FromValueOptional<'a>>(&'a self) -> Option { unsafe { let ok = from_glib(gobject_sys::g_type_check_value_holds( mut_override(self.to_glib_none().0), T::static_type().to_glib(), )); if ok { T::from_value_optional(self) } else { None } } } /// Returns `true` if the type of the value corresponds to `T` /// or is a sub-type of `T`. #[inline] pub fn is<'a, T: FromValueOptional<'a> + SetValue>(&self) -> bool { self.type_().is_a(&T::static_type()) } /// Returns the type of the value. pub fn type_(&self) -> Type { from_glib(self.0.g_type) } /// Returns whether `Value`s of type `src` can be transformed to type `dst`. pub fn type_transformable(src: Type, dst: Type) -> bool { unsafe { from_glib(gobject_sys::g_value_type_transformable( src.to_glib(), dst.to_glib(), )) } } #[doc(hidden)] pub fn into_raw(mut self) -> gobject_sys::GValue { unsafe { let ret = mem::replace(&mut self.0, mem::uninitialized()); mem::forget(self); ret } } pub fn try_into_send_value<'a, T: Send + FromValueOptional<'a> + SetValue>( self, ) -> Result { self.downcast::().map(TypedValue::into_send_value) } } impl Clone for Value { fn clone(&self) -> Self { unsafe { let mut ret = Value::from_type(from_glib(self.0.g_type)); gobject_sys::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_() != Type::Invalid { unsafe { gobject_sys::g_value_unset(self.to_glib_none_mut().0) } } } } impl fmt::Debug for Value { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { unsafe { let s: GString = from_glib_full(gobject_sys::g_strdup_value_contents(self.to_glib_none().0)); f.debug_tuple("Value").field(&s).finish() } } } impl<'a, T: ?Sized + SetValueOptional> From> for Value { #[inline] fn from(value: Option<&'a T>) -> Self { value.to_value() } } impl<'a, T: ?Sized + SetValue> From<&'a T> for Value { #[inline] fn from(value: &'a T) -> Self { value.to_value() } } impl From> for Value { fn from(value: TypedValue) -> Self { value.0 } } impl From for Value { fn from(value: SendValue) -> Self { value.0 } } impl Uninitialized for Value { unsafe fn uninitialized() -> Value { Value(mem::zeroed(), PhantomData) } } #[doc(hidden)] impl<'a> ToGlibPtr<'a, *const gobject_sys::GValue> for Value { type Storage = &'a Value; fn to_glib_none(&'a self) -> Stash<'a, *const gobject_sys::GValue, Self> { Stash(&self.0, self) } } #[doc(hidden)] impl<'a> ToGlibPtrMut<'a, *mut gobject_sys::GValue> for Value { type Storage = &'a mut Value; fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut gobject_sys::GValue, Self> { StashMut(&mut self.0, self) } } #[doc(hidden)] impl<'a> ToGlibPtr<'a, *mut gobject_sys::GValue> for &'a [&'a dyn ToValue] { type Storage = ValueArray; fn to_glib_none(&'a self) -> Stash<'a, *mut gobject_sys::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_sys::GValue> for &'a Value { type Storage = &'a [&'a Value]; fn to_glib_none_from_slice(t: &'a [&'a Value]) -> (*mut gobject_sys::GValue, &'a [&'a Value]) { (t.as_ptr() as *mut gobject_sys::GValue, t) } fn to_glib_container_from_slice( t: &'a [&'a Value], ) -> (*mut gobject_sys::GValue, &'a [&'a Value]) { if t.is_empty() { return (ptr::null_mut(), t); } unsafe { let res = glib_sys::g_malloc(mem::size_of::() * t.len()) as *mut gobject_sys::GValue; ptr::copy_nonoverlapping(t.as_ptr() as *const gobject_sys::GValue, res, t.len()); (res, t) } } fn to_glib_full_from_slice(t: &[&'a Value]) -> *mut gobject_sys::GValue { if t.is_empty() { return ptr::null_mut(); } unsafe { let res = glib_sys::g_malloc(mem::size_of::() * t.len()) as *mut gobject_sys::GValue; for (i, v) in t.iter().enumerate() { gobject_sys::g_value_init(res.add(i), v.type_().to_glib()); gobject_sys::g_value_copy(v.to_glib_none().0, res.add(i)); } res } } } #[doc(hidden)] impl<'a> ToGlibContainerFromSlice<'a, *const gobject_sys::GValue> for &'a Value { type Storage = &'a [&'a Value]; fn to_glib_none_from_slice( t: &'a [&'a Value], ) -> (*const gobject_sys::GValue, &'a [&'a Value]) { let (ptr, storage) = ToGlibContainerFromSlice::<'a, *mut gobject_sys::GValue>::to_glib_none_from_slice(t); (ptr as *const _, storage) } fn to_glib_container_from_slice( _: &'a [&'a Value], ) -> (*const gobject_sys::GValue, &'a [&'a Value]) { unimplemented!() } fn to_glib_full_from_slice(_: &[&'a Value]) -> *const gobject_sys::GValue { unimplemented!() } } macro_rules! from_glib { ($name:ident, $wrap:expr) => { impl FromGlibPtrNone<*const gobject_sys::GValue> for $name { unsafe fn from_glib_none(ptr: *const gobject_sys::GValue) -> Self { let mut ret = Value::from_type(from_glib((*ptr).g_type)); gobject_sys::g_value_copy(ptr, ret.to_glib_none_mut().0); $wrap(ret) } } impl FromGlibPtrNone<*mut gobject_sys::GValue> for $name { unsafe fn from_glib_none(ptr: *mut gobject_sys::GValue) -> Self { from_glib_none(ptr as *const _) } } impl FromGlibPtrFull<*mut gobject_sys::GValue> for $name { unsafe fn from_glib_full(ptr: *mut gobject_sys::GValue) -> Self { let mut ret = Value::uninitialized(); ptr::swap(&mut ret.0, ptr); glib_sys::g_free(ptr as *mut c_void); $wrap(ret) } } impl FromGlibContainerAsVec<*mut gobject_sys::GValue, *mut *mut gobject_sys::GValue> for $name { unsafe fn from_glib_none_num_as_vec( ptr: *mut *mut gobject_sys::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_sys::GValue, num: usize, ) -> Vec { let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); glib_sys::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec( ptr: *mut *mut gobject_sys::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)))); } glib_sys::g_free(ptr as *mut _); res } } impl FromGlibPtrArrayContainerAsVec<*mut gobject_sys::GValue, *mut *mut gobject_sys::GValue> for $name { unsafe fn from_glib_none_as_vec(ptr: *mut *mut gobject_sys::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_sys::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_sys::GValue) -> Vec { FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr)) } } impl FromGlibContainerAsVec<*mut gobject_sys::GValue, *const *mut gobject_sys::GValue> for $name { unsafe fn from_glib_none_num_as_vec( ptr: *const *mut gobject_sys::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_sys::GValue, _: usize, ) -> Vec { // Can't free a *const unimplemented!() } unsafe fn from_glib_full_num_as_vec( _: *const *mut gobject_sys::GValue, _: usize, ) -> Vec { // Can't free a *const unimplemented!() } } impl FromGlibPtrArrayContainerAsVec< *mut gobject_sys::GValue, *const *mut gobject_sys::GValue, > for $name { unsafe fn from_glib_none_as_vec(ptr: *const *mut gobject_sys::GValue) -> Vec { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr as *mut *mut _) } unsafe fn from_glib_container_as_vec(_: *const *mut gobject_sys::GValue) -> Vec { // Can't free a *const unimplemented!() } unsafe fn from_glib_full_as_vec(_: *const *mut gobject_sys::GValue) -> Vec { // Can't free a *const unimplemented!() } } }; } from_glib!(Value, |v| v); 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_sys::G_TYPE_INVALID { gobject_sys::g_value_unset(value); } } } } } /// A statically typed [`Value`](struct.Value.html). /// /// It dereferences to `Value` and can be used everywhere `Value` references are /// accepted. /// /// See the [module documentation](index.html) for more details. #[derive(Clone)] #[repr(C)] pub struct TypedValue(Value, PhantomData<*const T>); impl<'a, T: FromValueOptional<'a> + SetValue> TypedValue { /// Returns the value. /// /// Types that don't support a `None` value always return `Some`. See /// `get_some`. pub fn get(&'a self) -> Option { unsafe { T::from_value_optional(self) } } /// Returns the value. /// /// This method is only available for types that don't support a `None` /// value. pub fn get_some(&'a self) -> T where T: FromValue<'a>, { unsafe { T::from_value(self) } } /// Sets the value. /// /// This method is only available for types that support a `None` value. pub fn set(&mut self, value: Option<&U>) where T: Borrow, { unsafe { SetValueOptional::set_value_optional(&mut self.0, value) } } /// Sets the value to `None`. /// /// This method is only available for types that support a `None` value. pub fn set_none(&mut self) where T: SetValueOptional, { unsafe { T::set_value_optional(&mut self.0, None) } } /// Sets the value. pub fn set_some(&mut self, value: &U) where T: Borrow, { unsafe { SetValue::set_value(&mut self.0, value) } } } impl fmt::Debug for TypedValue { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.debug_tuple("TypedValue").field(&self.0).finish() } } impl<'a, T: FromValueOptional<'a> + SetValue + Send> TypedValue { pub fn into_send_value(self) -> SendValue { SendValue(self.0) } } impl Deref for TypedValue { type Target = Value; fn deref(&self) -> &Value { &self.0 } } impl<'a, T: FromValueOptional<'a> + SetValueOptional> From> for TypedValue { fn from(value: Option<&'a T>) -> Self { TypedValue(Value::from(value), PhantomData) } } impl<'a, T: FromValueOptional<'a> + SetValue> From<&'a T> for TypedValue { fn from(value: &'a T) -> Self { TypedValue(Value::from(value), PhantomData) } } impl<'a> From> for TypedValue { fn from(value: Option<&'a str>) -> Self { TypedValue(Value::from(value), PhantomData) } } impl<'a> From<&'a str> for TypedValue { fn from(value: &'a str) -> Self { TypedValue(Value::from(value), PhantomData) } } impl<'a> From> for TypedValue { fn from(value: TypedValue<&str>) -> Self { TypedValue(value.0, PhantomData) } } impl<'a> From> for TypedValue<&'a str> { fn from(value: TypedValue) -> Self { TypedValue(value.0, PhantomData) } } #[doc(hidden)] impl<'a, T: 'a> ToGlibPtrMut<'a, *mut gobject_sys::GValue> for TypedValue { type Storage = &'a mut TypedValue; fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut gobject_sys::GValue, Self> { StashMut(&mut (self.0).0, self) } } /// Converts to `Value`. pub trait ToValue { /// Returns a `Value` clone of `self`. 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 to_value_type(&self) -> Type; } impl ToValue for Option { fn to_value(&self) -> Value { unsafe { let mut ret = Value::from_type(T::static_type()); T::set_value_optional(&mut ret, self.as_ref()); ret } } #[inline] fn to_value_type(&self) -> Type { T::static_type() } } impl ToValue for T { fn to_value(&self) -> Value { unsafe { let mut ret = Value::from_type(T::static_type()); T::set_value(&mut ret, self); ret } } #[inline] fn to_value_type(&self) -> Type { T::static_type() } } impl ToValue for Value { fn to_value(&self) -> Value { self.clone() } fn to_value_type(&self) -> Type { self.type_() } } /// 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(C)] pub struct SendValue(Value); unsafe impl Send for SendValue {} impl SendValue { /// Tries to downcast to a `TypedValue`. /// /// Returns `Ok(TypedValue)` if the value carries a type corresponding /// to `T` and `Err(self)` otherwise. pub fn downcast<'a, T: FromValueOptional<'a> + SetValue + Send>( self, ) -> Result, Self> { self.0.downcast().map_err(SendValue) } /// Tries to downcast to a `&TypedValue`. /// /// Returns `Some(&TypedValue)` if the value carries a type corresponding /// to `T` and `None` otherwise. pub fn downcast_ref<'a, T: FromValueOptional<'a> + SetValue>(&self) -> Option<&TypedValue> { unsafe { let ok = from_glib(gobject_sys::g_type_check_value_holds( mut_override(self.to_glib_none().0), T::static_type().to_glib(), )); if ok { // This transmute is safe because SendValue and TypedValue have the same // representation: the only difference is the zero-sized phantom data Some(&*(self as *const SendValue as *const TypedValue)) } else { None } } } #[doc(hidden)] pub fn into_raw(self) -> gobject_sys::GValue { self.0.into_raw() } } impl fmt::Debug for SendValue { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.debug_tuple("SendValue").field(&self.0).finish() } } impl Deref for SendValue { type Target = Value; fn deref(&self) -> &Value { &self.0 } } impl<'a, T: ?Sized + SetValueOptional + Send> From> for SendValue { #[inline] fn from(value: Option<&'a T>) -> Self { SendValue(value.to_value()) } } impl<'a, T: ?Sized + SetValue + Send> From<&'a T> for SendValue { #[inline] fn from(value: &'a T) -> Self { SendValue(value.to_value()) } } impl From> for SendValue { fn from(value: TypedValue) -> Self { SendValue(value.0) } } from_glib!(SendValue, SendValue); #[doc(hidden)] impl<'a> ToGlibPtrMut<'a, *mut gobject_sys::GValue> for SendValue { type Storage = &'a mut SendValue; fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut gobject_sys::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 Option { fn to_send_value(&self) -> SendValue { SendValue(self.to_value()) } } impl ToSendValue for T { fn to_send_value(&self) -> SendValue { SendValue(self.to_value()) } } impl ToSendValue for SendValue { fn to_send_value(&self) -> SendValue { self.clone() } } impl ToValue for SendValue { fn to_value(&self) -> Value { self.0.clone() } fn to_value_type(&self) -> Type { self.type_() } } /// Extracts a value. /// /// Types that don't support a `None` value always return `Some`. pub trait FromValueOptional<'a>: StaticType + Sized { unsafe fn from_value_optional(&'a Value) -> Option; } /// Extracts a value. /// /// Only implemented for types that don't support a `None` value. pub trait FromValue<'a>: FromValueOptional<'a> { unsafe fn from_value(&'a Value) -> Self; } /// Sets a value. /// /// Only implemented for types that support a `None` value. pub trait SetValueOptional: SetValue { unsafe fn set_value_optional(&mut Value, Option<&Self>); } /// Sets a value. pub trait SetValue: StaticType { unsafe fn set_value(&mut Value, &Self); } impl<'a> FromValueOptional<'a> for String { unsafe fn from_value_optional(value: &'a Value) -> Option { from_glib_none(gobject_sys::g_value_get_string(value.to_glib_none().0)) } } impl<'a> FromValueOptional<'a> for &'a str { unsafe fn from_value_optional(value: &'a Value) -> Option { let cstr = gobject_sys::g_value_get_string(value.to_glib_none().0); if cstr.is_null() { None } else { CStr::from_ptr(cstr).to_str().ok() } } } impl SetValue for str { unsafe fn set_value(value: &mut Value, this: &Self) { gobject_sys::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full()) } } impl SetValueOptional for str { unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) { gobject_sys::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full()) } } impl<'a> FromValueOptional<'a> for Vec { unsafe fn from_value_optional(value: &'a Value) -> Option { Some( as FromValue>::from_value(value)) } } impl<'a> FromValue<'a> for Vec { unsafe fn from_value(value: &'a Value) -> Self { let ptr = gobject_sys::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char; FromGlibPtrContainer::from_glib_none(ptr) } } impl<'a> FromValueOptional<'a> for Vec { unsafe fn from_value_optional(value: &'a Value) -> Option { Some( as FromValue>::from_value(value)) } } impl<'a> FromValue<'a> for Vec { unsafe fn from_value(value: &'a Value) -> Self { let ptr = gobject_sys::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char; FromGlibPtrContainer::from_glib_none(ptr) } } impl<'a> SetValue for [&'a str] { unsafe fn set_value(value: &mut Value, this: &Self) { let ptr: *mut *mut c_char = this.to_glib_full(); gobject_sys::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void) } } impl<'a> SetValueOptional for [&'a str] { unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) { let ptr: *mut *mut c_char = this.to_glib_full(); gobject_sys::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void) } } impl SetValue for Vec { unsafe fn set_value(value: &mut Value, this: &Self) { let ptr: *mut *mut c_char = this.to_glib_full(); gobject_sys::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void) } } impl SetValueOptional for Vec { #[allow(clippy::redundant_closure)] unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) { let ptr: *mut *mut c_char = this.map(|v| v.to_glib_full()).unwrap_or(ptr::null_mut()); gobject_sys::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void) } } impl<'a, T: ?Sized + SetValue> SetValue for &'a T { unsafe fn set_value(value: &mut Value, this: &Self) { SetValue::set_value(value, *this) } } impl<'a, T: ?Sized + SetValueOptional> SetValueOptional for &'a T { unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) { SetValueOptional::set_value_optional(value, this.cloned()) } } impl SetValue for String { unsafe fn set_value(value: &mut Value, this: &Self) { gobject_sys::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full()) } } impl SetValueOptional for String { unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) { gobject_sys::g_value_take_string(value.to_glib_none_mut().0, this.to_glib_full()) } } impl<'a> FromValueOptional<'a> for bool { unsafe fn from_value_optional(value: &'a Value) -> Option { Some(from_glib(gobject_sys::g_value_get_boolean( value.to_glib_none().0, ))) } } impl<'a> FromValue<'a> for bool { unsafe fn from_value(value: &'a Value) -> Self { from_glib(gobject_sys::g_value_get_boolean(value.to_glib_none().0)) } } impl SetValue for bool { unsafe fn set_value(value: &mut Value, this: &Self) { gobject_sys::g_value_set_boolean(value.to_glib_none_mut().0, this.to_glib()) } } macro_rules! numeric { ($name:ident, $get:ident, $set:ident) => { impl<'a> FromValueOptional<'a> for $name { unsafe fn from_value_optional(value: &'a Value) -> Option { Some(gobject_sys::$get(value.to_glib_none().0)) } } impl<'a> FromValue<'a> for $name { unsafe fn from_value(value: &'a Value) -> Self { gobject_sys::$get(value.to_glib_none().0) } } impl SetValue for $name { unsafe fn set_value(value: &mut Value, this: &Self) { gobject_sys::$set(value.to_glib_none_mut().0, *this) } } }; } numeric!(i8, g_value_get_schar, g_value_set_schar); numeric!(u8, g_value_get_uchar, g_value_set_uchar); numeric!(i32, g_value_get_int, g_value_set_int); numeric!(u32, g_value_get_uint, g_value_set_uint); numeric!(i64, g_value_get_int64, g_value_set_int64); numeric!(u64, g_value_get_uint64, g_value_set_uint64); numeric!(f32, g_value_get_float, g_value_set_float); numeric!(f64, g_value_get_double, g_value_set_double); #[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::>(), Some(vec![GString::from("123"), GString::from("456")]) ); let v = vec![String::from("123"), String::from("456")].to_value(); assert_eq!( v.get::>(), Some(vec![GString::from("123"), GString::from("456")]) ); } } glib-0.8.2/src/value_array.rs010066400017500001750000000067531352206043600143440ustar0000000000000000// Copyright 2018, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use glib_sys; use gobject_sys; use std::cmp::Ordering; use std::ops; use std::slice; use translate::*; use Value; glib_wrapper! { #[derive(Debug)] pub struct ValueArray(Boxed); match fn { copy => |ptr| gobject_sys::g_value_array_copy(mut_override(ptr)), free => |ptr| gobject_sys::g_value_array_free(ptr), get_type => || gobject_sys::g_value_array_get_type(), } } impl ValueArray { pub fn new(n_prealloced: u32) -> ValueArray { unsafe { from_glib_full(gobject_sys::g_value_array_new(n_prealloced)) } } pub fn append(&mut self, value: &Value) { let value = value.to_glib_none(); unsafe { gobject_sys::g_value_array_append(self.to_glib_none_mut().0, value.0); } } pub fn get_nth(&self, index_: u32) -> Option { unsafe { from_glib_none(gobject_sys::g_value_array_get_nth( mut_override(self.to_glib_none().0), index_, )) } } pub fn insert(&mut self, index_: u32, value: &Value) { let value = value.to_glib_none(); unsafe { gobject_sys::g_value_array_insert(self.to_glib_none_mut().0, index_, value.0); } } pub fn prepend(&mut self, value: &Value) { let value = value.to_glib_none(); unsafe { gobject_sys::g_value_array_prepend(self.to_glib_none_mut().0, value.0); } } pub fn remove(&mut self, index_: u32) { unsafe { gobject_sys::g_value_array_remove(self.to_glib_none_mut().0, index_); } } pub fn sort_with_data Ordering>(&mut self, compare_func: F) { unsafe extern "C" fn compare_func_trampoline( a: glib_sys::gconstpointer, b: glib_sys::gconstpointer, func: glib_sys::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 glib_sys::gpointer; gobject_sys::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.8.2/src/variant.rs010066400017500001750000000273731352206036300134760ustar0000000000000000// Copyright 2013-2016, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or //! `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` and `&str`/`String`. //! //! # Examples //! //! ``` //! use glib::prelude::*; // or `use gtk::prelude::*;` //! use glib::Variant; //! //! // 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); //! //! // `Variant` implements `From` //! let hello = Variant::from("Hello!"); //! //! // `get_str` tries to borrow a string slice. //! assert_eq!(hello.get_str(), Some("Hello!")); //! assert_eq!(num.get_str(), None); //! ``` use glib_sys; use gobject_sys; use gstring::GString; use std::borrow::Cow; use std::cmp::{Eq, Ordering, PartialEq, PartialOrd}; use std::fmt; use std::hash::{Hash, Hasher}; use std::slice; use std::str; use translate::*; use value; use StaticType; use Type; use Value; use VariantTy; glib_wrapper! { /// A generic immutable value capable of carrying various types. /// /// See the [module documentation](index.html) for more details. pub struct Variant(Shared); match fn { ref => |ptr| glib_sys::g_variant_ref_sink(ptr), unref => |ptr| glib_sys::g_variant_unref(ptr), } } impl StaticType for Variant { fn static_type() -> Type { Type::Variant } } #[doc(hidden)] impl<'a> value::FromValueOptional<'a> for Variant { unsafe fn from_value_optional(value: &Value) -> Option { from_glib_full(gobject_sys::g_value_dup_variant( ToGlibPtr::to_glib_none(value).0, )) } } #[doc(hidden)] impl value::SetValue for Variant { unsafe fn set_value(value: &mut Value, this: &Self) { gobject_sys::g_value_set_variant( ToGlibPtrMut::to_glib_none_mut(value).0, ToGlibPtr::<*mut glib_sys::GVariant>::to_glib_none(this).0, ) } } #[doc(hidden)] impl value::SetValueOptional for Variant { unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) { gobject_sys::g_value_set_variant( ToGlibPtrMut::to_glib_none_mut(value).0, ToGlibPtr::<*mut glib_sys::GVariant>::to_glib_none(&this).0, ) } } impl Variant { /// Returns the type of the value. pub fn type_(&self) -> &VariantTy { unsafe { VariantTy::from_ptr(glib_sys::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 `&str`. /// /// Returns `Some` if the variant has a string type (`s`, `o` or `g` type /// strings). pub fn get_str(&self) -> Option<&str> { unsafe { match self.type_().to_str() { "s" | "o" | "g" => { let mut len = 0; let ptr = glib_sys::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, } } } } 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(glib_sys::g_variant_print( self.to_glib_none().0, false.to_glib(), )) }; f.write_str(&serialized) } } impl PartialEq for Variant { fn eq(&self, other: &Self) -> bool { unsafe { from_glib(glib_sys::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 glib_sys::g_variant_classify(self.to_glib_none().0) != glib_sys::g_variant_classify(other.to_glib_none().0) { return None; } if glib_sys::g_variant_is_container(self.to_glib_none().0) != glib_sys::GFALSE { return None; } let res = glib_sys::g_variant_compare( self.to_glib_none().0 as *const _, other.to_glib_none().0 as *const _, ); if res < 0 { Some(Ordering::Less) } else if res > 0 { Some(Ordering::Equal) } else { Some(Ordering::Greater) } } } } impl Hash for Variant { fn hash(&self, state: &mut H) { unsafe { state.write_u32(glib_sys::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<'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(glib_sys::$new_fn(*self)) } } } impl FromVariant for $name { fn from_variant(variant: &Variant) -> Option { unsafe { if variant.is::() { Some(glib_sys::$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(glib_sys::g_variant_new_boolean(self.to_glib())) } } } impl FromVariant for bool { fn from_variant(variant: &Variant) -> Option { unsafe { if variant.is::() { Some(from_glib(glib_sys::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.get_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(glib_sys::g_variant_new_take_string(self.to_glib_full())) } } } impl From for Variant { fn from(value: T) -> Variant { value.to_variant() } } #[cfg(test)] mod tests { use super::*; use std::collections::HashSet; macro_rules! unsigned { ($name:ident, $ty:ident) => { #[test] fn $name() { let mut n = $ty::max_value(); while n > 0 { let v = Variant::from(n); 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 = Variant::from(n); assert_eq!(v.get(), Some(n)); let v = Variant::from(-n); 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 = Variant::from(s); assert_eq!(v.get_str(), Some(s)); } #[test] fn test_string() { let s = String::from("this is a test"); let v = Variant::from(s.clone()); assert_eq!(v.get(), Some(s.clone())); } #[test] fn test_eq() { let v1 = Variant::from("this is a test"); let v2 = Variant::from("this is a test"); let v3 = Variant::from("test"); assert_eq!(v1, v2); assert!(v1 != v3); } #[test] fn test_hash() { let v1 = Variant::from("this is a test"); let v2 = Variant::from("this is a test"); let v3 = Variant::from("test"); let mut set = HashSet::new(); set.insert(v1); assert!(set.contains(&v2)); assert!(!set.contains(&v3)); } } glib-0.8.2/src/variant_type.rs010066400017500001750000000301701354212555500145330ustar0000000000000000// Copyright 2013-2016, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or use glib_sys; use gobject_sys; 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; use translate::*; use types::StaticType; use types::Type; use value::{FromValueOptional, SetValue, SetValueOptional, Value}; /// 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`). pub struct VariantType { // GVariantType* essentially is a char*, that always is valid UTF-8 but // isn't NUL-terminated. ptr: *mut glib_sys::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 { glib_sys::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: glib_sys::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> Into> for VariantType { fn into(self) -> Cow<'a, VariantTy> { Cow::Owned(self) } } #[doc(hidden)] impl<'a> ToGlibPtrMut<'a, *mut glib_sys::GVariantType> for VariantType { type Storage = &'a mut Self; fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut glib_sys::GVariantType, Self> { StashMut(self.ptr, self) } } #[doc(hidden)] impl FromGlibPtrNone<*const glib_sys::GVariantType> for VariantType { unsafe fn from_glib_none(ptr: *const glib_sys::GVariantType) -> VariantType { VariantTy::from_ptr(ptr).to_owned() } } #[doc(hidden)] impl FromGlibPtrFull<*const glib_sys::GVariantType> for VariantType { unsafe fn from_glib_full(ptr: *const glib_sys::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 { /// 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, ()> { let ptr = type_string.as_ptr(); let limit = ptr as usize + type_string.len(); let mut end = 0_usize; unsafe { let ok = from_glib(glib_sys::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(()) } } } /// Converts a type string into `&VariantTy` without any checks. 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 glib_sys::GVariantType) -> &'a VariantTy { let len = glib_sys::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 glib_sys::GVariantType { self.inner.as_ptr() as *const _ } /// Converts to a string slice. pub fn to_str(&self) -> &str { &self.inner } } unsafe impl Sync for VariantTy {} #[doc(hidden)] impl<'a> ToGlibPtr<'a, *const glib_sys::GVariantType> for VariantTy { type Storage = &'a Self; fn to_glib_none(&'a self) -> Stash<'a, *const glib_sys::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> Into> for &'a VariantTy { fn into(self) -> Cow<'a, VariantTy> { Cow::Borrowed(self) } } impl ToOwned for VariantTy { type Owned = VariantType; fn to_owned(&self) -> VariantType { unsafe { VariantType { ptr: glib_sys::g_variant_type_copy(self.as_ptr()), len: self.inner.len(), } } } } impl StaticType for VariantTy { fn static_type() -> Type { unsafe { from_glib(glib_sys::g_variant_type_get_gtype()) } } } impl SetValue for VariantTy { unsafe fn set_value(value: &mut Value, this: &Self) { gobject_sys::g_value_set_boxed( value.to_glib_none_mut().0, this.to_glib_none().0 as glib_sys::gpointer, ) } } impl SetValueOptional for VariantTy { unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) { use std::ptr; let p = match this { Some(ref t) => t.to_glib_none().0 as glib_sys::gpointer, None => ptr::null(), }; gobject_sys::g_value_set_boxed(value.to_glib_none_mut().0, p) } } impl<'a> FromValueOptional<'a> for &'a VariantTy { unsafe fn from_value_optional(value: &'a Value) -> Option { let cvty = gobject_sys::g_value_get_boxed(value.to_glib_none().0) as *mut glib_sys::GVariantType; if cvty.is_null() { None } else { Some(VariantTy::from_ptr(cvty)) } } } impl StaticType for VariantType { fn static_type() -> Type { unsafe { from_glib(glib_sys::g_variant_type_get_gtype()) } } } impl SetValue for VariantType { unsafe fn set_value(value: &mut Value, this: &Self) { gobject_sys::g_value_set_boxed( value.to_glib_none_mut().0, this.to_glib_none().0 as glib_sys::gpointer, ) } } impl SetValueOptional for VariantType { unsafe fn set_value_optional(value: &mut Value, this: Option<&Self>) { use std::ptr; let p = match this { Some(ref t) => t.to_glib_none().0 as glib_sys::gpointer, None => ptr::null(), }; gobject_sys::g_value_set_boxed(value.to_glib_none_mut().0, p) } } impl<'a> FromValueOptional<'a> for VariantType { unsafe fn from_value_optional(value: &'a Value) -> Option { Option::::from_glib_none( gobject_sys::g_value_get_boxed(value.to_glib_none().0) as *mut glib_sys::GVariantType, ) } } 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) => { 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 glib_sys; use translate::*; use value::ToValue; unsafe fn equal(ptr1: *const T, ptr2: *const U) -> bool { from_glib(glib_sys::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!(ty1 != ty2); assert!(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 = ty1.to_value(); let ty4 = tyv2.get::().unwrap(); assert_eq!(ty3, ty4); assert_eq!(VariantTy::static_type(), VariantTy::static_type()); } } glib-0.8.2/src/wrapper.rs010066400017500001750000000355041354212620200135020ustar0000000000000000// Copyright 2015-2016, The Gtk-rs Project Developers. // See the COPYRIGHT file at the top-level directory of this distribution. // Licensed under the MIT license, see the LICENSE file or //! `IMPL` The `glib_wrapper!` macro and miscellaneous wrapper traits. /// Defines a wrapper type and implements the appropriate traits. /// /// The basic syntax is /// /// ```ignore /// glib_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 /// glib_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 /// glib_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), /// get_type => || ffi::gtk_text_iter_get_type(), /// } /// } /// ``` /// /// `get_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 /// glib_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 /// glib_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), /// get_type => || ffi::gdk_frame_timings_get_type(), /// } /// } /// ``` /// /// `get_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 /// glib_wrapper! { /// /// Your documentation goes here /// pub struct InstanceName(Object) /// @extends ParentClass, GrandparentClass, ..., /// @implements Interface1, Interface2, ...; /// /// match fn { /// get_type => || ffi::instance_get_type(), /// } /// } /// ``` /// /// `get_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 /// glib_wrapper! { /// pub struct WindowGroup(Object); /// /// match fn { /// get_type => || ffi::gtk_window_group_get_type(), /// } /// } /// ``` /// /// In contrast, `ffi::GtkButton` has a parent, grandparent, etc. classes, which must be specified: /// /// ```ignore /// glib_wrapper! { /// pub struct Button(Object) @extends Bin, Container, Widget; /// // see note on interfaces in the example below /// /// match fn { /// get_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 /// glib_wrapper! { /// pub struct Button(Object) /// @extends Bin, Container, Widget, // parent classes /// @implements Buildable, Actionable; // interfaces /// /// match fn { /// get_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 /// glib_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 /// glib_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 /// glib_wrapper! { /// pub struct TreeSortable(Interface) @requires TreeModel; /// ... /// } /// ``` /// /// [#boxed]: #boxed /// [#shared]: #shared /// [#object]: #object /// [#non-derivable-classes]: #non-derivable-classes #[macro_export] macro_rules! glib_wrapper { // Boxed ( $(#[$attr:meta])* pub struct $name:ident(Boxed<$ffi_name:path>); 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:path>); match fn { copy => |$copy_arg:ident| $copy_expr:expr, free => |$free_arg:ident| $free_expr:expr, get_type => || $get_type_expr:expr, } ) => { $crate::glib_boxed_wrapper!([$($attr)*] $name, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr, @get_type $get_type_expr); }; ( $(#[$attr:meta])* pub struct $name:ident(Boxed<$ffi_name:path>); 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:path>); 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, get_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, @get_type $get_type_expr); }; // Shared ( $(#[$attr:meta])* pub struct $name:ident(Shared<$ffi_name:path>); 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:path>); match fn { ref => |$ref_arg:ident| $ref_expr:expr, unref => |$unref_arg:ident| $unref_expr:expr, get_type => || $get_type_expr:expr, } ) => { $crate::glib_shared_wrapper!([$($attr)*] $name, $ffi_name, @ref $ref_arg $ref_expr, @unref $unref_arg $unref_expr, @get_type $get_type_expr); }; // Object, no class struct, no parents or interfaces ( $(#[$attr:meta])* pub struct $name:ident(Object<$ffi_name:path, $rust_class_name:ident>); match fn { get_type => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $crate::wrapper::Void, $rust_class_name, @get_type $get_type_expr, @extends [], @implements []); }; // Object, class struct, no parents or interfaces ( $(#[$attr:meta])* pub struct $name:ident(Object<$ffi_name:path, $ffi_class_name:path, $rust_class_name:ident>); match fn { get_type => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $ffi_class_name, $rust_class_name, @get_type $get_type_expr, @extends [], @implements []); }; // Object, no class struct, parents, no interfaces ( $(#[$attr:meta])* pub struct $name:ident(Object<$ffi_name:path, $rust_class_name:ident>) @extends $($extends:path),+; match fn { get_type => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $crate::wrapper::Void, $rust_class_name, @get_type $get_type_expr, @extends [$($extends),+], @implements []); }; // Object, class struct, parents, no interfaces ( $(#[$attr:meta])* pub struct $name:ident(Object<$ffi_name:path, $ffi_class_name:path, $rust_class_name:ident>) @extends $($extends:path),+; match fn { get_type => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $ffi_class_name, $rust_class_name, @get_type $get_type_expr, @extends [$($extends),+], @implements []); }; // Object, no class struct, no parents, interfaces ( $(#[$attr:meta])* pub struct $name:ident(Object<$ffi_name:path, $rust_class_name:ident>) @implements $($implements:path),+; match fn { get_type => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $crate::wrapper::Void, $rust_class_name, @get_type $get_type_expr, @extends [], @implements [$($implements),+]); }; // Object, class struct, no parents, interfaces ( $(#[$attr:meta])* pub struct $name:ident(Object<$ffi_name:path, $ffi_class_name:path, $rust_class_name:ident>) @implements $($implements:path),+; match fn { get_type => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $ffi_class_name, $rust_class_name, @get_type $get_type_expr, @extends [], @implements [$($implements),+]); }; // Object, no class struct, parents and interfaces ( $(#[$attr:meta])* pub struct $name:ident(Object<$ffi_name:path, $rust_class_name:ident>) @extends $($extends:path),+, @implements $($implements:path),+; match fn { get_type => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $crate::wrapper::Void, $rust_class_name, @get_type $get_type_expr, @extends [$($extends),+], @implements [$($implements),+]); }; // Object, class struct, parents and interfaces ( $(#[$attr:meta])* pub struct $name:ident(Object<$ffi_name:path, $ffi_class_name:path, $rust_class_name:ident>) @extends $($extends:path),+, @implements $($implements:path),+; match fn { get_type => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@object [$($attr)*] $name, $ffi_name, $ffi_class_name, $rust_class_name, @get_type $get_type_expr, @extends [$($extends),+], @implements [$($implements),+]); }; // Interface, no prerequisites ( $(#[$attr:meta])* pub struct $name:ident(Interface<$ffi_name:path>); match fn { get_type => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@interface [$($attr)*] $name, $ffi_name, @get_type $get_type_expr, @requires []); }; // Interface, prerequisites ( $(#[$attr:meta])* pub struct $name:ident(Interface<$ffi_name:path>) @requires $($requires:path),+; match fn { get_type => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!(@interface [$($attr)*] $name, $ffi_name, @get_type $get_type_expr, @requires [$($requires),+]); }; } // So we can refer to the empty type by a path pub type Void = (); glib-0.8.2/.cargo_vcs_info.json0000644000000001120000000000000120110ustar00{ "git": { "sha1": "fa8910db505ce681a5b97a1ea7b8af2a6913b310" } }