glib-0.20.9/.cargo_vcs_info.json0000644000000001420000000000100120360ustar { "git": { "sha1": "052084edb141065138e407dd6e53471ad166413f" }, "path_in_vcs": "glib" }glib-0.20.9/COPYRIGHT000064400000000000000000000012131046102023000121210ustar 00000000000000The gtk-rs Project is licensed under the MIT license, see the LICENSE file or . Copyrights in the gtk-rs Project project are retained by their contributors. No copyright assignment is required to contribute to the gtk-rs Project project. For full authorship information, see the version control history. This project provides interoperability with various GNOME libraries but doesn't distribute any parts of them. Distributing compiled libraries and executables that link to those libraries may be subject to terms of the GNU LGPL or other licenses. For more information check the license of each GNOME library. glib-0.20.9/Cargo.lock0000644000000636140000000000100100260ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "anes" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstyle" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "basic-toml" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" dependencies = [ "serde", ] [[package]] name = "bitflags" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "bumpalo" version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "cast" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-expr" version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d4ba6e40bd1184518716a6e1a781bf9160e286d219ccdb8ab2612e74cfe4789" dependencies = [ "smallvec", "target-lexicon", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "ciborium" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", "serde", ] [[package]] name = "ciborium-io" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", "half", ] [[package]] name = "clap" version = "4.5.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8acebd8ad879283633b343856142139f2da2317c96b05b4dd6181c61e2480184" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" version = "4.5.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ba32cbda51c7e1dfd49acc1457ba1a7dec5b64fe360e828acb13ca8dc9c2f9" dependencies = [ "anstyle", "clap_lex", ] [[package]] name = "clap_lex" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "criterion" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" dependencies = [ "anes", "cast", "ciborium", "clap", "criterion-plot", "is-terminal", "itertools", "num-traits", "once_cell", "oorandom", "plotters", "rayon", "regex", "serde", "serde_derive", "serde_json", "tinytemplate", "walkdir", ] [[package]] name = "criterion-plot" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", "itertools", ] [[package]] name = "crossbeam-deque" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", "windows-sys 0.59.0", ] [[package]] name = "fastrand" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "futures-channel" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", ] [[package]] name = "futures-core" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", "futures-util", ] [[package]] name = "futures-macro" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "futures-task" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-macro", "futures-task", "pin-project-lite", "pin-utils", "slab", ] [[package]] name = "getrandom" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" dependencies = [ "cfg-if", "libc", "wasi", "windows-targets", ] [[package]] name = "gio-sys" version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "160eb5250a26998c3e1b54e6a3d4ea15c6c7762a6062a19a7b63eff6e2b33f9e" dependencies = [ "glib-sys", "gobject-sys", "libc", "system-deps", "windows-sys 0.52.0", ] [[package]] name = "gir-format-check" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a5da913a8586ce748f1164c890e1ebe75a7bbc472668f57b7f9fb893d7ac416" [[package]] name = "glib" version = "0.20.9" dependencies = [ "bitflags", "criterion", "futures-channel", "futures-core", "futures-executor", "futures-task", "futures-util", "gio-sys", "gir-format-check", "glib-macros", "glib-sys", "gobject-sys", "libc", "log", "memchr", "smallvec", "tempfile", "trybuild2", ] [[package]] name = "glib-macros" version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "715601f8f02e71baef9c1f94a657a9a77c192aea6097cf9ae7e5e177cd8cde68" dependencies = [ "heck", "proc-macro-crate", "proc-macro2", "quote", "syn", ] [[package]] name = "glib-sys" version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8928869a44cfdd1fccb17d6746e4ff82c8f82e41ce705aa026a52ca8dc3aefb" dependencies = [ "libc", "system-deps", ] [[package]] name = "glob" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "gobject-sys" version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c773a3cb38a419ad9c26c81d177d96b4b08980e8bdbbf32dace883e96e96e7e3" dependencies = [ "glib-sys", "libc", "system-deps", ] [[package]] name = "half" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" dependencies = [ "cfg-if", "crunchy", ] [[package]] name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "indexmap" version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "is-terminal" version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37" dependencies = [ "hermit-abi", "libc", "windows-sys 0.59.0", ] [[package]] name = "itertools" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", ] [[package]] name = "libc" version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "linux-raw-sys" version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "log" version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "once_cell" version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "oorandom" version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "pin-project-lite" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plotters" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", "plotters-svg", "wasm-bindgen", "web-sys", ] [[package]] name = "plotters-backend" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] [[package]] name = "proc-macro-crate" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] [[package]] name = "rayon" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", ] [[package]] name = "rayon-core" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", ] [[package]] name = "regex" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustix" version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", "windows-sys 0.59.0", ] [[package]] name = "rustversion" version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "ryu" version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ "winapi-util", ] [[package]] name = "serde" version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.138" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] [[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" [[package]] name = "syn" version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "system-deps" version = "7.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66d23aaf9f331227789a99e8de4c91bf46703add012bdfd45fdecdfb2975a005" dependencies = [ "cfg-expr", "heck", "pkg-config", "toml", "version-compare", ] [[package]] name = "target-lexicon" version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" dependencies = [ "cfg-if", "fastrand", "getrandom", "once_cell", "rustix", "windows-sys 0.59.0", ] [[package]] name = "termcolor" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "tinytemplate" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" dependencies = [ "serde", "serde_json", ] [[package]] name = "toml" version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" dependencies = [ "serde", "serde_spanned", "toml_datetime", "toml_edit", ] [[package]] name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", "winnow", ] [[package]] name = "trybuild2" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e7ab1c31cd9e92e56b63f4d85a6c6a854880aaf433191623f5d50e152dcdbc2" dependencies = [ "basic-toml", "glob", "once_cell", "serde", "serde_derive", "serde_json", "termcolor", ] [[package]] name = "unicode-ident" version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" [[package]] name = "version-compare" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" [[package]] name = "walkdir" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "wasi" version = "0.13.3+wasi-0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" dependencies = [ "wit-bindgen-rt", ] [[package]] name = "wasm-bindgen" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "winapi-util" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59690dea168f2198d1a3b0cac23b8063efcd11012f10ae4698f284808c8ef603" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen-rt" version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" dependencies = [ "bitflags", ] glib-0.20.9/Cargo.toml0000644000000076700000000000100100510ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.70" name = "glib" version = "0.20.9" authors = ["The gtk-rs Project Developers"] build = false exclude = ["gir-files/*"] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Rust bindings for the GLib library" homepage = "https://gtk-rs.org/" documentation = "https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/" readme = "README.md" keywords = [ "glib", "gtk-rs", "gnome", "GUI", ] license = "MIT" repository = "https://github.com/gtk-rs/gtk-rs-core" [package.metadata.docs.rs] all-features = true rustc-args = [ "--cfg", "docsrs", ] rustdoc-args = [ "--cfg", "docsrs", "--generate-link-to-definition", ] [lib] name = "glib" path = "src/lib.rs" [[test]] name = "bridged_logging" path = "tests/bridged_logging.rs" [[test]] name = "check_gir" path = "tests/check_gir.rs" [[test]] name = "clone" path = "tests/clone.rs" [[test]] name = "derive" path = "tests/derive.rs" [[test]] name = "log" path = "tests/log.rs" [[test]] name = "print" path = "tests/print.rs" [[test]] name = "regex_compiletest" path = "tests/regex_compiletest.rs" [[test]] name = "structured_log" path = "tests/structured_log.rs" [[test]] name = "subclass_compiletest" path = "tests/subclass_compiletest.rs" required-features = ["compiletests"] [[test]] name = "unicollate" path = "tests/unicollate.rs" [[test]] name = "value" path = "tests/value.rs" [[bench]] name = "gstring" path = "benches/gstring.rs" harness = false [dependencies.bitflags] version = "2.6" [dependencies.futures-channel] version = "0.3" [dependencies.futures-core] version = "0.3" default-features = false [dependencies.futures-executor] version = "0.3" [dependencies.futures-task] version = "0.3" default-features = false [dependencies.futures-util] version = "0.3" [dependencies.gio-sys] version = "0.20.6" optional = true [dependencies.glib-macros] version = "0.20.3" [dependencies.glib-sys] version = "0.20.6" [dependencies.gobject-sys] version = "0.20" [dependencies.libc] version = "0.2" [dependencies.memchr] version = "2.7.4" [dependencies.rs-log] version = "0.4" optional = true package = "log" [dependencies.smallvec] version = "1.13" features = [ "union", "const_generics", "const_new", ] [dev-dependencies.criterion] version = "0.5.1" [dev-dependencies.gir-format-check] version = "^0.1" [dev-dependencies.tempfile] version = "3" [dev-dependencies.trybuild2] version = "1" [features] compiletests = [] default = ["gio"] gio = ["gio-sys"] log = ["rs-log"] log_macros = ["log"] v2_58 = [ "glib-sys/v2_58", "gobject-sys/v2_58", ] v2_60 = [ "v2_58", "glib-sys/v2_60", ] v2_62 = [ "v2_60", "glib-sys/v2_62", "gobject-sys/v2_62", ] v2_64 = [ "v2_62", "glib-sys/v2_64", ] v2_66 = [ "v2_64", "glib-sys/v2_66", "gobject-sys/v2_66", ] v2_68 = [ "v2_66", "glib-sys/v2_68", "gobject-sys/v2_68", ] v2_70 = [ "v2_68", "glib-sys/v2_70", "gobject-sys/v2_70", ] v2_72 = [ "v2_70", "glib-sys/v2_72", "gobject-sys/v2_72", ] v2_74 = [ "v2_72", "glib-sys/v2_74", "gobject-sys/v2_74", ] v2_76 = [ "v2_74", "glib-sys/v2_76", "gobject-sys/v2_76", ] v2_78 = [ "v2_76", "glib-sys/v2_78", "gobject-sys/v2_78", ] v2_80 = [ "v2_78", "glib-sys/v2_80", "gobject-sys/v2_80", ] v2_82 = [ "v2_80", "glib-sys/v2_82", "gobject-sys/v2_82", ] v2_84 = [ "v2_82", "glib-sys/v2_84", "gobject-sys/v2_84", ] glib-0.20.9/Cargo.toml.orig000064400000000000000000000042611046102023000135230ustar 00000000000000[package] name = "glib" documentation = "https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/" description = "Rust bindings for the GLib library" readme = "README.md" keywords = ["glib", "gtk-rs", "gnome", "GUI"] authors.workspace = true edition.workspace = true exclude.workspace = true homepage.workspace = true license.workspace = true repository.workspace = true rust-version.workspace = true version.workspace = true [lib] name = "glib" [dependencies] libc.workspace = true bitflags.workspace = true futures-core = { version = "0.3", default-features = false } futures-task = { version = "0.3", default-features = false } futures-executor = "0.3" futures-channel = "0.3" futures-util = "0.3" glib-sys.workspace = true gobject-sys.workspace = true glib-macros.workspace = true rs-log = { package = "log", version = "0.4", optional = true } smallvec = { version = "1.13", features = ["union", "const_generics", "const_new"] } gio-sys = { workspace = true, optional = true } memchr = "2.7.4" [dev-dependencies] tempfile = "3" gir-format-check.workspace = true trybuild2 = "1" criterion = "0.5.1" [features] default = ["gio"] v2_58 = ["glib-sys/v2_58", "gobject-sys/v2_58"] v2_60 = ["v2_58", "glib-sys/v2_60"] v2_62 = ["v2_60", "glib-sys/v2_62", "gobject-sys/v2_62"] v2_64 = ["v2_62", "glib-sys/v2_64"] v2_66 = ["v2_64", "glib-sys/v2_66", "gobject-sys/v2_66"] v2_68 = ["v2_66", "glib-sys/v2_68", "gobject-sys/v2_68"] v2_70 = ["v2_68", "glib-sys/v2_70", "gobject-sys/v2_70"] v2_72 = ["v2_70", "glib-sys/v2_72", "gobject-sys/v2_72"] v2_74 = ["v2_72", "glib-sys/v2_74", "gobject-sys/v2_74"] v2_76 = ["v2_74", "glib-sys/v2_76", "gobject-sys/v2_76"] v2_78 = ["v2_76", "glib-sys/v2_78", "gobject-sys/v2_78"] v2_80 = ["v2_78", "glib-sys/v2_80", "gobject-sys/v2_80"] v2_82 = ["v2_80", "glib-sys/v2_82", "gobject-sys/v2_82"] v2_84 = ["v2_82", "glib-sys/v2_84", "gobject-sys/v2_84"] log = ["rs-log"] log_macros = ["log"] compiletests = [] gio = ["gio-sys"] [[test]] name = "subclass_compiletest" required-features = ["compiletests"] [[bench]] name = "gstring" harness = false [package.metadata.docs.rs] all-features = true rustc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"] glib-0.20.9/Gir.toml000064400000000000000000000603501046102023000122530ustar 00000000000000[options] girs_directories = ["../gir-files"] library = "GLib" version = "2.0" min_cfg_version = "2.56" use_gi_docgen = true target_path = "." work_mode = "normal" single_version_file = true deprecate_by_min_version = true trust_return_value_nullability = true generate = [ "GLib.ConvertError", "GLib.DateDay", "GLib.DateMonth", "GLib.DateWeekday", "GLib.DateYear", "GLib.FileError", "GLib.FileSetContentsFlags", "GLib.IOCondition", "GLib.KeyFileError", "GLib.KeyFileFlags", "GLib.LogLevelFlags", "GLib.LogWriterOutput", "GLib.MainContextFlags", "GLib.MarkupError", "GLib.NormalizeMode", "GLib.OptionArg", "GLib.OptionFlags", "GLib.RegexCompileFlags", "GLib.RegexMatchFlags", "GLib.SeekType", "GLib.SpawnFlags", "GLib.Time", "GLib.TimeType", "GLib.UnicodeType", "GLib.UriError", "GLib.UriFlags", "GLib.UriHideFlags", "GLib.UriParamsFlags", "GLib.VariantClass", ] manual = [ "GLib.ByteArray", "GLib.Bytes", "GLib.Error", "GLib.ParamSpecBoolean", "GLib.ParamSpecBoxed", "GLib.ParamSpecChar", "GLib.ParamSpecDouble", "GLib.ParamSpecEnum", "GLib.ParamSpecFlags", "GLib.ParamSpecFloat", "GLib.ParamSpecGType", "GLib.ParamSpecInt", "GLib.ParamSpecInt64", "GLib.ParamSpecLong", "GLib.ParamSpecObject", "GLib.ParamSpecOverride", "GLib.ParamSpecParam", "GLib.ParamSpecPointer", "GLib.ParamSpecString", "GLib.ParamSpecUChar", "GLib.ParamSpecUInt", "GLib.ParamSpecUInt64", "GLib.ParamSpecULong", "GLib.ParamSpecUnichar", "GLib.ParamSpecValueArray", "GLib.ParamSpecVariant", "GLib.UserDirectory", "GLib.Variant", "GLib.VariantType", "GObject.Object", "GObject.ObjectClass", ] [[object]] name = "GLib.*" status = "generate" [[object.function]] pattern = "(assertion_message_cmpint|assert_warning|assertion_message|assertion_message_cmpnum|assertion_message_cmpstr|warn_message|return_if_fail_warning)" ignore = true # Not useful assertions functions [[object.function]] pattern = "(set_print_handler|set_printerr_handler|vasprintf|vfprintf|vprintf|vsnprintf|vsprintf|stpcpy|sprintf|snprintf|printf|printf_string_upper_bound|printerr|prefix_error|print|fprintf)" ignore = true # Not useful string functions [[object.function]] pattern = "(malloc|malloc0|malloc0_n|malloc_n|memdup|memdup2|realloc|realloc_n|try_malloc||try_malloc0|try_malloc0_n|try_malloc_n|try_realloc|try_realloc_n|free|aligned_alloc|aligned_alloc0|aligned_free|free_sized|aligned_free_sized)" ignore = true # Not useful allocations functions [[object.function]] pattern = "(slice_get_config|slice_get_config_state|slice_set_config|slice_alloc|slice_alloc0|slice_copy|slice_free1|slice_free_chain_with_offset)" ignore = true # Not useful slices functions [[object.function]] pattern = "(path_is_absolute|path_skip_root|rmdir|basename|canonicalize_filename|build_filename|build_filename_valist|build_filenamev|build_path|build_pathv|canonicalize_filename|chdir)" ignore = true # Not useful paths functions, use Path/PathBuf [[object.function]] pattern = "(int64_equal|int64_hash|int_equal|int_hash|double_equal|double_hash|direct_equal|direct_hash)" ignore = true # Not useful equal/hash functions, only useful for GHashTable [[object.function]] pattern = "(clear_handle_id|clear_list|clear_pointer|clear_slist|clear_error|nullify_pointer)" ignore = true # Not useful freeing functions [[object.function]] pattern = "(fdwalk_set_cloexec|closefrom)" ignore = true # unsafe [[object.function]] pattern = "(datalist_.*|dataset_.*)" ignore = true # Not useful GData related functions [[object.function]] pattern = "(path_get_basename|path_get_dirname|file_test)" visibility = "crate" # used for tests [[object.function]] pattern = "(propagate_prefixed_error|set_error|file_error_from_errno|propagate_error|set_error_literal|set_error)" ignore = true # Not useful error handling functions [[object.function]] name = "parse_debug_string" ignore = true # useless [[object.function]] pattern = "(log_.*|logv)" ignore = true # needs manual wrappers to make their usage nicer [[object.function]] pattern = "compute_.*_for_string" ignore = true # needs manual wrapper to avoid an unnecessary copy of the string [[object.function]] pattern = "(idle_remove_by_data|qsort_with_data)" ignore = true # Unsafe functions [[object.function]] pattern = "(fopen|creat|chmod|blow_chunks|utime|slice_debug_tree_statistics|rename|remove|open|mkdir|lstat|fsync|freopen|set_prgname_once)" ignore = true # see https://gitlab.gnome.org/GNOME/glib/-/issues/3231 [[object.function]] pattern = "iconv" doc_struct_name = "IConv" manual = true [[object.function]] pattern = "convert_with_iconv" doc_struct_name = "IConv" manual = true rename = "convert" [[object.function]] pattern = "pointer_.*" ignore = true # Not usable, uses raw pointers [[object.function]] pattern = "file_read_link" ignore = true # use the ones from the std [[object.function]] pattern = "pattern_.*" ignore = true # use the ones from the std [[object.function]] pattern = "(markup_collect_attributes|markup_printf_escaped|markup_vprintf_escaped)" ignore = true # varargs functions are unbindable [[object.function]] pattern = "io_.*" ignore = true # they are supposed to be used with IOChannel, which doesn't have safe bindings [[object.function]] name = "file_open_tmp" manual = true # Return a RawFd instead of a i32 [[object.function]] pattern = "atomic_.+" ignore = true [[object.function]] pattern = "bit_.*" ignore = true # use the ones in the std [[object.function]] name = "get_current_time" ignore = true # Deprecated [[object.function]] name = "get_filename_charsets" manual = true [[object.function]] pattern = "str.+v" #string ignore = true [[object.function]] name = "strv_length" #string ignore = true [[object.function]] pattern = "str.+" ignore = true [[object.function]] pattern = "ucs4_.+" ignore = true [[object.function]] pattern = "utf16_.+" ignore = true [[object.function]] pattern = "utf8_.+" ignore = true [[object.function]] pattern = "unichar_.+" ignore = true [[object.function]] pattern = "ascii_.+" ignore = true [[object.function]] name = "assertion_message_error" #Quark ignore = true [[object.function]] name = "assertion_message_expr" ignore = true # function is useless [[object.function]] name = "assertion_message_cmpstrv" ignore = true # function is useless [[object.function]] pattern = "test_.+" ignore = true # functions are useless [[object.function]] pattern = "prefix_error_literal" 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]] pattern = "[gs]et_prgname" #manual pathbuf ignore = true [[object.function]] name = "get_user_name" [object.function.return] string_type = "os_string" [[object.function]] name = "get_real_name" [object.function.return] string_type = "os_string" [[object.function]] pattern = "setenv" [[object.function.parameter]] name = "variable" string_type = "os_string" [[object.function.parameter]] name = "value" string_type = "os_string" [object.function.return] bool_return_is_error = "Failed to set environment variable" [[object.function]] pattern = "getenv" [[object.function.parameter]] name = "variable" string_type = "os_string" [object.function.return] string_type = "os_string" [[object.function]] name = "unsetenv" [[object.function.parameter]] name = "variable" string_type = "os_string" [[object.function]] name = "file_get_contents" # Use glib::Slice as return value manual = true [[object.function]] name = "mkstemp" # modifies the string passed in manual = true [[object.function]] name = "mkstemp_full" # modifies the string passed in manual = true [[object.function]] pattern = "mkdtemp(_full)?" # needs to be transfer full, see # https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2596 manual = true [[object.function]] name = "strdup" #not needed ignore = true [[object.function]] pattern = "unix_.+" cfg_condition = "unix" [[object.function]] name = "spawn_command_line_async" cfg_condition = "unix" [[object.function.parameter]] name = "command_line" string_type = "os_string" [[object.function]] name = "unix_open_pipe" manual = true [[object.function]] name = "convert_with_fallback" manual = 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" manual = true [[object.function]] name = "filename_from_utf8" manual = true [[object.function]] name = "filename_to_utf8" manual = true [[object.function]] name = "locale_from_utf8" manual = true [[object.function]] name = "locale_to_utf8" manual = true [[object.function]] name = "child_watch_source_new" # Need manual bindings to be useful ignore = true [[object.function]] name = "idle_source_new" # Need manual bindings to be useful ignore = true [[object.function]] name = "timeout_source_new" # Need manual bindings to be useful ignore = true [[object.function]] name = "timeout_source_new_seconds" # Need manual bindings to be useful ignore = true [[object.function]] name = "unix_signal_source_new" # Need manual bindings to be useful ignore = true [[object.function]] pattern = "unix_fd.*" # Need manual binding for RawFd ignore = true [[object.function]] name = "close" # Need manual binding for RawFd ignore = true [[object.function]] name = "log_writer_is_journald" # Need manual binding for RawFd ignore = true [[object.function]] name = "log_writer_supports_color" # Need manual binding for RawFd ignore = true [[object.function]] name = "unix_set_fd_nonblocking" # Need manual binding for RawFd ignore = true [[object.function]] name = "environ_getenv" # manual input &[OsString] ignore = true [[object.function]] pattern = "environ_(un)?setenv" # unusable ignore = true [[object.function]] name = "get_charset" # boolean return value ignore = true [[object.function]] name = "get_environ" [object.function.return] string_type = "os_string" [[object.function]] name = "listenv" [object.function.return] string_type = "os_string" [[object.function]] name = "shell_parse_argv" [[object.function.parameter]] name = "command_line" string_type = "os_string" [[object.function.parameter]] name = "argvp" string_type = "os_string" [[object.function]] name = "shell_quote" [[object.function.parameter]] name = "unquoted_string" string_type = "os_string" [object.function.return] string_type = "os_string" [[object.function]] name = "shell_unquote" [[object.function.parameter]] name = "quoted_string" string_type = "os_string" [object.function.return] string_type = "os_string" [[object.function]] name = "intern_static_string" ignore = true [[object.function]] name = "intern_string" ignore = true [[object.function]] # Pid conversion issue name = "child_watch_add" ignore = true [[object.function]] # Pid conversion issue name = "child_watch_add_full" ignore = true # idle_* and timeout_* are manually implemented [[object.function]] name = "idle_add" ignore = true [[object.function]] name = "idle_add_full" ignore = true [[object.function]] name = "idle_add_once" ignore = true [[object.function]] name = "timeout_add" ignore = true [[object.function]] name = "timeout_add_full" ignore = true [[object.function]] name = "timeout_add_once" ignore = true [[object.function]] name = "timeout_add_seconds" ignore = true [[object.function]] name = "timeout_add_seconds_full" ignore = true [[object.function]] name = "timeout_add_seconds_once" ignore = true # we have a manual impl already [[object.function]] name = "unix_signal_add" ignore = true [[object.function]] name = "unix_signal_add_full" ignore = true [[object.function]] pattern = "rc_box_.+" #need manual implementation ignore = true [[object.function]] pattern = "ref_count_.+" #need manual implementation ignore = true [[object.function]] pattern = "ref_string_.+" #need manual implementation ignore = true [[object.function]] name = "spawn_async_with_fds" # generates invalid FDs ignore = true [[object.function]] name = "spawn_async_with_pipes" # generates invalid FDs ignore = true [[object.function]] name = "log_set_handler" # leaks closure ignore = true [[object.function]] name = "log_default_handler" # last argument is unused ignore = true [[object.function]] name = "log_set_handler_full" # from_glib_borrow on non-pointer objects ignore = true [[object.function]] name = "log_set_writer_func" # from_glib_borrow on non-pointer objects ignore = true [[object.function]] name = "log_structured" # implemented with a macro because of var args and weird arguments pairing ignore = true [[object.function]] name = "log" # implemented with a macro because of var args ignore = true [[object.function]] name = "log_set_default_handler" # It returned the old callback, which is problematic ignore = true [[object.function]] name = "log_remove_handler" # Change handler_id parameter type to LogHandlerId ignore = true [[object.function]] name = "log_set_always_fatal" # update of arguments and return type ignore = true [[object.function]] name = "log_variant" # usage of LogLevelFlags ignore = true [[object.function]] name = "log_set_fatal_mask" # update of arguments and return type ignore = true [[object.constant]] pattern = "DIR_SEPARATOR(_S)?" #not cross-platform ignore = true [[object.constant]] pattern = "SEARCHPATH_SEPARATOR(_S)?" #not cross-platform ignore = true [[object.constant]] name = "MODULE_SUFFIX" #not cross-platform ignore = true [[object.constant]] pattern = "GU?INT(16)?(32)?(64)?(PTR)?_FORMAT" #for C printf ignore = true [[object.constant]] pattern = "GU?INT(16)?(32)?(64)?(PTR)?_MODIFIER" #for C printf ignore = true [[object.constant]] pattern = "GS?SIZE_(FORMAT)?(MODIFIER)?" #for C printf ignore = true [[object.constant]] pattern = "GNUC_(PRETTY_)?FUNCTION" #for C printf ignore = true [[object.constant]] pattern = "PID_FORMAT" #for C printf ignore = true [[object.constant]] pattern = "POLLFD_FORMAT" #for C printf ignore = true [[object.function]] name = "variant_get_gtype" # get_type() function that should be used in StaticType impl instead ignore = true [[object.function]] pattern = "unichar_((break_)?type|get_(script|mirror_char)|combining_class|is(mark|graph|punct|title|defined|wide(_cjk)?|zerowidth)|totitle|(fully_)?decompose|compose)" manual = true # defined as extension methods on char [[object]] name = "GLib.Checksum" status = "generate" concurrency = "send+sync" [[object.function]] name = "get_digest" #wrong array definition manual = true [[object.function]] name = "get_string" #consume manual = true [[object]] name = "GLib.ChecksumType" status = "generate" [[object.member]] name = "sha384" version = "2.52" [[object]] name = "GLib.DateTime" status = "generate" concurrency = "send+sync" [[object.function]] name = "new_local" rename = "from_local" [[object.function]] name = "new_now" rename = "now" [[object.function]] name = "new_now_local" rename = "now_local" [[object.function]] name = "new_now_utc" rename = "now_utc" [[object.function]] name = "new_utc" rename = "from_utc" [[object.function]] pattern = ".+" [object.function.return] nullable_return_is_error = "Invalid date" [[object]] name = "GLib.FileTest" # used for tests status = "generate" visibility = "crate" [[object]] name = "GLib.FormatSizeFlags" status = "generate" [[object.member]] name = "only_value" version = "2.74" [[object.member]] name = "only_unit" version = "2.74" [[object]] name = "GLib.IConv" status = "manual" concurrency = "send" [[object.function]] name = "open" rename = "new" constructor = true [[object]] name = "GLib.KeyFile" status = "generate" [[object.function]] name = "load_from_data_dirs" manual = true [[object.function]] name = "load_from_dirs" manual = true [[object.function]] name = "save_to_file" # file parameter needs to be a PathBuf manual = true [[object.function]] name = "set_locale_string_list" #[&str] to *mut i8 ignore = true [[object.function]] name = "set_string_list" #[&str] to *mut i8 ignore = true [[object.function]] name = "to_data" manual = true [[object.function]] name = "set_double_list" #wrong array type ignore = true [[object.function]] name = "set_integer_list" #wrong array type ignore = true [[object.function]] name = "get_groups" #return slice of str pointers manual = true [[object.function]] name = "get_keys" #return slice of str pointers manual = true [[object.function]] name = "get_boolean" #boolean return value needs to be returned manual = true [[object.function]] name = "has_key" #boolean return value needs to be returned manual = true [[object.function]] name = "get_boolean_list" #boolean array needs to be converted to Vec manual = true [[object.function]] name = "get_string" # can return an error but still a value to be freed manual = true [[object.function]] name = "get_string_list" # can return an error but still a value to be freed manual = true [[object.function]] name = "get_locale_string" # can return an error but still a value to be freed manual = true [[object.function]] name = "get_locale_string_list" # can return an error but still a value to be freed manual = true [[object.function]] name = "get_comment" [[object.function.parameter]] name = "key" nullable = true [[object]] name = "GLib.MainContext" status = "generate" concurrency = "send+sync" [[object.function]] name = "prepare" # out parameter not marked as such manual = true [[object.function]] name = "find_source_by_id" # source id is a newtype manual = true [[object.function]] name = "invoke" manual = true [[object.function]] name = "invoke_full" manual = true [[object.function]] name = "acquire" # implemented with a guard type manual = true [[object.function]] name = "release" # implemented with a guard type manual = true [[object.function]] name = "push_thread_default" # implemented with a guard type manual = true [[object.function]] name = "pop_thread_default" # implemented with a guard type manual = true [[object]] name = "GLib.MainLoop" status = "generate" concurrency = "send+sync" [[object]] name = "GLib.MarkupParseContext" status = "generate" [[object.function]] name = "get_user_data" ignore = true # unsafe pointer [[object]] name = "GLib.MatchInfo" status = "manual" [[object]] name = "GLib.Regex" status = "generate" [[object.function]] name = "check_replacement" # impl IntoGStr for parameters instead of &str manual = true [[object.function]] name = "escape_nul" # impl IntoGStr for parameters instead of &str manual = true [[object.function]] name = "escape_string" # impl IntoGStr for parameters instead of &str manual = true [[object.function]] name = "match" # implement in terms of match_full manual = true [[object.function]] name = "match_all" # implement in terms of match_all_full manual = true [[object.function]] name = "match_all_full" # impl IntoGStr for parameters instead of &str manual = true [[object.function]] name = "match_simple" # impl IntoGStr for parameters instead of &str manual = true [[object.function]] name = "match_full" # impl IntoGStr for parameters instead of &str manual = true [[object.function]] name = "replace" # impl IntoGStr for parameters instead of &str manual = true [[object.function]] name = "replace_literal" # impl IntoGStr for parameters instead of &str manual = true [[object.function]] name = "split" # implement in terms of split_full manual = true [[object.function]] name = "split_full" # impl IntoGStr for parameters instead of &str # return slice of str pointers manual = true [[object.function]] name = "split_simple" # impl IntoGStr for parameters instead of &str # return slice of str pointers manual = true [[object.function]] name = "get_string_number" # impl IntoGStr for parameters instead of &str manual = true [[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.ThreadPool" status = "manual" concurrency = "send+sync" [[object.function]] name = "new_shared" rename = "shared" [[object.function]] name = "new_exclusive" rename = "exclusive" [[object]] name = "GLib.TimeSpan" status = "manual" conversion_type = "scalar" [[object]] name = "GLib.TimeZone" status = "generate" concurrency = "send+sync" [[object.function]] name = "new_identifier" rename = "from_identifier" [[object.function]] name = "new_local" rename = "local" [[object.function]] name = "new_offset" rename = "from_offset" [[object.function]] name = "new_utc" rename = "utc" [[object.function]] name = "adjust_time" # in-out parameter manual = true [[object]] name = "GLib.UnicodeBreakType" status = "generate" [[object.member]] name = "close_paranthesis" ignore = true [[object.member]] pattern = "(aksara|aksara_pre_base|aksara_start|virama_final|virama)" version = "2.80" [[object]] name = "GLib.UnicodeScript" status = "generate" [[object.member]] pattern = "cypro_minoan|old_uyghur|tangsa|toto|vithkuqi|math" version = "2.72" [[object.member]] pattern = "kawi|nag_mundari" version = "2.74" [[object.member]] pattern = "todhri|garay|tulu_tigalari|sunuwar|gurung_khema|kirat_rai|ol_onal" version = "2.84" [[object]] name = "GLib.Uri" status = "generate" concurrency = "send+sync" glib-0.20.9/Gir_GObject.toml000064400000000000000000000074131046102023000136510ustar 00000000000000[options] girs_dir = "gir-files" library = "GObject" version = "2.0" min_cfg_version = "2.56" target_path = "." auto_path = "src/gobject/auto" work_mode = "normal" single_version_file = true deprecate_by_min_version = true trust_return_value_nullability = true girs_directories = ["../gir-files"] generate = [ "GObject.BindingFlags", "GObject.SignalFlags", "GObject.TypeFlags", ] ignore = [ ] manual = [ "GLib.Quark", "GObject.Object", "GObject.Value", "GObject.EnumValue", "GObject.FlagsValue", "GObject.TypeValueTable", "GObject.ParamFlags", "GObject.ParamSpec", "GObject.ParamSpecChar", "GObject.ParamSpecUChar", "GObject.ParamSpecBoolean", "GObject.ParamSpecInt", "GObject.ParamSpecUInt", "GObject.ParamSpecLong", "GObject.ParamSpecULong", "GObject.ParamSpecInt64", "GObject.ParamSpecUInt64", "GObject.ParamSpecUnichar", "GObject.ParamSpecEnum", "GObject.ParamSpecFlags", "GObject.ParamSpecFloat", "GObject.ParamSpecDouble", "GObject.ParamSpecString", "GObject.ParamSpecParam", "GObject.ParamSpecBoxed", "GObject.ParamSpecPointer", "GObject.ParamSpecValueArray", "GObject.ParamSpecObject", "GObject.ParamSpecOverride", "GObject.ParamSpecGType", "GObject.ParamSpecVariant", "GObject.InterfaceInfo", "GObject.TypeInfo", "GObject.TypePlugin", "GObject.TypeModule", ] [[object]] name = "GObject.Binding" status = "generate" final_type = true concurrency = "send+sync" [[object.function]] name = "get_source" # Not thread-safe, see https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1745 # Using the GObject properties will be automatically safe with GLib 2.68. ignore = true [[object.function]] name = "get_target" # Not thread-safe, see https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1745 # Using the GObject properties will be automatically safe with GLib 2.68. ignore = true [[object.function]] name = "dup_source" # equivalent to manual get_source ignore = true [[object.function]] name = "dup_target" # equivalent to manual get_target ignore = true [[object.property]] name = "source" # So we can implement setter/getter with the correct name ignore = true [[object.property]] name = "target" # So we can implement setter/getter with the correct name ignore = true [[object]] name = "GObject.BindingGroup" status = "generate" final_type = true concurrency = "send+sync" [[object.function]] name = "bind" manual = true [[object.function]] name = "bind_full" ignore = true [[object.function]] name = "bind_with_closures" ignore = true [[object.function]] name = "dup_source" rename = "source" [[object.property]] name = "source" generate = ["notify"] [[object]] name = "GObject.SignalGroup" status = "generate" final_type = true concurrency = "send+sync" version = "2.74" [[object.function]] name = "new" rename = "with_type" [[object.function]] name = "connect" manual = true [[object.function]] name = "connect_after" ignore = true [[object.function]] name = "connect_data" ignore = true [[object.function]] name = "connect_object" ignore = true [[object.function]] name = "connect_swapped" ignore = true [[object.function]] name = "connect_closure" manual = true [[object.function]] name = "dup_target" rename = "target" [[object.property]] name = "target" # notify signal is racy, use connect_bind/connect_unbind instead generate = [] [[object.signal]] name = "bind" manual = true [[object.signal]] name = "unbind" manual = true [[object]] name = "GObject.*" status = "ignore" glib-0.20.9/LICENSE000064400000000000000000000020001046102023000116260ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. glib-0.20.9/README.md000064400000000000000000000127661046102023000121240ustar 00000000000000# Rust GLib and GObject bindings __Rust__ bindings and wrappers for [GLib](https://docs.gtk.org/glib/), part of [gtk-rs-core](https://github.com/gtk-rs/gtk-rs-core). GLib __2.56__ is the lowest supported version for the underlying library. This library contains bindings to GLib and GObject types and APIs as well as common building blocks used in both handmade and machine generated bindings to GTK and other GLib-based libraries. It is the foundation for higher level libraries with uniform Rusty (safe and strongly typed) APIs. It avoids exposing GLib-specific data types where possible and is not meant to provide comprehensive GLib bindings, which would often amount to duplicating the Rust Standard Library or other utility crates. ## Minimum supported Rust version Currently, the minimum supported Rust version is `1.70.0`. ## Dynamic typing Most types in the GLib family have [`Type`] identifiers. Their corresponding Rust types implement the [`StaticType`] trait. A dynamically typed [`Value`] can carry values of any `StaticType`. [Variants][`Variant`] can carry values of [`StaticVariantType`]. ## Errors Errors are represented by [`Error`], which can carry values from various [error domains](error::ErrorDomain) such as [`FileError`]. ## Objects Each class and interface has a corresponding smart pointer struct representing an instance of that type (e.g. [`Object`] for [`GObject`] or [`gtk4::Widget`] for [`GtkWidget`]). They are reference counted and feature interior mutability similarly to Rust's [`Rc>`] idiom. Consequently, cloning objects is cheap and their methods never require mutable borrows. Two smart pointers are equal if they point to the same object. The root of the object hierarchy is [`Object`]. Inheritance and subtyping is denoted with the [`IsA`] marker trait. The [`Cast`] trait enables upcasting and downcasting. Interfaces and non-leaf classes also have corresponding traits (e.g. [`ObjectExt`] or [`WidgetExt`]), which are blanketly implemented for all their subtypes. You can create new subclasses of [`Object`] or other object types. Look at the module's documentation for further details and a code example. ## Under the hood GLib-based libraries largely operate on pointers to various boxed or reference counted structures so the bindings have to implement corresponding smart pointers (wrappers), which encapsulate resource management and safety checks. Such wrappers are defined via the [`wrapper!`] macro, which uses abstractions defined in the [`wrapper`], [`boxed`], [`shared`] and [`object`][mod@object] modules. The [`translate`] module defines and partly implements conversions between high level Rust types (including the aforementioned wrappers) and their FFI counterparts. ## Documentation * [Rust API - Stable](https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/) * [Rust API - Development](https://gtk-rs.org/gtk-rs-core/git/docs/glib) * [C API](https://docs.gtk.org/glib/) * [GTK Installation instructions](https://www.gtk.org/docs/installations/) ## Using We recommend using [crates from crates.io](https://crates.io/keywords/gtk-rs), as [demonstrated here](https://gtk-rs.org/#using). If you want to track the bleeding edge, use the git dependency instead: ```toml [dependencies] glib = { git = "https://github.com/gtk-rs/gtk-rs-core.git", package = "glib" } ``` Avoid mixing versioned and git crates like this: ```toml # This will not compile [dependencies] glib = "0.13" glib = { git = "https://github.com/gtk-rs/gtk-rs-core.git", package = "glib" } ``` ## License __glib__ is available under the MIT License, please refer to it. [`Type`]: https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/types/struct.Type.html [`StaticType`]: https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/types/trait.StaticType.html [`Value`]: https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/value/struct.Value.html [`Variant`]: https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/variant/struct.Variant.html [`StaticVariantType`]: https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/variant/trait.StaticVariantType.html [`Error`]: https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/error/struct.Error.html [`FileError`]: https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/enum.FileError.html [`Object`]: https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/object/struct.Object.html [`GObject`]: https://docs.gtk.org/gobject/class.Object.html [`gtk4::Widget`]: https://gtk-rs.org/gtk4-rs/stable/latest/docs/gtk4/struct.Widget.html [`GtkWidget`]: https://docs.gtk.org/gtk4/class.Widget.html [`Rc>`]: https://doc.rust-lang.org/stable/core/cell/index.html#introducing-mutability-inside-of-something-immutable [`IsA`]: https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/object/trait.IsA.html [`Cast`]: https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/object/trait.Cast.html [`ObjectExt`]: https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/object/trait.ObjectExt.html [`WidgetExt`]: https://gtk-rs.org/gtk4-rs/stable/latest/docs/gtk4/prelude/trait.WidgetExt.html [`wrapper!`]: https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/macro.wrapper.html [`wrapper`]: https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/wrapper/index.html [`boxed`]: https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/boxed/index.html [`shared`]: https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/shared/index.html [mod@object]: https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/object/index.html [`translate`]: https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/translate/index.htmlglib-0.20.9/benches/gstring.rs000064400000000000000000000022141046102023000142620ustar 00000000000000use criterion::{black_box, criterion_group, criterion_main, Criterion}; use glib::IntoGStr; pub fn str_into_gstr(c: &mut Criterion) { c.bench_function("str as IntoGStr", |b| { b.iter(|| { "abcdefg".run_with_gstr(|g| { black_box(g); }) }) }); } pub fn string_into_gstr(c: &mut Criterion) { c.bench_function("String as IntoGStr", |b| { b.iter(|| { let mut s = String::from("abcdefg"); s.shrink_to_fit(); assert_eq!(s.capacity(), s.len()); s.run_with_gstr(|g| { black_box(g); }) }) }); } pub fn string_with_capacity_into_gstr(c: &mut Criterion) { c.bench_function("String::with_capacity as IntoGStr", |b| { b.iter(|| { let mut s = String::with_capacity(100); s.push_str("abcdefg"); assert!(s.capacity() > s.len()); s.run_with_gstr(|g| { black_box(g); }) }) }); } criterion_group!( benches, str_into_gstr, string_into_gstr, string_with_capacity_into_gstr ); criterion_main!(benches); glib-0.20.9/src/auto/alias.rs000064400000000000000000000005141046102023000140270ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT #[allow(unused_imports)] use crate::auto::*; #[doc(alias = "GDateDay")] pub type DateDay = u8; #[doc(alias = "GDateYear")] pub type DateYear = u16; #[doc(alias = "GTime")] pub type Time = i32; glib-0.20.9/src/auto/checksum.rs000064400000000000000000000025351046102023000145450ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::{ffi, translate::*, ChecksumType}; crate::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Checksum(Boxed); match fn { copy => |ptr| ffi::g_checksum_copy(ptr), free => |ptr| ffi::g_checksum_free(ptr), type_ => || ffi::g_checksum_get_type(), } } impl Checksum { #[doc(alias = "g_checksum_new")] pub fn new(checksum_type: ChecksumType) -> Option { unsafe { from_glib_full(ffi::g_checksum_new(checksum_type.into_glib())) } } #[doc(alias = "g_checksum_reset")] pub fn reset(&mut self) { unsafe { ffi::g_checksum_reset(self.to_glib_none_mut().0); } } #[doc(alias = "g_checksum_update")] pub fn update(&mut self, data: &[u8]) { let length = data.len() as _; unsafe { ffi::g_checksum_update(self.to_glib_none_mut().0, data.to_glib_none().0, length); } } #[doc(alias = "g_checksum_type_get_length")] pub fn type_get_length(checksum_type: ChecksumType) -> isize { unsafe { ffi::g_checksum_type_get_length(checksum_type.into_glib()) } } } unsafe impl Send for Checksum {} unsafe impl Sync for Checksum {} glib-0.20.9/src/auto/constants.rs000064400000000000000000000152001046102023000147500ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::{ffi, GStr}; #[doc(alias = "G_CSET_A_2_Z")] pub static CSET_A_2_Z: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_CSET_A_2_Z) }; #[doc(alias = "G_CSET_DIGITS")] pub static CSET_DIGITS: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_CSET_DIGITS) }; #[doc(alias = "G_CSET_a_2_z")] pub static CSET_a_2_z: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_CSET_a_2_z) }; #[doc(alias = "G_KEY_FILE_DESKTOP_GROUP")] pub static KEY_FILE_DESKTOP_GROUP: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_GROUP) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_ACTIONS")] pub static KEY_FILE_DESKTOP_KEY_ACTIONS: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_ACTIONS) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_CATEGORIES")] pub static KEY_FILE_DESKTOP_KEY_CATEGORIES: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_CATEGORIES) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_COMMENT")] pub static KEY_FILE_DESKTOP_KEY_COMMENT: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_COMMENT) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE")] pub static KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_EXEC")] pub static KEY_FILE_DESKTOP_KEY_EXEC: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_EXEC) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_GENERIC_NAME")] pub static KEY_FILE_DESKTOP_KEY_GENERIC_NAME: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_GENERIC_NAME) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_HIDDEN")] pub static KEY_FILE_DESKTOP_KEY_HIDDEN: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_HIDDEN) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_ICON")] pub static KEY_FILE_DESKTOP_KEY_ICON: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_ICON) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_MIME_TYPE")] pub static KEY_FILE_DESKTOP_KEY_MIME_TYPE: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_MIME_TYPE) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_NAME")] pub static KEY_FILE_DESKTOP_KEY_NAME: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_NAME) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN")] pub static KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY")] pub static KEY_FILE_DESKTOP_KEY_NO_DISPLAY: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN")] pub static KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_PATH")] pub static KEY_FILE_DESKTOP_KEY_PATH: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_PATH) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY")] pub static KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS")] pub static KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_TERMINAL")] pub static KEY_FILE_DESKTOP_KEY_TERMINAL: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_TERMINAL) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_TRY_EXEC")] pub static KEY_FILE_DESKTOP_KEY_TRY_EXEC: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_TRY_EXEC) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_TYPE")] pub static KEY_FILE_DESKTOP_KEY_TYPE: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_TYPE) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_URL")] pub static KEY_FILE_DESKTOP_KEY_URL: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_URL) }; #[doc(alias = "G_KEY_FILE_DESKTOP_KEY_VERSION")] pub static KEY_FILE_DESKTOP_KEY_VERSION: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_KEY_VERSION) }; #[doc(alias = "G_KEY_FILE_DESKTOP_TYPE_APPLICATION")] pub static KEY_FILE_DESKTOP_TYPE_APPLICATION: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_TYPE_APPLICATION) }; #[doc(alias = "G_KEY_FILE_DESKTOP_TYPE_DIRECTORY")] pub static KEY_FILE_DESKTOP_TYPE_DIRECTORY: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_TYPE_DIRECTORY) }; #[doc(alias = "G_KEY_FILE_DESKTOP_TYPE_LINK")] pub static KEY_FILE_DESKTOP_TYPE_LINK: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_KEY_FILE_DESKTOP_TYPE_LINK) }; #[doc(alias = "G_OPTION_REMAINING")] pub static OPTION_REMAINING: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_OPTION_REMAINING) }; #[doc(alias = "G_STR_DELIMITERS")] pub static STR_DELIMITERS: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_STR_DELIMITERS) }; #[cfg(feature = "v2_60")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_60")))] #[doc(alias = "G_TEST_OPTION_ISOLATE_DIRS")] pub static TEST_OPTION_ISOLATE_DIRS: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_TEST_OPTION_ISOLATE_DIRS) }; #[cfg(feature = "v2_84")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_84")))] #[doc(alias = "G_TEST_OPTION_NONFATAL_ASSERTIONS")] pub static TEST_OPTION_NONFATAL_ASSERTIONS: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_TEST_OPTION_NONFATAL_ASSERTIONS) }; #[cfg(feature = "v2_84")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_84")))] #[doc(alias = "G_TEST_OPTION_NO_PRGNAME")] pub static TEST_OPTION_NO_PRGNAME: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_TEST_OPTION_NO_PRGNAME) }; #[doc(alias = "G_URI_RESERVED_CHARS_GENERIC_DELIMITERS")] pub static URI_RESERVED_CHARS_GENERIC_DELIMITERS: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_URI_RESERVED_CHARS_GENERIC_DELIMITERS) }; #[doc(alias = "G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS")] pub static URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS: &GStr = unsafe { GStr::from_utf8_with_nul_unchecked(ffi::G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS) }; glib-0.20.9/src/auto/date_time.rs000064400000000000000000000421231046102023000146730ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::{ffi, translate::*, BoolError, TimeSpan, TimeZone}; crate::wrapper! { #[derive(Debug)] pub struct DateTime(Shared); match fn { ref => |ptr| ffi::g_date_time_ref(ptr), unref => |ptr| ffi::g_date_time_unref(ptr), type_ => || ffi::g_date_time_get_type(), } } impl DateTime { #[doc(alias = "g_date_time_new")] pub fn new( tz: &TimeZone, year: i32, month: i32, day: i32, hour: i32, minute: i32, seconds: f64, ) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new( tz.to_glib_none().0, year, month, day, hour, minute, seconds, )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_new_from_iso8601")] #[doc(alias = "new_from_iso8601")] pub fn from_iso8601(text: &str, default_tz: Option<&TimeZone>) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new_from_iso8601( text.to_glib_none().0, default_tz.to_glib_none().0, )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } //#[cfg_attr(feature = "v2_62", deprecated = "Since 2.62")] //#[allow(deprecated)] //#[doc(alias = "g_date_time_new_from_timeval_local")] //#[doc(alias = "new_from_timeval_local")] //pub fn from_timeval_local(tv: /*Ignored*/&TimeVal) -> Result { // unsafe { TODO: call ffi:g_date_time_new_from_timeval_local() } //} //#[cfg_attr(feature = "v2_62", deprecated = "Since 2.62")] //#[allow(deprecated)] //#[doc(alias = "g_date_time_new_from_timeval_utc")] //#[doc(alias = "new_from_timeval_utc")] //pub fn from_timeval_utc(tv: /*Ignored*/&TimeVal) -> Result { // unsafe { TODO: call ffi:g_date_time_new_from_timeval_utc() } //} #[doc(alias = "g_date_time_new_from_unix_local")] #[doc(alias = "new_from_unix_local")] pub fn from_unix_local(t: i64) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new_from_unix_local(t)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[cfg(feature = "v2_80")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_80")))] #[doc(alias = "g_date_time_new_from_unix_local_usec")] #[doc(alias = "new_from_unix_local_usec")] pub fn from_unix_local_usec(usecs: i64) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new_from_unix_local_usec(usecs)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_new_from_unix_utc")] #[doc(alias = "new_from_unix_utc")] pub fn from_unix_utc(t: i64) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new_from_unix_utc(t)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[cfg(feature = "v2_80")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_80")))] #[doc(alias = "g_date_time_new_from_unix_utc_usec")] #[doc(alias = "new_from_unix_utc_usec")] pub fn from_unix_utc_usec(usecs: i64) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new_from_unix_utc_usec(usecs)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_new_local")] #[doc(alias = "new_local")] pub fn from_local( year: i32, month: i32, day: i32, hour: i32, minute: i32, seconds: f64, ) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new_local( year, month, day, hour, minute, seconds, )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_new_now")] #[doc(alias = "new_now")] pub fn now(tz: &TimeZone) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new_now(tz.to_glib_none().0)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_new_now_local")] #[doc(alias = "new_now_local")] pub fn now_local() -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new_now_local()) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_new_now_utc")] #[doc(alias = "new_now_utc")] pub fn now_utc() -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new_now_utc()) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_new_utc")] #[doc(alias = "new_utc")] pub fn from_utc( year: i32, month: i32, day: i32, hour: i32, minute: i32, seconds: f64, ) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_new_utc( year, month, day, hour, minute, seconds, )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_add")] pub fn add(&self, timespan: TimeSpan) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_add( self.to_glib_none().0, timespan.into_glib(), )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_add_days")] pub fn add_days(&self, days: i32) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_add_days(self.to_glib_none().0, days)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_add_full")] pub fn add_full( &self, years: i32, months: i32, days: i32, hours: i32, minutes: i32, seconds: f64, ) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_add_full( self.to_glib_none().0, years, months, days, hours, minutes, seconds, )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_add_hours")] pub fn add_hours(&self, hours: i32) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_add_hours(self.to_glib_none().0, hours)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_add_minutes")] pub fn add_minutes(&self, minutes: i32) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_add_minutes( self.to_glib_none().0, minutes, )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_add_months")] pub fn add_months(&self, months: i32) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_add_months(self.to_glib_none().0, months)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_add_seconds")] pub fn add_seconds(&self, seconds: f64) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_add_seconds( self.to_glib_none().0, seconds, )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_add_weeks")] pub fn add_weeks(&self, weeks: i32) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_add_weeks(self.to_glib_none().0, weeks)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_add_years")] pub fn add_years(&self, years: i32) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_add_years(self.to_glib_none().0, years)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_compare")] fn compare(&self, dt2: &DateTime) -> i32 { unsafe { ffi::g_date_time_compare( ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(self).0 as ffi::gconstpointer, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(dt2).0 as ffi::gconstpointer, ) } } #[doc(alias = "g_date_time_difference")] pub fn difference(&self, begin: &DateTime) -> TimeSpan { unsafe { from_glib(ffi::g_date_time_difference( self.to_glib_none().0, begin.to_glib_none().0, )) } } #[doc(alias = "g_date_time_equal")] fn equal(&self, dt2: &DateTime) -> bool { unsafe { from_glib(ffi::g_date_time_equal( ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(self).0 as ffi::gconstpointer, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(dt2).0 as ffi::gconstpointer, )) } } #[doc(alias = "g_date_time_format")] pub fn format(&self, format: &str) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_format( self.to_glib_none().0, format.to_glib_none().0, )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[cfg(feature = "v2_62")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_62")))] #[doc(alias = "g_date_time_format_iso8601")] pub fn format_iso8601(&self) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_format_iso8601(self.to_glib_none().0)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_get_day_of_month")] #[doc(alias = "get_day_of_month")] pub fn day_of_month(&self) -> i32 { unsafe { ffi::g_date_time_get_day_of_month(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_day_of_week")] #[doc(alias = "get_day_of_week")] pub fn day_of_week(&self) -> i32 { unsafe { ffi::g_date_time_get_day_of_week(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_day_of_year")] #[doc(alias = "get_day_of_year")] pub fn day_of_year(&self) -> i32 { unsafe { ffi::g_date_time_get_day_of_year(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_hour")] #[doc(alias = "get_hour")] pub fn hour(&self) -> i32 { unsafe { ffi::g_date_time_get_hour(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_microsecond")] #[doc(alias = "get_microsecond")] pub fn microsecond(&self) -> i32 { unsafe { ffi::g_date_time_get_microsecond(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_minute")] #[doc(alias = "get_minute")] pub fn minute(&self) -> i32 { unsafe { ffi::g_date_time_get_minute(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_month")] #[doc(alias = "get_month")] pub fn month(&self) -> i32 { unsafe { ffi::g_date_time_get_month(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_second")] #[doc(alias = "get_second")] pub fn second(&self) -> i32 { unsafe { ffi::g_date_time_get_second(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_seconds")] #[doc(alias = "get_seconds")] pub fn seconds(&self) -> f64 { unsafe { ffi::g_date_time_get_seconds(self.to_glib_none().0) } } #[cfg(feature = "v2_58")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_58")))] #[doc(alias = "g_date_time_get_timezone")] #[doc(alias = "get_timezone")] pub fn timezone(&self) -> TimeZone { unsafe { from_glib_none(ffi::g_date_time_get_timezone(self.to_glib_none().0)) } } #[doc(alias = "g_date_time_get_timezone_abbreviation")] #[doc(alias = "get_timezone_abbreviation")] pub fn timezone_abbreviation(&self) -> crate::GString { unsafe { from_glib_none(ffi::g_date_time_get_timezone_abbreviation( self.to_glib_none().0, )) } } #[doc(alias = "g_date_time_get_utc_offset")] #[doc(alias = "get_utc_offset")] pub fn utc_offset(&self) -> TimeSpan { unsafe { from_glib(ffi::g_date_time_get_utc_offset(self.to_glib_none().0)) } } #[doc(alias = "g_date_time_get_week_numbering_year")] #[doc(alias = "get_week_numbering_year")] pub fn week_numbering_year(&self) -> i32 { unsafe { ffi::g_date_time_get_week_numbering_year(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_week_of_year")] #[doc(alias = "get_week_of_year")] pub fn week_of_year(&self) -> i32 { unsafe { ffi::g_date_time_get_week_of_year(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_year")] #[doc(alias = "get_year")] pub fn year(&self) -> i32 { unsafe { ffi::g_date_time_get_year(self.to_glib_none().0) } } #[doc(alias = "g_date_time_get_ymd")] #[doc(alias = "get_ymd")] pub fn ymd(&self) -> (i32, i32, i32) { unsafe { let mut year = std::mem::MaybeUninit::uninit(); let mut month = std::mem::MaybeUninit::uninit(); let mut day = std::mem::MaybeUninit::uninit(); ffi::g_date_time_get_ymd( self.to_glib_none().0, year.as_mut_ptr(), month.as_mut_ptr(), day.as_mut_ptr(), ); (year.assume_init(), month.assume_init(), day.assume_init()) } } #[doc(alias = "g_date_time_hash")] fn hash(&self) -> u32 { unsafe { ffi::g_date_time_hash( ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(self).0 as ffi::gconstpointer, ) } } #[doc(alias = "g_date_time_is_daylight_savings")] pub fn is_daylight_savings(&self) -> bool { unsafe { from_glib(ffi::g_date_time_is_daylight_savings(self.to_glib_none().0)) } } #[doc(alias = "g_date_time_to_local")] pub fn to_local(&self) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_to_local(self.to_glib_none().0)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } //#[cfg_attr(feature = "v2_62", deprecated = "Since 2.62")] //#[allow(deprecated)] //#[doc(alias = "g_date_time_to_timeval")] //pub fn to_timeval(&self, tv: /*Ignored*/&mut TimeVal) -> bool { // unsafe { TODO: call ffi:g_date_time_to_timeval() } //} #[doc(alias = "g_date_time_to_timezone")] pub fn to_timezone(&self, tz: &TimeZone) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_to_timezone( self.to_glib_none().0, tz.to_glib_none().0, )) .ok_or_else(|| crate::bool_error!("Invalid date")) } } #[doc(alias = "g_date_time_to_unix")] pub fn to_unix(&self) -> i64 { unsafe { ffi::g_date_time_to_unix(self.to_glib_none().0) } } #[cfg(feature = "v2_80")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_80")))] #[doc(alias = "g_date_time_to_unix_usec")] pub fn to_unix_usec(&self) -> i64 { unsafe { ffi::g_date_time_to_unix_usec(self.to_glib_none().0) } } #[doc(alias = "g_date_time_to_utc")] pub fn to_utc(&self) -> Result { unsafe { Option::<_>::from_glib_full(ffi::g_date_time_to_utc(self.to_glib_none().0)) .ok_or_else(|| crate::bool_error!("Invalid date")) } } } impl PartialOrd for DateTime { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for DateTime { #[inline] fn cmp(&self, other: &Self) -> std::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 std::hash::Hash for DateTime { #[inline] fn hash(&self, state: &mut H) where H: std::hash::Hasher, { std::hash::Hash::hash(&self.hash(), state) } } unsafe impl Send for DateTime {} unsafe impl Sync for DateTime {} glib-0.20.9/src/auto/enums.rs000064400000000000000000002622111046102023000140710ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::{ffi, prelude::*, translate::*}; #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GChecksumType")] pub enum ChecksumType { #[doc(alias = "G_CHECKSUM_MD5")] Md5, #[doc(alias = "G_CHECKSUM_SHA1")] Sha1, #[doc(alias = "G_CHECKSUM_SHA256")] Sha256, #[doc(alias = "G_CHECKSUM_SHA512")] Sha512, #[doc(alias = "G_CHECKSUM_SHA384")] Sha384, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for ChecksumType { type GlibType = ffi::GChecksumType; #[inline] fn into_glib(self) -> ffi::GChecksumType { match self { Self::Md5 => ffi::G_CHECKSUM_MD5, Self::Sha1 => ffi::G_CHECKSUM_SHA1, Self::Sha256 => ffi::G_CHECKSUM_SHA256, Self::Sha512 => ffi::G_CHECKSUM_SHA512, Self::Sha384 => ffi::G_CHECKSUM_SHA384, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for ChecksumType { #[inline] unsafe fn from_glib(value: ffi::GChecksumType) -> Self { match value { ffi::G_CHECKSUM_MD5 => Self::Md5, ffi::G_CHECKSUM_SHA1 => Self::Sha1, ffi::G_CHECKSUM_SHA256 => Self::Sha256, ffi::G_CHECKSUM_SHA512 => Self::Sha512, ffi::G_CHECKSUM_SHA384 => Self::Sha384, value => Self::__Unknown(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GConvertError")] pub enum ConvertError { #[doc(alias = "G_CONVERT_ERROR_NO_CONVERSION")] NoConversion, #[doc(alias = "G_CONVERT_ERROR_ILLEGAL_SEQUENCE")] IllegalSequence, #[doc(alias = "G_CONVERT_ERROR_FAILED")] Failed, #[doc(alias = "G_CONVERT_ERROR_PARTIAL_INPUT")] PartialInput, #[doc(alias = "G_CONVERT_ERROR_BAD_URI")] BadUri, #[doc(alias = "G_CONVERT_ERROR_NOT_ABSOLUTE_PATH")] NotAbsolutePath, #[doc(alias = "G_CONVERT_ERROR_NO_MEMORY")] NoMemory, #[doc(alias = "G_CONVERT_ERROR_EMBEDDED_NUL")] EmbeddedNul, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for ConvertError { type GlibType = ffi::GConvertError; #[inline] fn into_glib(self) -> ffi::GConvertError { match self { Self::NoConversion => ffi::G_CONVERT_ERROR_NO_CONVERSION, Self::IllegalSequence => ffi::G_CONVERT_ERROR_ILLEGAL_SEQUENCE, Self::Failed => ffi::G_CONVERT_ERROR_FAILED, Self::PartialInput => ffi::G_CONVERT_ERROR_PARTIAL_INPUT, Self::BadUri => ffi::G_CONVERT_ERROR_BAD_URI, Self::NotAbsolutePath => ffi::G_CONVERT_ERROR_NOT_ABSOLUTE_PATH, Self::NoMemory => ffi::G_CONVERT_ERROR_NO_MEMORY, Self::EmbeddedNul => ffi::G_CONVERT_ERROR_EMBEDDED_NUL, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for ConvertError { #[inline] unsafe fn from_glib(value: ffi::GConvertError) -> Self { match value { ffi::G_CONVERT_ERROR_NO_CONVERSION => Self::NoConversion, ffi::G_CONVERT_ERROR_ILLEGAL_SEQUENCE => Self::IllegalSequence, ffi::G_CONVERT_ERROR_FAILED => Self::Failed, ffi::G_CONVERT_ERROR_PARTIAL_INPUT => Self::PartialInput, ffi::G_CONVERT_ERROR_BAD_URI => Self::BadUri, ffi::G_CONVERT_ERROR_NOT_ABSOLUTE_PATH => Self::NotAbsolutePath, ffi::G_CONVERT_ERROR_NO_MEMORY => Self::NoMemory, ffi::G_CONVERT_ERROR_EMBEDDED_NUL => Self::EmbeddedNul, value => Self::__Unknown(value), } } } impl crate::error::ErrorDomain for ConvertError { #[inline] fn domain() -> crate::Quark { unsafe { from_glib(ffi::g_convert_error_quark()) } } #[inline] fn code(self) -> i32 { self.into_glib() } #[inline] #[allow(clippy::match_single_binding)] fn from(code: i32) -> Option { match unsafe { from_glib(code) } { Self::__Unknown(_) => Some(Self::Failed), value => Some(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GDateMonth")] pub enum DateMonth { #[doc(alias = "G_DATE_BAD_MONTH")] BadMonth, #[doc(alias = "G_DATE_JANUARY")] January, #[doc(alias = "G_DATE_FEBRUARY")] February, #[doc(alias = "G_DATE_MARCH")] March, #[doc(alias = "G_DATE_APRIL")] April, #[doc(alias = "G_DATE_MAY")] May, #[doc(alias = "G_DATE_JUNE")] June, #[doc(alias = "G_DATE_JULY")] July, #[doc(alias = "G_DATE_AUGUST")] August, #[doc(alias = "G_DATE_SEPTEMBER")] September, #[doc(alias = "G_DATE_OCTOBER")] October, #[doc(alias = "G_DATE_NOVEMBER")] November, #[doc(alias = "G_DATE_DECEMBER")] December, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for DateMonth { type GlibType = ffi::GDateMonth; fn into_glib(self) -> ffi::GDateMonth { match self { Self::BadMonth => ffi::G_DATE_BAD_MONTH, Self::January => ffi::G_DATE_JANUARY, Self::February => ffi::G_DATE_FEBRUARY, Self::March => ffi::G_DATE_MARCH, Self::April => ffi::G_DATE_APRIL, Self::May => ffi::G_DATE_MAY, Self::June => ffi::G_DATE_JUNE, Self::July => ffi::G_DATE_JULY, Self::August => ffi::G_DATE_AUGUST, Self::September => ffi::G_DATE_SEPTEMBER, Self::October => ffi::G_DATE_OCTOBER, Self::November => ffi::G_DATE_NOVEMBER, Self::December => ffi::G_DATE_DECEMBER, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for DateMonth { unsafe fn from_glib(value: ffi::GDateMonth) -> Self { match value { ffi::G_DATE_BAD_MONTH => Self::BadMonth, ffi::G_DATE_JANUARY => Self::January, ffi::G_DATE_FEBRUARY => Self::February, ffi::G_DATE_MARCH => Self::March, ffi::G_DATE_APRIL => Self::April, ffi::G_DATE_MAY => Self::May, ffi::G_DATE_JUNE => Self::June, ffi::G_DATE_JULY => Self::July, ffi::G_DATE_AUGUST => Self::August, ffi::G_DATE_SEPTEMBER => Self::September, ffi::G_DATE_OCTOBER => Self::October, ffi::G_DATE_NOVEMBER => Self::November, ffi::G_DATE_DECEMBER => Self::December, value => Self::__Unknown(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GDateWeekday")] pub enum DateWeekday { #[doc(alias = "G_DATE_BAD_WEEKDAY")] BadWeekday, #[doc(alias = "G_DATE_MONDAY")] Monday, #[doc(alias = "G_DATE_TUESDAY")] Tuesday, #[doc(alias = "G_DATE_WEDNESDAY")] Wednesday, #[doc(alias = "G_DATE_THURSDAY")] Thursday, #[doc(alias = "G_DATE_FRIDAY")] Friday, #[doc(alias = "G_DATE_SATURDAY")] Saturday, #[doc(alias = "G_DATE_SUNDAY")] Sunday, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for DateWeekday { type GlibType = ffi::GDateWeekday; #[inline] fn into_glib(self) -> ffi::GDateWeekday { match self { Self::BadWeekday => ffi::G_DATE_BAD_WEEKDAY, Self::Monday => ffi::G_DATE_MONDAY, Self::Tuesday => ffi::G_DATE_TUESDAY, Self::Wednesday => ffi::G_DATE_WEDNESDAY, Self::Thursday => ffi::G_DATE_THURSDAY, Self::Friday => ffi::G_DATE_FRIDAY, Self::Saturday => ffi::G_DATE_SATURDAY, Self::Sunday => ffi::G_DATE_SUNDAY, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for DateWeekday { #[inline] unsafe fn from_glib(value: ffi::GDateWeekday) -> Self { match value { ffi::G_DATE_BAD_WEEKDAY => Self::BadWeekday, ffi::G_DATE_MONDAY => Self::Monday, ffi::G_DATE_TUESDAY => Self::Tuesday, ffi::G_DATE_WEDNESDAY => Self::Wednesday, ffi::G_DATE_THURSDAY => Self::Thursday, ffi::G_DATE_FRIDAY => Self::Friday, ffi::G_DATE_SATURDAY => Self::Saturday, ffi::G_DATE_SUNDAY => Self::Sunday, value => Self::__Unknown(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GFileError")] pub enum FileError { #[doc(alias = "G_FILE_ERROR_EXIST")] Exist, #[doc(alias = "G_FILE_ERROR_ISDIR")] Isdir, #[doc(alias = "G_FILE_ERROR_ACCES")] Acces, #[doc(alias = "G_FILE_ERROR_NAMETOOLONG")] Nametoolong, #[doc(alias = "G_FILE_ERROR_NOENT")] Noent, #[doc(alias = "G_FILE_ERROR_NOTDIR")] Notdir, #[doc(alias = "G_FILE_ERROR_NXIO")] Nxio, #[doc(alias = "G_FILE_ERROR_NODEV")] Nodev, #[doc(alias = "G_FILE_ERROR_ROFS")] Rofs, #[doc(alias = "G_FILE_ERROR_TXTBSY")] Txtbsy, #[doc(alias = "G_FILE_ERROR_FAULT")] Fault, #[doc(alias = "G_FILE_ERROR_LOOP")] Loop, #[doc(alias = "G_FILE_ERROR_NOSPC")] Nospc, #[doc(alias = "G_FILE_ERROR_NOMEM")] Nomem, #[doc(alias = "G_FILE_ERROR_MFILE")] Mfile, #[doc(alias = "G_FILE_ERROR_NFILE")] Nfile, #[doc(alias = "G_FILE_ERROR_BADF")] Badf, #[doc(alias = "G_FILE_ERROR_INVAL")] Inval, #[doc(alias = "G_FILE_ERROR_PIPE")] Pipe, #[doc(alias = "G_FILE_ERROR_AGAIN")] Again, #[doc(alias = "G_FILE_ERROR_INTR")] Intr, #[doc(alias = "G_FILE_ERROR_IO")] Io, #[doc(alias = "G_FILE_ERROR_PERM")] Perm, #[doc(alias = "G_FILE_ERROR_NOSYS")] Nosys, #[doc(alias = "G_FILE_ERROR_FAILED")] Failed, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for FileError { type GlibType = ffi::GFileError; fn into_glib(self) -> ffi::GFileError { match self { Self::Exist => ffi::G_FILE_ERROR_EXIST, Self::Isdir => ffi::G_FILE_ERROR_ISDIR, Self::Acces => ffi::G_FILE_ERROR_ACCES, Self::Nametoolong => ffi::G_FILE_ERROR_NAMETOOLONG, Self::Noent => ffi::G_FILE_ERROR_NOENT, Self::Notdir => ffi::G_FILE_ERROR_NOTDIR, Self::Nxio => ffi::G_FILE_ERROR_NXIO, Self::Nodev => ffi::G_FILE_ERROR_NODEV, Self::Rofs => ffi::G_FILE_ERROR_ROFS, Self::Txtbsy => ffi::G_FILE_ERROR_TXTBSY, Self::Fault => ffi::G_FILE_ERROR_FAULT, Self::Loop => ffi::G_FILE_ERROR_LOOP, Self::Nospc => ffi::G_FILE_ERROR_NOSPC, Self::Nomem => ffi::G_FILE_ERROR_NOMEM, Self::Mfile => ffi::G_FILE_ERROR_MFILE, Self::Nfile => ffi::G_FILE_ERROR_NFILE, Self::Badf => ffi::G_FILE_ERROR_BADF, Self::Inval => ffi::G_FILE_ERROR_INVAL, Self::Pipe => ffi::G_FILE_ERROR_PIPE, Self::Again => ffi::G_FILE_ERROR_AGAIN, Self::Intr => ffi::G_FILE_ERROR_INTR, Self::Io => ffi::G_FILE_ERROR_IO, Self::Perm => ffi::G_FILE_ERROR_PERM, Self::Nosys => ffi::G_FILE_ERROR_NOSYS, Self::Failed => ffi::G_FILE_ERROR_FAILED, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for FileError { unsafe fn from_glib(value: ffi::GFileError) -> Self { match value { ffi::G_FILE_ERROR_EXIST => Self::Exist, ffi::G_FILE_ERROR_ISDIR => Self::Isdir, ffi::G_FILE_ERROR_ACCES => Self::Acces, ffi::G_FILE_ERROR_NAMETOOLONG => Self::Nametoolong, ffi::G_FILE_ERROR_NOENT => Self::Noent, ffi::G_FILE_ERROR_NOTDIR => Self::Notdir, ffi::G_FILE_ERROR_NXIO => Self::Nxio, ffi::G_FILE_ERROR_NODEV => Self::Nodev, ffi::G_FILE_ERROR_ROFS => Self::Rofs, ffi::G_FILE_ERROR_TXTBSY => Self::Txtbsy, ffi::G_FILE_ERROR_FAULT => Self::Fault, ffi::G_FILE_ERROR_LOOP => Self::Loop, ffi::G_FILE_ERROR_NOSPC => Self::Nospc, ffi::G_FILE_ERROR_NOMEM => Self::Nomem, ffi::G_FILE_ERROR_MFILE => Self::Mfile, ffi::G_FILE_ERROR_NFILE => Self::Nfile, ffi::G_FILE_ERROR_BADF => Self::Badf, ffi::G_FILE_ERROR_INVAL => Self::Inval, ffi::G_FILE_ERROR_PIPE => Self::Pipe, ffi::G_FILE_ERROR_AGAIN => Self::Again, ffi::G_FILE_ERROR_INTR => Self::Intr, ffi::G_FILE_ERROR_IO => Self::Io, ffi::G_FILE_ERROR_PERM => Self::Perm, ffi::G_FILE_ERROR_NOSYS => Self::Nosys, ffi::G_FILE_ERROR_FAILED => Self::Failed, value => Self::__Unknown(value), } } } impl crate::error::ErrorDomain for FileError { #[inline] fn domain() -> crate::Quark { unsafe { from_glib(ffi::g_file_error_quark()) } } #[inline] fn code(self) -> i32 { self.into_glib() } #[inline] #[allow(clippy::match_single_binding)] fn from(code: i32) -> Option { match unsafe { from_glib(code) } { Self::__Unknown(_) => Some(Self::Failed), value => Some(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GKeyFileError")] pub enum KeyFileError { #[doc(alias = "G_KEY_FILE_ERROR_UNKNOWN_ENCODING")] UnknownEncoding, #[doc(alias = "G_KEY_FILE_ERROR_PARSE")] Parse, #[doc(alias = "G_KEY_FILE_ERROR_NOT_FOUND")] NotFound, #[doc(alias = "G_KEY_FILE_ERROR_KEY_NOT_FOUND")] KeyNotFound, #[doc(alias = "G_KEY_FILE_ERROR_GROUP_NOT_FOUND")] GroupNotFound, #[doc(alias = "G_KEY_FILE_ERROR_INVALID_VALUE")] InvalidValue, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for KeyFileError { type GlibType = ffi::GKeyFileError; #[inline] fn into_glib(self) -> ffi::GKeyFileError { match self { Self::UnknownEncoding => ffi::G_KEY_FILE_ERROR_UNKNOWN_ENCODING, Self::Parse => ffi::G_KEY_FILE_ERROR_PARSE, Self::NotFound => ffi::G_KEY_FILE_ERROR_NOT_FOUND, Self::KeyNotFound => ffi::G_KEY_FILE_ERROR_KEY_NOT_FOUND, Self::GroupNotFound => ffi::G_KEY_FILE_ERROR_GROUP_NOT_FOUND, Self::InvalidValue => ffi::G_KEY_FILE_ERROR_INVALID_VALUE, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for KeyFileError { #[inline] unsafe fn from_glib(value: ffi::GKeyFileError) -> Self { match value { ffi::G_KEY_FILE_ERROR_UNKNOWN_ENCODING => Self::UnknownEncoding, ffi::G_KEY_FILE_ERROR_PARSE => Self::Parse, ffi::G_KEY_FILE_ERROR_NOT_FOUND => Self::NotFound, ffi::G_KEY_FILE_ERROR_KEY_NOT_FOUND => Self::KeyNotFound, ffi::G_KEY_FILE_ERROR_GROUP_NOT_FOUND => Self::GroupNotFound, ffi::G_KEY_FILE_ERROR_INVALID_VALUE => Self::InvalidValue, value => Self::__Unknown(value), } } } impl crate::error::ErrorDomain for KeyFileError { #[inline] fn domain() -> crate::Quark { unsafe { from_glib(ffi::g_key_file_error_quark()) } } #[inline] fn code(self) -> i32 { self.into_glib() } #[inline] #[allow(clippy::match_single_binding)] fn from(code: i32) -> Option { match unsafe { from_glib(code) } { value => Some(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GLogWriterOutput")] pub enum LogWriterOutput { #[doc(alias = "G_LOG_WRITER_HANDLED")] Handled, #[doc(alias = "G_LOG_WRITER_UNHANDLED")] Unhandled, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for LogWriterOutput { type GlibType = ffi::GLogWriterOutput; #[inline] fn into_glib(self) -> ffi::GLogWriterOutput { match self { Self::Handled => ffi::G_LOG_WRITER_HANDLED, Self::Unhandled => ffi::G_LOG_WRITER_UNHANDLED, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for LogWriterOutput { #[inline] unsafe fn from_glib(value: ffi::GLogWriterOutput) -> Self { match value { ffi::G_LOG_WRITER_HANDLED => Self::Handled, ffi::G_LOG_WRITER_UNHANDLED => Self::Unhandled, value => Self::__Unknown(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GMarkupError")] pub enum MarkupError { #[doc(alias = "G_MARKUP_ERROR_BAD_UTF8")] BadUtf8, #[doc(alias = "G_MARKUP_ERROR_EMPTY")] Empty, #[doc(alias = "G_MARKUP_ERROR_PARSE")] Parse, #[doc(alias = "G_MARKUP_ERROR_UNKNOWN_ELEMENT")] UnknownElement, #[doc(alias = "G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE")] UnknownAttribute, #[doc(alias = "G_MARKUP_ERROR_INVALID_CONTENT")] InvalidContent, #[doc(alias = "G_MARKUP_ERROR_MISSING_ATTRIBUTE")] MissingAttribute, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for MarkupError { type GlibType = ffi::GMarkupError; #[inline] fn into_glib(self) -> ffi::GMarkupError { match self { Self::BadUtf8 => ffi::G_MARKUP_ERROR_BAD_UTF8, Self::Empty => ffi::G_MARKUP_ERROR_EMPTY, Self::Parse => ffi::G_MARKUP_ERROR_PARSE, Self::UnknownElement => ffi::G_MARKUP_ERROR_UNKNOWN_ELEMENT, Self::UnknownAttribute => ffi::G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, Self::InvalidContent => ffi::G_MARKUP_ERROR_INVALID_CONTENT, Self::MissingAttribute => ffi::G_MARKUP_ERROR_MISSING_ATTRIBUTE, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for MarkupError { #[inline] unsafe fn from_glib(value: ffi::GMarkupError) -> Self { match value { ffi::G_MARKUP_ERROR_BAD_UTF8 => Self::BadUtf8, ffi::G_MARKUP_ERROR_EMPTY => Self::Empty, ffi::G_MARKUP_ERROR_PARSE => Self::Parse, ffi::G_MARKUP_ERROR_UNKNOWN_ELEMENT => Self::UnknownElement, ffi::G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE => Self::UnknownAttribute, ffi::G_MARKUP_ERROR_INVALID_CONTENT => Self::InvalidContent, ffi::G_MARKUP_ERROR_MISSING_ATTRIBUTE => Self::MissingAttribute, value => Self::__Unknown(value), } } } impl crate::error::ErrorDomain for MarkupError { #[inline] fn domain() -> crate::Quark { unsafe { from_glib(ffi::g_markup_error_quark()) } } #[inline] fn code(self) -> i32 { self.into_glib() } #[inline] #[allow(clippy::match_single_binding)] fn from(code: i32) -> Option { match unsafe { from_glib(code) } { value => Some(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GNormalizeMode")] pub enum NormalizeMode { #[doc(alias = "G_NORMALIZE_DEFAULT")] Default, #[doc(alias = "G_NORMALIZE_DEFAULT_COMPOSE")] DefaultCompose, #[doc(alias = "G_NORMALIZE_ALL")] All, #[doc(alias = "G_NORMALIZE_ALL_COMPOSE")] AllCompose, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for NormalizeMode { type GlibType = ffi::GNormalizeMode; #[inline] fn into_glib(self) -> ffi::GNormalizeMode { match self { Self::Default => ffi::G_NORMALIZE_DEFAULT, Self::DefaultCompose => ffi::G_NORMALIZE_DEFAULT_COMPOSE, Self::All => ffi::G_NORMALIZE_ALL, Self::AllCompose => ffi::G_NORMALIZE_ALL_COMPOSE, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for NormalizeMode { #[inline] unsafe fn from_glib(value: ffi::GNormalizeMode) -> Self { match value { ffi::G_NORMALIZE_DEFAULT => Self::Default, ffi::G_NORMALIZE_DEFAULT_COMPOSE => Self::DefaultCompose, ffi::G_NORMALIZE_ALL => Self::All, ffi::G_NORMALIZE_ALL_COMPOSE => Self::AllCompose, value => Self::__Unknown(value), } } } impl StaticType for NormalizeMode { #[inline] #[doc(alias = "g_normalize_mode_get_type")] fn static_type() -> crate::Type { unsafe { from_glib(ffi::g_normalize_mode_get_type()) } } } impl crate::HasParamSpec for NormalizeMode { type ParamSpec = crate::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> crate::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl crate::value::ValueType for NormalizeMode { type Type = Self; } unsafe impl<'a> crate::value::FromValue<'a> for NormalizeMode { type Checker = crate::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a crate::Value) -> Self { from_glib(crate::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for NormalizeMode { #[inline] fn to_value(&self) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { crate::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> crate::Type { Self::static_type() } } impl From for crate::Value { #[inline] fn from(v: NormalizeMode) -> Self { ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GOptionArg")] pub enum OptionArg { #[doc(alias = "G_OPTION_ARG_NONE")] None, #[doc(alias = "G_OPTION_ARG_STRING")] String, #[doc(alias = "G_OPTION_ARG_INT")] Int, #[doc(alias = "G_OPTION_ARG_CALLBACK")] Callback, #[doc(alias = "G_OPTION_ARG_FILENAME")] Filename, #[doc(alias = "G_OPTION_ARG_STRING_ARRAY")] StringArray, #[doc(alias = "G_OPTION_ARG_FILENAME_ARRAY")] FilenameArray, #[doc(alias = "G_OPTION_ARG_DOUBLE")] Double, #[doc(alias = "G_OPTION_ARG_INT64")] Int64, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for OptionArg { type GlibType = ffi::GOptionArg; #[inline] fn into_glib(self) -> ffi::GOptionArg { match self { Self::None => ffi::G_OPTION_ARG_NONE, Self::String => ffi::G_OPTION_ARG_STRING, Self::Int => ffi::G_OPTION_ARG_INT, Self::Callback => ffi::G_OPTION_ARG_CALLBACK, Self::Filename => ffi::G_OPTION_ARG_FILENAME, Self::StringArray => ffi::G_OPTION_ARG_STRING_ARRAY, Self::FilenameArray => ffi::G_OPTION_ARG_FILENAME_ARRAY, Self::Double => ffi::G_OPTION_ARG_DOUBLE, Self::Int64 => ffi::G_OPTION_ARG_INT64, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for OptionArg { #[inline] unsafe fn from_glib(value: ffi::GOptionArg) -> Self { match value { ffi::G_OPTION_ARG_NONE => Self::None, ffi::G_OPTION_ARG_STRING => Self::String, ffi::G_OPTION_ARG_INT => Self::Int, ffi::G_OPTION_ARG_CALLBACK => Self::Callback, ffi::G_OPTION_ARG_FILENAME => Self::Filename, ffi::G_OPTION_ARG_STRING_ARRAY => Self::StringArray, ffi::G_OPTION_ARG_FILENAME_ARRAY => Self::FilenameArray, ffi::G_OPTION_ARG_DOUBLE => Self::Double, ffi::G_OPTION_ARG_INT64 => Self::Int64, value => Self::__Unknown(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GSeekType")] pub enum SeekType { #[doc(alias = "G_SEEK_CUR")] Cur, #[doc(alias = "G_SEEK_SET")] Set, #[doc(alias = "G_SEEK_END")] End, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for SeekType { type GlibType = ffi::GSeekType; #[inline] fn into_glib(self) -> ffi::GSeekType { match self { Self::Cur => ffi::G_SEEK_CUR, Self::Set => ffi::G_SEEK_SET, Self::End => ffi::G_SEEK_END, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for SeekType { #[inline] unsafe fn from_glib(value: ffi::GSeekType) -> Self { match value { ffi::G_SEEK_CUR => Self::Cur, ffi::G_SEEK_SET => Self::Set, ffi::G_SEEK_END => Self::End, value => Self::__Unknown(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GTimeType")] pub enum TimeType { #[doc(alias = "G_TIME_TYPE_STANDARD")] Standard, #[doc(alias = "G_TIME_TYPE_DAYLIGHT")] Daylight, #[doc(alias = "G_TIME_TYPE_UNIVERSAL")] Universal, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for TimeType { type GlibType = ffi::GTimeType; #[inline] fn into_glib(self) -> ffi::GTimeType { match self { Self::Standard => ffi::G_TIME_TYPE_STANDARD, Self::Daylight => ffi::G_TIME_TYPE_DAYLIGHT, Self::Universal => ffi::G_TIME_TYPE_UNIVERSAL, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for TimeType { #[inline] unsafe fn from_glib(value: ffi::GTimeType) -> Self { match value { ffi::G_TIME_TYPE_STANDARD => Self::Standard, ffi::G_TIME_TYPE_DAYLIGHT => Self::Daylight, ffi::G_TIME_TYPE_UNIVERSAL => Self::Universal, value => Self::__Unknown(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GUnicodeBreakType")] pub enum UnicodeBreakType { #[doc(alias = "G_UNICODE_BREAK_MANDATORY")] Mandatory, #[doc(alias = "G_UNICODE_BREAK_CARRIAGE_RETURN")] CarriageReturn, #[doc(alias = "G_UNICODE_BREAK_LINE_FEED")] LineFeed, #[doc(alias = "G_UNICODE_BREAK_COMBINING_MARK")] CombiningMark, #[doc(alias = "G_UNICODE_BREAK_SURROGATE")] Surrogate, #[doc(alias = "G_UNICODE_BREAK_ZERO_WIDTH_SPACE")] ZeroWidthSpace, #[doc(alias = "G_UNICODE_BREAK_INSEPARABLE")] Inseparable, #[doc(alias = "G_UNICODE_BREAK_NON_BREAKING_GLUE")] NonBreakingGlue, #[doc(alias = "G_UNICODE_BREAK_CONTINGENT")] Contingent, #[doc(alias = "G_UNICODE_BREAK_SPACE")] Space, #[doc(alias = "G_UNICODE_BREAK_AFTER")] After, #[doc(alias = "G_UNICODE_BREAK_BEFORE")] Before, #[doc(alias = "G_UNICODE_BREAK_BEFORE_AND_AFTER")] BeforeAndAfter, #[doc(alias = "G_UNICODE_BREAK_HYPHEN")] Hyphen, #[doc(alias = "G_UNICODE_BREAK_NON_STARTER")] NonStarter, #[doc(alias = "G_UNICODE_BREAK_OPEN_PUNCTUATION")] OpenPunctuation, #[doc(alias = "G_UNICODE_BREAK_CLOSE_PUNCTUATION")] ClosePunctuation, #[doc(alias = "G_UNICODE_BREAK_QUOTATION")] Quotation, #[doc(alias = "G_UNICODE_BREAK_EXCLAMATION")] Exclamation, #[doc(alias = "G_UNICODE_BREAK_IDEOGRAPHIC")] Ideographic, #[doc(alias = "G_UNICODE_BREAK_NUMERIC")] Numeric, #[doc(alias = "G_UNICODE_BREAK_INFIX_SEPARATOR")] InfixSeparator, #[doc(alias = "G_UNICODE_BREAK_SYMBOL")] Symbol, #[doc(alias = "G_UNICODE_BREAK_ALPHABETIC")] Alphabetic, #[doc(alias = "G_UNICODE_BREAK_PREFIX")] Prefix, #[doc(alias = "G_UNICODE_BREAK_POSTFIX")] Postfix, #[doc(alias = "G_UNICODE_BREAK_COMPLEX_CONTEXT")] ComplexContext, #[doc(alias = "G_UNICODE_BREAK_AMBIGUOUS")] Ambiguous, #[doc(alias = "G_UNICODE_BREAK_UNKNOWN")] Unknown, #[doc(alias = "G_UNICODE_BREAK_NEXT_LINE")] NextLine, #[doc(alias = "G_UNICODE_BREAK_WORD_JOINER")] WordJoiner, #[doc(alias = "G_UNICODE_BREAK_HANGUL_L_JAMO")] HangulLJamo, #[doc(alias = "G_UNICODE_BREAK_HANGUL_V_JAMO")] HangulVJamo, #[doc(alias = "G_UNICODE_BREAK_HANGUL_T_JAMO")] HangulTJamo, #[doc(alias = "G_UNICODE_BREAK_HANGUL_LV_SYLLABLE")] HangulLvSyllable, #[doc(alias = "G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE")] HangulLvtSyllable, #[doc(alias = "G_UNICODE_BREAK_CLOSE_PARENTHESIS")] CloseParenthesis, #[doc(alias = "G_UNICODE_BREAK_CONDITIONAL_JAPANESE_STARTER")] ConditionalJapaneseStarter, #[doc(alias = "G_UNICODE_BREAK_HEBREW_LETTER")] HebrewLetter, #[doc(alias = "G_UNICODE_BREAK_REGIONAL_INDICATOR")] RegionalIndicator, #[doc(alias = "G_UNICODE_BREAK_EMOJI_BASE")] EmojiBase, #[doc(alias = "G_UNICODE_BREAK_EMOJI_MODIFIER")] EmojiModifier, #[doc(alias = "G_UNICODE_BREAK_ZERO_WIDTH_JOINER")] ZeroWidthJoiner, #[cfg(feature = "v2_80")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_80")))] #[doc(alias = "G_UNICODE_BREAK_AKSARA")] Aksara, #[cfg(feature = "v2_80")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_80")))] #[doc(alias = "G_UNICODE_BREAK_AKSARA_PRE_BASE")] AksaraPreBase, #[cfg(feature = "v2_80")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_80")))] #[doc(alias = "G_UNICODE_BREAK_AKSARA_START")] AksaraStart, #[cfg(feature = "v2_80")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_80")))] #[doc(alias = "G_UNICODE_BREAK_VIRAMA_FINAL")] ViramaFinal, #[cfg(feature = "v2_80")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_80")))] #[doc(alias = "G_UNICODE_BREAK_VIRAMA")] Virama, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for UnicodeBreakType { type GlibType = ffi::GUnicodeBreakType; fn into_glib(self) -> ffi::GUnicodeBreakType { match self { Self::Mandatory => ffi::G_UNICODE_BREAK_MANDATORY, Self::CarriageReturn => ffi::G_UNICODE_BREAK_CARRIAGE_RETURN, Self::LineFeed => ffi::G_UNICODE_BREAK_LINE_FEED, Self::CombiningMark => ffi::G_UNICODE_BREAK_COMBINING_MARK, Self::Surrogate => ffi::G_UNICODE_BREAK_SURROGATE, Self::ZeroWidthSpace => ffi::G_UNICODE_BREAK_ZERO_WIDTH_SPACE, Self::Inseparable => ffi::G_UNICODE_BREAK_INSEPARABLE, Self::NonBreakingGlue => ffi::G_UNICODE_BREAK_NON_BREAKING_GLUE, Self::Contingent => ffi::G_UNICODE_BREAK_CONTINGENT, Self::Space => ffi::G_UNICODE_BREAK_SPACE, Self::After => ffi::G_UNICODE_BREAK_AFTER, Self::Before => ffi::G_UNICODE_BREAK_BEFORE, Self::BeforeAndAfter => ffi::G_UNICODE_BREAK_BEFORE_AND_AFTER, Self::Hyphen => ffi::G_UNICODE_BREAK_HYPHEN, Self::NonStarter => ffi::G_UNICODE_BREAK_NON_STARTER, Self::OpenPunctuation => ffi::G_UNICODE_BREAK_OPEN_PUNCTUATION, Self::ClosePunctuation => ffi::G_UNICODE_BREAK_CLOSE_PUNCTUATION, Self::Quotation => ffi::G_UNICODE_BREAK_QUOTATION, Self::Exclamation => ffi::G_UNICODE_BREAK_EXCLAMATION, Self::Ideographic => ffi::G_UNICODE_BREAK_IDEOGRAPHIC, Self::Numeric => ffi::G_UNICODE_BREAK_NUMERIC, Self::InfixSeparator => ffi::G_UNICODE_BREAK_INFIX_SEPARATOR, Self::Symbol => ffi::G_UNICODE_BREAK_SYMBOL, Self::Alphabetic => ffi::G_UNICODE_BREAK_ALPHABETIC, Self::Prefix => ffi::G_UNICODE_BREAK_PREFIX, Self::Postfix => ffi::G_UNICODE_BREAK_POSTFIX, Self::ComplexContext => ffi::G_UNICODE_BREAK_COMPLEX_CONTEXT, Self::Ambiguous => ffi::G_UNICODE_BREAK_AMBIGUOUS, Self::Unknown => ffi::G_UNICODE_BREAK_UNKNOWN, Self::NextLine => ffi::G_UNICODE_BREAK_NEXT_LINE, Self::WordJoiner => ffi::G_UNICODE_BREAK_WORD_JOINER, Self::HangulLJamo => ffi::G_UNICODE_BREAK_HANGUL_L_JAMO, Self::HangulVJamo => ffi::G_UNICODE_BREAK_HANGUL_V_JAMO, Self::HangulTJamo => ffi::G_UNICODE_BREAK_HANGUL_T_JAMO, Self::HangulLvSyllable => ffi::G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, Self::HangulLvtSyllable => ffi::G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, Self::CloseParenthesis => ffi::G_UNICODE_BREAK_CLOSE_PARENTHESIS, Self::ConditionalJapaneseStarter => ffi::G_UNICODE_BREAK_CONDITIONAL_JAPANESE_STARTER, Self::HebrewLetter => ffi::G_UNICODE_BREAK_HEBREW_LETTER, Self::RegionalIndicator => ffi::G_UNICODE_BREAK_REGIONAL_INDICATOR, Self::EmojiBase => ffi::G_UNICODE_BREAK_EMOJI_BASE, Self::EmojiModifier => ffi::G_UNICODE_BREAK_EMOJI_MODIFIER, Self::ZeroWidthJoiner => ffi::G_UNICODE_BREAK_ZERO_WIDTH_JOINER, #[cfg(feature = "v2_80")] Self::Aksara => ffi::G_UNICODE_BREAK_AKSARA, #[cfg(feature = "v2_80")] Self::AksaraPreBase => ffi::G_UNICODE_BREAK_AKSARA_PRE_BASE, #[cfg(feature = "v2_80")] Self::AksaraStart => ffi::G_UNICODE_BREAK_AKSARA_START, #[cfg(feature = "v2_80")] Self::ViramaFinal => ffi::G_UNICODE_BREAK_VIRAMA_FINAL, #[cfg(feature = "v2_80")] Self::Virama => ffi::G_UNICODE_BREAK_VIRAMA, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for UnicodeBreakType { unsafe fn from_glib(value: ffi::GUnicodeBreakType) -> Self { match value { ffi::G_UNICODE_BREAK_MANDATORY => Self::Mandatory, ffi::G_UNICODE_BREAK_CARRIAGE_RETURN => Self::CarriageReturn, ffi::G_UNICODE_BREAK_LINE_FEED => Self::LineFeed, ffi::G_UNICODE_BREAK_COMBINING_MARK => Self::CombiningMark, ffi::G_UNICODE_BREAK_SURROGATE => Self::Surrogate, ffi::G_UNICODE_BREAK_ZERO_WIDTH_SPACE => Self::ZeroWidthSpace, ffi::G_UNICODE_BREAK_INSEPARABLE => Self::Inseparable, ffi::G_UNICODE_BREAK_NON_BREAKING_GLUE => Self::NonBreakingGlue, ffi::G_UNICODE_BREAK_CONTINGENT => Self::Contingent, ffi::G_UNICODE_BREAK_SPACE => Self::Space, ffi::G_UNICODE_BREAK_AFTER => Self::After, ffi::G_UNICODE_BREAK_BEFORE => Self::Before, ffi::G_UNICODE_BREAK_BEFORE_AND_AFTER => Self::BeforeAndAfter, ffi::G_UNICODE_BREAK_HYPHEN => Self::Hyphen, ffi::G_UNICODE_BREAK_NON_STARTER => Self::NonStarter, ffi::G_UNICODE_BREAK_OPEN_PUNCTUATION => Self::OpenPunctuation, ffi::G_UNICODE_BREAK_CLOSE_PUNCTUATION => Self::ClosePunctuation, ffi::G_UNICODE_BREAK_QUOTATION => Self::Quotation, ffi::G_UNICODE_BREAK_EXCLAMATION => Self::Exclamation, ffi::G_UNICODE_BREAK_IDEOGRAPHIC => Self::Ideographic, ffi::G_UNICODE_BREAK_NUMERIC => Self::Numeric, ffi::G_UNICODE_BREAK_INFIX_SEPARATOR => Self::InfixSeparator, ffi::G_UNICODE_BREAK_SYMBOL => Self::Symbol, ffi::G_UNICODE_BREAK_ALPHABETIC => Self::Alphabetic, ffi::G_UNICODE_BREAK_PREFIX => Self::Prefix, ffi::G_UNICODE_BREAK_POSTFIX => Self::Postfix, ffi::G_UNICODE_BREAK_COMPLEX_CONTEXT => Self::ComplexContext, ffi::G_UNICODE_BREAK_AMBIGUOUS => Self::Ambiguous, ffi::G_UNICODE_BREAK_UNKNOWN => Self::Unknown, ffi::G_UNICODE_BREAK_NEXT_LINE => Self::NextLine, ffi::G_UNICODE_BREAK_WORD_JOINER => Self::WordJoiner, ffi::G_UNICODE_BREAK_HANGUL_L_JAMO => Self::HangulLJamo, ffi::G_UNICODE_BREAK_HANGUL_V_JAMO => Self::HangulVJamo, ffi::G_UNICODE_BREAK_HANGUL_T_JAMO => Self::HangulTJamo, ffi::G_UNICODE_BREAK_HANGUL_LV_SYLLABLE => Self::HangulLvSyllable, ffi::G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE => Self::HangulLvtSyllable, ffi::G_UNICODE_BREAK_CLOSE_PARENTHESIS => Self::CloseParenthesis, ffi::G_UNICODE_BREAK_CONDITIONAL_JAPANESE_STARTER => Self::ConditionalJapaneseStarter, ffi::G_UNICODE_BREAK_HEBREW_LETTER => Self::HebrewLetter, ffi::G_UNICODE_BREAK_REGIONAL_INDICATOR => Self::RegionalIndicator, ffi::G_UNICODE_BREAK_EMOJI_BASE => Self::EmojiBase, ffi::G_UNICODE_BREAK_EMOJI_MODIFIER => Self::EmojiModifier, ffi::G_UNICODE_BREAK_ZERO_WIDTH_JOINER => Self::ZeroWidthJoiner, #[cfg(feature = "v2_80")] ffi::G_UNICODE_BREAK_AKSARA => Self::Aksara, #[cfg(feature = "v2_80")] ffi::G_UNICODE_BREAK_AKSARA_PRE_BASE => Self::AksaraPreBase, #[cfg(feature = "v2_80")] ffi::G_UNICODE_BREAK_AKSARA_START => Self::AksaraStart, #[cfg(feature = "v2_80")] ffi::G_UNICODE_BREAK_VIRAMA_FINAL => Self::ViramaFinal, #[cfg(feature = "v2_80")] ffi::G_UNICODE_BREAK_VIRAMA => Self::Virama, value => Self::__Unknown(value), } } } impl StaticType for UnicodeBreakType { #[inline] #[doc(alias = "g_unicode_break_type_get_type")] fn static_type() -> crate::Type { unsafe { from_glib(ffi::g_unicode_break_type_get_type()) } } } impl crate::HasParamSpec for UnicodeBreakType { type ParamSpec = crate::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> crate::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl crate::value::ValueType for UnicodeBreakType { type Type = Self; } unsafe impl<'a> crate::value::FromValue<'a> for UnicodeBreakType { type Checker = crate::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a crate::Value) -> Self { from_glib(crate::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for UnicodeBreakType { #[inline] fn to_value(&self) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { crate::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> crate::Type { Self::static_type() } } impl From for crate::Value { #[inline] fn from(v: UnicodeBreakType) -> Self { ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GUnicodeScript")] pub enum UnicodeScript { #[doc(alias = "G_UNICODE_SCRIPT_INVALID_CODE")] InvalidCode, #[doc(alias = "G_UNICODE_SCRIPT_COMMON")] Common, #[doc(alias = "G_UNICODE_SCRIPT_INHERITED")] Inherited, #[doc(alias = "G_UNICODE_SCRIPT_ARABIC")] Arabic, #[doc(alias = "G_UNICODE_SCRIPT_ARMENIAN")] Armenian, #[doc(alias = "G_UNICODE_SCRIPT_BENGALI")] Bengali, #[doc(alias = "G_UNICODE_SCRIPT_BOPOMOFO")] Bopomofo, #[doc(alias = "G_UNICODE_SCRIPT_CHEROKEE")] Cherokee, #[doc(alias = "G_UNICODE_SCRIPT_COPTIC")] Coptic, #[doc(alias = "G_UNICODE_SCRIPT_CYRILLIC")] Cyrillic, #[doc(alias = "G_UNICODE_SCRIPT_DESERET")] Deseret, #[doc(alias = "G_UNICODE_SCRIPT_DEVANAGARI")] Devanagari, #[doc(alias = "G_UNICODE_SCRIPT_ETHIOPIC")] Ethiopic, #[doc(alias = "G_UNICODE_SCRIPT_GEORGIAN")] Georgian, #[doc(alias = "G_UNICODE_SCRIPT_GOTHIC")] Gothic, #[doc(alias = "G_UNICODE_SCRIPT_GREEK")] Greek, #[doc(alias = "G_UNICODE_SCRIPT_GUJARATI")] Gujarati, #[doc(alias = "G_UNICODE_SCRIPT_GURMUKHI")] Gurmukhi, #[doc(alias = "G_UNICODE_SCRIPT_HAN")] Han, #[doc(alias = "G_UNICODE_SCRIPT_HANGUL")] Hangul, #[doc(alias = "G_UNICODE_SCRIPT_HEBREW")] Hebrew, #[doc(alias = "G_UNICODE_SCRIPT_HIRAGANA")] Hiragana, #[doc(alias = "G_UNICODE_SCRIPT_KANNADA")] Kannada, #[doc(alias = "G_UNICODE_SCRIPT_KATAKANA")] Katakana, #[doc(alias = "G_UNICODE_SCRIPT_KHMER")] Khmer, #[doc(alias = "G_UNICODE_SCRIPT_LAO")] Lao, #[doc(alias = "G_UNICODE_SCRIPT_LATIN")] Latin, #[doc(alias = "G_UNICODE_SCRIPT_MALAYALAM")] Malayalam, #[doc(alias = "G_UNICODE_SCRIPT_MONGOLIAN")] Mongolian, #[doc(alias = "G_UNICODE_SCRIPT_MYANMAR")] Myanmar, #[doc(alias = "G_UNICODE_SCRIPT_OGHAM")] Ogham, #[doc(alias = "G_UNICODE_SCRIPT_OLD_ITALIC")] OldItalic, #[doc(alias = "G_UNICODE_SCRIPT_ORIYA")] Oriya, #[doc(alias = "G_UNICODE_SCRIPT_RUNIC")] Runic, #[doc(alias = "G_UNICODE_SCRIPT_SINHALA")] Sinhala, #[doc(alias = "G_UNICODE_SCRIPT_SYRIAC")] Syriac, #[doc(alias = "G_UNICODE_SCRIPT_TAMIL")] Tamil, #[doc(alias = "G_UNICODE_SCRIPT_TELUGU")] Telugu, #[doc(alias = "G_UNICODE_SCRIPT_THAANA")] Thaana, #[doc(alias = "G_UNICODE_SCRIPT_THAI")] Thai, #[doc(alias = "G_UNICODE_SCRIPT_TIBETAN")] Tibetan, #[doc(alias = "G_UNICODE_SCRIPT_CANADIAN_ABORIGINAL")] CanadianAboriginal, #[doc(alias = "G_UNICODE_SCRIPT_YI")] Yi, #[doc(alias = "G_UNICODE_SCRIPT_TAGALOG")] Tagalog, #[doc(alias = "G_UNICODE_SCRIPT_HANUNOO")] Hanunoo, #[doc(alias = "G_UNICODE_SCRIPT_BUHID")] Buhid, #[doc(alias = "G_UNICODE_SCRIPT_TAGBANWA")] Tagbanwa, #[doc(alias = "G_UNICODE_SCRIPT_BRAILLE")] Braille, #[doc(alias = "G_UNICODE_SCRIPT_CYPRIOT")] Cypriot, #[doc(alias = "G_UNICODE_SCRIPT_LIMBU")] Limbu, #[doc(alias = "G_UNICODE_SCRIPT_OSMANYA")] Osmanya, #[doc(alias = "G_UNICODE_SCRIPT_SHAVIAN")] Shavian, #[doc(alias = "G_UNICODE_SCRIPT_LINEAR_B")] LinearB, #[doc(alias = "G_UNICODE_SCRIPT_TAI_LE")] TaiLe, #[doc(alias = "G_UNICODE_SCRIPT_UGARITIC")] Ugaritic, #[doc(alias = "G_UNICODE_SCRIPT_NEW_TAI_LUE")] NewTaiLue, #[doc(alias = "G_UNICODE_SCRIPT_BUGINESE")] Buginese, #[doc(alias = "G_UNICODE_SCRIPT_GLAGOLITIC")] Glagolitic, #[doc(alias = "G_UNICODE_SCRIPT_TIFINAGH")] Tifinagh, #[doc(alias = "G_UNICODE_SCRIPT_SYLOTI_NAGRI")] SylotiNagri, #[doc(alias = "G_UNICODE_SCRIPT_OLD_PERSIAN")] OldPersian, #[doc(alias = "G_UNICODE_SCRIPT_KHAROSHTHI")] Kharoshthi, #[doc(alias = "G_UNICODE_SCRIPT_UNKNOWN")] Unknown, #[doc(alias = "G_UNICODE_SCRIPT_BALINESE")] Balinese, #[doc(alias = "G_UNICODE_SCRIPT_CUNEIFORM")] Cuneiform, #[doc(alias = "G_UNICODE_SCRIPT_PHOENICIAN")] Phoenician, #[doc(alias = "G_UNICODE_SCRIPT_PHAGS_PA")] PhagsPa, #[doc(alias = "G_UNICODE_SCRIPT_NKO")] Nko, #[doc(alias = "G_UNICODE_SCRIPT_KAYAH_LI")] KayahLi, #[doc(alias = "G_UNICODE_SCRIPT_LEPCHA")] Lepcha, #[doc(alias = "G_UNICODE_SCRIPT_REJANG")] Rejang, #[doc(alias = "G_UNICODE_SCRIPT_SUNDANESE")] Sundanese, #[doc(alias = "G_UNICODE_SCRIPT_SAURASHTRA")] Saurashtra, #[doc(alias = "G_UNICODE_SCRIPT_CHAM")] Cham, #[doc(alias = "G_UNICODE_SCRIPT_OL_CHIKI")] OlChiki, #[doc(alias = "G_UNICODE_SCRIPT_VAI")] Vai, #[doc(alias = "G_UNICODE_SCRIPT_CARIAN")] Carian, #[doc(alias = "G_UNICODE_SCRIPT_LYCIAN")] Lycian, #[doc(alias = "G_UNICODE_SCRIPT_LYDIAN")] Lydian, #[doc(alias = "G_UNICODE_SCRIPT_AVESTAN")] Avestan, #[doc(alias = "G_UNICODE_SCRIPT_BAMUM")] Bamum, #[doc(alias = "G_UNICODE_SCRIPT_EGYPTIAN_HIEROGLYPHS")] EgyptianHieroglyphs, #[doc(alias = "G_UNICODE_SCRIPT_IMPERIAL_ARAMAIC")] ImperialAramaic, #[doc(alias = "G_UNICODE_SCRIPT_INSCRIPTIONAL_PAHLAVI")] InscriptionalPahlavi, #[doc(alias = "G_UNICODE_SCRIPT_INSCRIPTIONAL_PARTHIAN")] InscriptionalParthian, #[doc(alias = "G_UNICODE_SCRIPT_JAVANESE")] Javanese, #[doc(alias = "G_UNICODE_SCRIPT_KAITHI")] Kaithi, #[doc(alias = "G_UNICODE_SCRIPT_LISU")] Lisu, #[doc(alias = "G_UNICODE_SCRIPT_MEETEI_MAYEK")] MeeteiMayek, #[doc(alias = "G_UNICODE_SCRIPT_OLD_SOUTH_ARABIAN")] OldSouthArabian, #[doc(alias = "G_UNICODE_SCRIPT_OLD_TURKIC")] OldTurkic, #[doc(alias = "G_UNICODE_SCRIPT_SAMARITAN")] Samaritan, #[doc(alias = "G_UNICODE_SCRIPT_TAI_THAM")] TaiTham, #[doc(alias = "G_UNICODE_SCRIPT_TAI_VIET")] TaiViet, #[doc(alias = "G_UNICODE_SCRIPT_BATAK")] Batak, #[doc(alias = "G_UNICODE_SCRIPT_BRAHMI")] Brahmi, #[doc(alias = "G_UNICODE_SCRIPT_MANDAIC")] Mandaic, #[doc(alias = "G_UNICODE_SCRIPT_CHAKMA")] Chakma, #[doc(alias = "G_UNICODE_SCRIPT_MEROITIC_CURSIVE")] MeroiticCursive, #[doc(alias = "G_UNICODE_SCRIPT_MEROITIC_HIEROGLYPHS")] MeroiticHieroglyphs, #[doc(alias = "G_UNICODE_SCRIPT_MIAO")] Miao, #[doc(alias = "G_UNICODE_SCRIPT_SHARADA")] Sharada, #[doc(alias = "G_UNICODE_SCRIPT_SORA_SOMPENG")] SoraSompeng, #[doc(alias = "G_UNICODE_SCRIPT_TAKRI")] Takri, #[doc(alias = "G_UNICODE_SCRIPT_BASSA_VAH")] BassaVah, #[doc(alias = "G_UNICODE_SCRIPT_CAUCASIAN_ALBANIAN")] CaucasianAlbanian, #[doc(alias = "G_UNICODE_SCRIPT_DUPLOYAN")] Duployan, #[doc(alias = "G_UNICODE_SCRIPT_ELBASAN")] Elbasan, #[doc(alias = "G_UNICODE_SCRIPT_GRANTHA")] Grantha, #[doc(alias = "G_UNICODE_SCRIPT_KHOJKI")] Khojki, #[doc(alias = "G_UNICODE_SCRIPT_KHUDAWADI")] Khudawadi, #[doc(alias = "G_UNICODE_SCRIPT_LINEAR_A")] LinearA, #[doc(alias = "G_UNICODE_SCRIPT_MAHAJANI")] Mahajani, #[doc(alias = "G_UNICODE_SCRIPT_MANICHAEAN")] Manichaean, #[doc(alias = "G_UNICODE_SCRIPT_MENDE_KIKAKUI")] MendeKikakui, #[doc(alias = "G_UNICODE_SCRIPT_MODI")] Modi, #[doc(alias = "G_UNICODE_SCRIPT_MRO")] Mro, #[doc(alias = "G_UNICODE_SCRIPT_NABATAEAN")] Nabataean, #[doc(alias = "G_UNICODE_SCRIPT_OLD_NORTH_ARABIAN")] OldNorthArabian, #[doc(alias = "G_UNICODE_SCRIPT_OLD_PERMIC")] OldPermic, #[doc(alias = "G_UNICODE_SCRIPT_PAHAWH_HMONG")] PahawhHmong, #[doc(alias = "G_UNICODE_SCRIPT_PALMYRENE")] Palmyrene, #[doc(alias = "G_UNICODE_SCRIPT_PAU_CIN_HAU")] PauCinHau, #[doc(alias = "G_UNICODE_SCRIPT_PSALTER_PAHLAVI")] PsalterPahlavi, #[doc(alias = "G_UNICODE_SCRIPT_SIDDHAM")] Siddham, #[doc(alias = "G_UNICODE_SCRIPT_TIRHUTA")] Tirhuta, #[doc(alias = "G_UNICODE_SCRIPT_WARANG_CITI")] WarangCiti, #[doc(alias = "G_UNICODE_SCRIPT_AHOM")] Ahom, #[doc(alias = "G_UNICODE_SCRIPT_ANATOLIAN_HIEROGLYPHS")] AnatolianHieroglyphs, #[doc(alias = "G_UNICODE_SCRIPT_HATRAN")] Hatran, #[doc(alias = "G_UNICODE_SCRIPT_MULTANI")] Multani, #[doc(alias = "G_UNICODE_SCRIPT_OLD_HUNGARIAN")] OldHungarian, #[doc(alias = "G_UNICODE_SCRIPT_SIGNWRITING")] Signwriting, #[doc(alias = "G_UNICODE_SCRIPT_ADLAM")] Adlam, #[doc(alias = "G_UNICODE_SCRIPT_BHAIKSUKI")] Bhaiksuki, #[doc(alias = "G_UNICODE_SCRIPT_MARCHEN")] Marchen, #[doc(alias = "G_UNICODE_SCRIPT_NEWA")] Newa, #[doc(alias = "G_UNICODE_SCRIPT_OSAGE")] Osage, #[doc(alias = "G_UNICODE_SCRIPT_TANGUT")] Tangut, #[doc(alias = "G_UNICODE_SCRIPT_MASARAM_GONDI")] MasaramGondi, #[doc(alias = "G_UNICODE_SCRIPT_NUSHU")] Nushu, #[doc(alias = "G_UNICODE_SCRIPT_SOYOMBO")] Soyombo, #[doc(alias = "G_UNICODE_SCRIPT_ZANABAZAR_SQUARE")] ZanabazarSquare, #[doc(alias = "G_UNICODE_SCRIPT_DOGRA")] Dogra, #[doc(alias = "G_UNICODE_SCRIPT_GUNJALA_GONDI")] GunjalaGondi, #[doc(alias = "G_UNICODE_SCRIPT_HANIFI_ROHINGYA")] HanifiRohingya, #[doc(alias = "G_UNICODE_SCRIPT_MAKASAR")] Makasar, #[doc(alias = "G_UNICODE_SCRIPT_MEDEFAIDRIN")] Medefaidrin, #[doc(alias = "G_UNICODE_SCRIPT_OLD_SOGDIAN")] OldSogdian, #[doc(alias = "G_UNICODE_SCRIPT_SOGDIAN")] Sogdian, #[doc(alias = "G_UNICODE_SCRIPT_ELYMAIC")] Elymaic, #[doc(alias = "G_UNICODE_SCRIPT_NANDINAGARI")] Nandinagari, #[doc(alias = "G_UNICODE_SCRIPT_NYIAKENG_PUACHUE_HMONG")] NyiakengPuachueHmong, #[doc(alias = "G_UNICODE_SCRIPT_WANCHO")] Wancho, #[doc(alias = "G_UNICODE_SCRIPT_CHORASMIAN")] Chorasmian, #[doc(alias = "G_UNICODE_SCRIPT_DIVES_AKURU")] DivesAkuru, #[doc(alias = "G_UNICODE_SCRIPT_KHITAN_SMALL_SCRIPT")] KhitanSmallScript, #[doc(alias = "G_UNICODE_SCRIPT_YEZIDI")] Yezidi, #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] #[doc(alias = "G_UNICODE_SCRIPT_CYPRO_MINOAN")] CyproMinoan, #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] #[doc(alias = "G_UNICODE_SCRIPT_OLD_UYGHUR")] OldUyghur, #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] #[doc(alias = "G_UNICODE_SCRIPT_TANGSA")] Tangsa, #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] #[doc(alias = "G_UNICODE_SCRIPT_TOTO")] Toto, #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] #[doc(alias = "G_UNICODE_SCRIPT_VITHKUQI")] Vithkuqi, #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] #[doc(alias = "G_UNICODE_SCRIPT_MATH")] Math, #[cfg(feature = "v2_74")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))] #[doc(alias = "G_UNICODE_SCRIPT_KAWI")] Kawi, #[cfg(feature = "v2_74")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))] #[doc(alias = "G_UNICODE_SCRIPT_NAG_MUNDARI")] NagMundari, #[cfg(feature = "v2_84")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_84")))] #[doc(alias = "G_UNICODE_SCRIPT_TODHRI")] Todhri, #[cfg(feature = "v2_84")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_84")))] #[doc(alias = "G_UNICODE_SCRIPT_GARAY")] Garay, #[cfg(feature = "v2_84")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_84")))] #[doc(alias = "G_UNICODE_SCRIPT_TULU_TIGALARI")] TuluTigalari, #[cfg(feature = "v2_84")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_84")))] #[doc(alias = "G_UNICODE_SCRIPT_SUNUWAR")] Sunuwar, #[cfg(feature = "v2_84")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_84")))] #[doc(alias = "G_UNICODE_SCRIPT_GURUNG_KHEMA")] GurungKhema, #[cfg(feature = "v2_84")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_84")))] #[doc(alias = "G_UNICODE_SCRIPT_KIRAT_RAI")] KiratRai, #[cfg(feature = "v2_84")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_84")))] #[doc(alias = "G_UNICODE_SCRIPT_OL_ONAL")] OlOnal, #[doc(hidden)] __Unknown(i32), } impl UnicodeScript { #[doc(alias = "g_unicode_script_from_iso15924")] pub fn from_iso15924(iso15924: u32) -> UnicodeScript { unsafe { from_glib(ffi::g_unicode_script_from_iso15924(iso15924)) } } #[doc(alias = "g_unicode_script_to_iso15924")] pub fn to_iso15924(self) -> u32 { unsafe { ffi::g_unicode_script_to_iso15924(self.into_glib()) } } } #[doc(hidden)] impl IntoGlib for UnicodeScript { type GlibType = ffi::GUnicodeScript; fn into_glib(self) -> ffi::GUnicodeScript { match self { Self::InvalidCode => ffi::G_UNICODE_SCRIPT_INVALID_CODE, Self::Common => ffi::G_UNICODE_SCRIPT_COMMON, Self::Inherited => ffi::G_UNICODE_SCRIPT_INHERITED, Self::Arabic => ffi::G_UNICODE_SCRIPT_ARABIC, Self::Armenian => ffi::G_UNICODE_SCRIPT_ARMENIAN, Self::Bengali => ffi::G_UNICODE_SCRIPT_BENGALI, Self::Bopomofo => ffi::G_UNICODE_SCRIPT_BOPOMOFO, Self::Cherokee => ffi::G_UNICODE_SCRIPT_CHEROKEE, Self::Coptic => ffi::G_UNICODE_SCRIPT_COPTIC, Self::Cyrillic => ffi::G_UNICODE_SCRIPT_CYRILLIC, Self::Deseret => ffi::G_UNICODE_SCRIPT_DESERET, Self::Devanagari => ffi::G_UNICODE_SCRIPT_DEVANAGARI, Self::Ethiopic => ffi::G_UNICODE_SCRIPT_ETHIOPIC, Self::Georgian => ffi::G_UNICODE_SCRIPT_GEORGIAN, Self::Gothic => ffi::G_UNICODE_SCRIPT_GOTHIC, Self::Greek => ffi::G_UNICODE_SCRIPT_GREEK, Self::Gujarati => ffi::G_UNICODE_SCRIPT_GUJARATI, Self::Gurmukhi => ffi::G_UNICODE_SCRIPT_GURMUKHI, Self::Han => ffi::G_UNICODE_SCRIPT_HAN, Self::Hangul => ffi::G_UNICODE_SCRIPT_HANGUL, Self::Hebrew => ffi::G_UNICODE_SCRIPT_HEBREW, Self::Hiragana => ffi::G_UNICODE_SCRIPT_HIRAGANA, Self::Kannada => ffi::G_UNICODE_SCRIPT_KANNADA, Self::Katakana => ffi::G_UNICODE_SCRIPT_KATAKANA, Self::Khmer => ffi::G_UNICODE_SCRIPT_KHMER, Self::Lao => ffi::G_UNICODE_SCRIPT_LAO, Self::Latin => ffi::G_UNICODE_SCRIPT_LATIN, Self::Malayalam => ffi::G_UNICODE_SCRIPT_MALAYALAM, Self::Mongolian => ffi::G_UNICODE_SCRIPT_MONGOLIAN, Self::Myanmar => ffi::G_UNICODE_SCRIPT_MYANMAR, Self::Ogham => ffi::G_UNICODE_SCRIPT_OGHAM, Self::OldItalic => ffi::G_UNICODE_SCRIPT_OLD_ITALIC, Self::Oriya => ffi::G_UNICODE_SCRIPT_ORIYA, Self::Runic => ffi::G_UNICODE_SCRIPT_RUNIC, Self::Sinhala => ffi::G_UNICODE_SCRIPT_SINHALA, Self::Syriac => ffi::G_UNICODE_SCRIPT_SYRIAC, Self::Tamil => ffi::G_UNICODE_SCRIPT_TAMIL, Self::Telugu => ffi::G_UNICODE_SCRIPT_TELUGU, Self::Thaana => ffi::G_UNICODE_SCRIPT_THAANA, Self::Thai => ffi::G_UNICODE_SCRIPT_THAI, Self::Tibetan => ffi::G_UNICODE_SCRIPT_TIBETAN, Self::CanadianAboriginal => ffi::G_UNICODE_SCRIPT_CANADIAN_ABORIGINAL, Self::Yi => ffi::G_UNICODE_SCRIPT_YI, Self::Tagalog => ffi::G_UNICODE_SCRIPT_TAGALOG, Self::Hanunoo => ffi::G_UNICODE_SCRIPT_HANUNOO, Self::Buhid => ffi::G_UNICODE_SCRIPT_BUHID, Self::Tagbanwa => ffi::G_UNICODE_SCRIPT_TAGBANWA, Self::Braille => ffi::G_UNICODE_SCRIPT_BRAILLE, Self::Cypriot => ffi::G_UNICODE_SCRIPT_CYPRIOT, Self::Limbu => ffi::G_UNICODE_SCRIPT_LIMBU, Self::Osmanya => ffi::G_UNICODE_SCRIPT_OSMANYA, Self::Shavian => ffi::G_UNICODE_SCRIPT_SHAVIAN, Self::LinearB => ffi::G_UNICODE_SCRIPT_LINEAR_B, Self::TaiLe => ffi::G_UNICODE_SCRIPT_TAI_LE, Self::Ugaritic => ffi::G_UNICODE_SCRIPT_UGARITIC, Self::NewTaiLue => ffi::G_UNICODE_SCRIPT_NEW_TAI_LUE, Self::Buginese => ffi::G_UNICODE_SCRIPT_BUGINESE, Self::Glagolitic => ffi::G_UNICODE_SCRIPT_GLAGOLITIC, Self::Tifinagh => ffi::G_UNICODE_SCRIPT_TIFINAGH, Self::SylotiNagri => ffi::G_UNICODE_SCRIPT_SYLOTI_NAGRI, Self::OldPersian => ffi::G_UNICODE_SCRIPT_OLD_PERSIAN, Self::Kharoshthi => ffi::G_UNICODE_SCRIPT_KHAROSHTHI, Self::Unknown => ffi::G_UNICODE_SCRIPT_UNKNOWN, Self::Balinese => ffi::G_UNICODE_SCRIPT_BALINESE, Self::Cuneiform => ffi::G_UNICODE_SCRIPT_CUNEIFORM, Self::Phoenician => ffi::G_UNICODE_SCRIPT_PHOENICIAN, Self::PhagsPa => ffi::G_UNICODE_SCRIPT_PHAGS_PA, Self::Nko => ffi::G_UNICODE_SCRIPT_NKO, Self::KayahLi => ffi::G_UNICODE_SCRIPT_KAYAH_LI, Self::Lepcha => ffi::G_UNICODE_SCRIPT_LEPCHA, Self::Rejang => ffi::G_UNICODE_SCRIPT_REJANG, Self::Sundanese => ffi::G_UNICODE_SCRIPT_SUNDANESE, Self::Saurashtra => ffi::G_UNICODE_SCRIPT_SAURASHTRA, Self::Cham => ffi::G_UNICODE_SCRIPT_CHAM, Self::OlChiki => ffi::G_UNICODE_SCRIPT_OL_CHIKI, Self::Vai => ffi::G_UNICODE_SCRIPT_VAI, Self::Carian => ffi::G_UNICODE_SCRIPT_CARIAN, Self::Lycian => ffi::G_UNICODE_SCRIPT_LYCIAN, Self::Lydian => ffi::G_UNICODE_SCRIPT_LYDIAN, Self::Avestan => ffi::G_UNICODE_SCRIPT_AVESTAN, Self::Bamum => ffi::G_UNICODE_SCRIPT_BAMUM, Self::EgyptianHieroglyphs => ffi::G_UNICODE_SCRIPT_EGYPTIAN_HIEROGLYPHS, Self::ImperialAramaic => ffi::G_UNICODE_SCRIPT_IMPERIAL_ARAMAIC, Self::InscriptionalPahlavi => ffi::G_UNICODE_SCRIPT_INSCRIPTIONAL_PAHLAVI, Self::InscriptionalParthian => ffi::G_UNICODE_SCRIPT_INSCRIPTIONAL_PARTHIAN, Self::Javanese => ffi::G_UNICODE_SCRIPT_JAVANESE, Self::Kaithi => ffi::G_UNICODE_SCRIPT_KAITHI, Self::Lisu => ffi::G_UNICODE_SCRIPT_LISU, Self::MeeteiMayek => ffi::G_UNICODE_SCRIPT_MEETEI_MAYEK, Self::OldSouthArabian => ffi::G_UNICODE_SCRIPT_OLD_SOUTH_ARABIAN, Self::OldTurkic => ffi::G_UNICODE_SCRIPT_OLD_TURKIC, Self::Samaritan => ffi::G_UNICODE_SCRIPT_SAMARITAN, Self::TaiTham => ffi::G_UNICODE_SCRIPT_TAI_THAM, Self::TaiViet => ffi::G_UNICODE_SCRIPT_TAI_VIET, Self::Batak => ffi::G_UNICODE_SCRIPT_BATAK, Self::Brahmi => ffi::G_UNICODE_SCRIPT_BRAHMI, Self::Mandaic => ffi::G_UNICODE_SCRIPT_MANDAIC, Self::Chakma => ffi::G_UNICODE_SCRIPT_CHAKMA, Self::MeroiticCursive => ffi::G_UNICODE_SCRIPT_MEROITIC_CURSIVE, Self::MeroiticHieroglyphs => ffi::G_UNICODE_SCRIPT_MEROITIC_HIEROGLYPHS, Self::Miao => ffi::G_UNICODE_SCRIPT_MIAO, Self::Sharada => ffi::G_UNICODE_SCRIPT_SHARADA, Self::SoraSompeng => ffi::G_UNICODE_SCRIPT_SORA_SOMPENG, Self::Takri => ffi::G_UNICODE_SCRIPT_TAKRI, Self::BassaVah => ffi::G_UNICODE_SCRIPT_BASSA_VAH, Self::CaucasianAlbanian => ffi::G_UNICODE_SCRIPT_CAUCASIAN_ALBANIAN, Self::Duployan => ffi::G_UNICODE_SCRIPT_DUPLOYAN, Self::Elbasan => ffi::G_UNICODE_SCRIPT_ELBASAN, Self::Grantha => ffi::G_UNICODE_SCRIPT_GRANTHA, Self::Khojki => ffi::G_UNICODE_SCRIPT_KHOJKI, Self::Khudawadi => ffi::G_UNICODE_SCRIPT_KHUDAWADI, Self::LinearA => ffi::G_UNICODE_SCRIPT_LINEAR_A, Self::Mahajani => ffi::G_UNICODE_SCRIPT_MAHAJANI, Self::Manichaean => ffi::G_UNICODE_SCRIPT_MANICHAEAN, Self::MendeKikakui => ffi::G_UNICODE_SCRIPT_MENDE_KIKAKUI, Self::Modi => ffi::G_UNICODE_SCRIPT_MODI, Self::Mro => ffi::G_UNICODE_SCRIPT_MRO, Self::Nabataean => ffi::G_UNICODE_SCRIPT_NABATAEAN, Self::OldNorthArabian => ffi::G_UNICODE_SCRIPT_OLD_NORTH_ARABIAN, Self::OldPermic => ffi::G_UNICODE_SCRIPT_OLD_PERMIC, Self::PahawhHmong => ffi::G_UNICODE_SCRIPT_PAHAWH_HMONG, Self::Palmyrene => ffi::G_UNICODE_SCRIPT_PALMYRENE, Self::PauCinHau => ffi::G_UNICODE_SCRIPT_PAU_CIN_HAU, Self::PsalterPahlavi => ffi::G_UNICODE_SCRIPT_PSALTER_PAHLAVI, Self::Siddham => ffi::G_UNICODE_SCRIPT_SIDDHAM, Self::Tirhuta => ffi::G_UNICODE_SCRIPT_TIRHUTA, Self::WarangCiti => ffi::G_UNICODE_SCRIPT_WARANG_CITI, Self::Ahom => ffi::G_UNICODE_SCRIPT_AHOM, Self::AnatolianHieroglyphs => ffi::G_UNICODE_SCRIPT_ANATOLIAN_HIEROGLYPHS, Self::Hatran => ffi::G_UNICODE_SCRIPT_HATRAN, Self::Multani => ffi::G_UNICODE_SCRIPT_MULTANI, Self::OldHungarian => ffi::G_UNICODE_SCRIPT_OLD_HUNGARIAN, Self::Signwriting => ffi::G_UNICODE_SCRIPT_SIGNWRITING, Self::Adlam => ffi::G_UNICODE_SCRIPT_ADLAM, Self::Bhaiksuki => ffi::G_UNICODE_SCRIPT_BHAIKSUKI, Self::Marchen => ffi::G_UNICODE_SCRIPT_MARCHEN, Self::Newa => ffi::G_UNICODE_SCRIPT_NEWA, Self::Osage => ffi::G_UNICODE_SCRIPT_OSAGE, Self::Tangut => ffi::G_UNICODE_SCRIPT_TANGUT, Self::MasaramGondi => ffi::G_UNICODE_SCRIPT_MASARAM_GONDI, Self::Nushu => ffi::G_UNICODE_SCRIPT_NUSHU, Self::Soyombo => ffi::G_UNICODE_SCRIPT_SOYOMBO, Self::ZanabazarSquare => ffi::G_UNICODE_SCRIPT_ZANABAZAR_SQUARE, Self::Dogra => ffi::G_UNICODE_SCRIPT_DOGRA, Self::GunjalaGondi => ffi::G_UNICODE_SCRIPT_GUNJALA_GONDI, Self::HanifiRohingya => ffi::G_UNICODE_SCRIPT_HANIFI_ROHINGYA, Self::Makasar => ffi::G_UNICODE_SCRIPT_MAKASAR, Self::Medefaidrin => ffi::G_UNICODE_SCRIPT_MEDEFAIDRIN, Self::OldSogdian => ffi::G_UNICODE_SCRIPT_OLD_SOGDIAN, Self::Sogdian => ffi::G_UNICODE_SCRIPT_SOGDIAN, Self::Elymaic => ffi::G_UNICODE_SCRIPT_ELYMAIC, Self::Nandinagari => ffi::G_UNICODE_SCRIPT_NANDINAGARI, Self::NyiakengPuachueHmong => ffi::G_UNICODE_SCRIPT_NYIAKENG_PUACHUE_HMONG, Self::Wancho => ffi::G_UNICODE_SCRIPT_WANCHO, Self::Chorasmian => ffi::G_UNICODE_SCRIPT_CHORASMIAN, Self::DivesAkuru => ffi::G_UNICODE_SCRIPT_DIVES_AKURU, Self::KhitanSmallScript => ffi::G_UNICODE_SCRIPT_KHITAN_SMALL_SCRIPT, Self::Yezidi => ffi::G_UNICODE_SCRIPT_YEZIDI, #[cfg(feature = "v2_72")] Self::CyproMinoan => ffi::G_UNICODE_SCRIPT_CYPRO_MINOAN, #[cfg(feature = "v2_72")] Self::OldUyghur => ffi::G_UNICODE_SCRIPT_OLD_UYGHUR, #[cfg(feature = "v2_72")] Self::Tangsa => ffi::G_UNICODE_SCRIPT_TANGSA, #[cfg(feature = "v2_72")] Self::Toto => ffi::G_UNICODE_SCRIPT_TOTO, #[cfg(feature = "v2_72")] Self::Vithkuqi => ffi::G_UNICODE_SCRIPT_VITHKUQI, #[cfg(feature = "v2_72")] Self::Math => ffi::G_UNICODE_SCRIPT_MATH, #[cfg(feature = "v2_74")] Self::Kawi => ffi::G_UNICODE_SCRIPT_KAWI, #[cfg(feature = "v2_74")] Self::NagMundari => ffi::G_UNICODE_SCRIPT_NAG_MUNDARI, #[cfg(feature = "v2_84")] Self::Todhri => ffi::G_UNICODE_SCRIPT_TODHRI, #[cfg(feature = "v2_84")] Self::Garay => ffi::G_UNICODE_SCRIPT_GARAY, #[cfg(feature = "v2_84")] Self::TuluTigalari => ffi::G_UNICODE_SCRIPT_TULU_TIGALARI, #[cfg(feature = "v2_84")] Self::Sunuwar => ffi::G_UNICODE_SCRIPT_SUNUWAR, #[cfg(feature = "v2_84")] Self::GurungKhema => ffi::G_UNICODE_SCRIPT_GURUNG_KHEMA, #[cfg(feature = "v2_84")] Self::KiratRai => ffi::G_UNICODE_SCRIPT_KIRAT_RAI, #[cfg(feature = "v2_84")] Self::OlOnal => ffi::G_UNICODE_SCRIPT_OL_ONAL, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for UnicodeScript { unsafe fn from_glib(value: ffi::GUnicodeScript) -> Self { match value { ffi::G_UNICODE_SCRIPT_INVALID_CODE => Self::InvalidCode, ffi::G_UNICODE_SCRIPT_COMMON => Self::Common, ffi::G_UNICODE_SCRIPT_INHERITED => Self::Inherited, ffi::G_UNICODE_SCRIPT_ARABIC => Self::Arabic, ffi::G_UNICODE_SCRIPT_ARMENIAN => Self::Armenian, ffi::G_UNICODE_SCRIPT_BENGALI => Self::Bengali, ffi::G_UNICODE_SCRIPT_BOPOMOFO => Self::Bopomofo, ffi::G_UNICODE_SCRIPT_CHEROKEE => Self::Cherokee, ffi::G_UNICODE_SCRIPT_COPTIC => Self::Coptic, ffi::G_UNICODE_SCRIPT_CYRILLIC => Self::Cyrillic, ffi::G_UNICODE_SCRIPT_DESERET => Self::Deseret, ffi::G_UNICODE_SCRIPT_DEVANAGARI => Self::Devanagari, ffi::G_UNICODE_SCRIPT_ETHIOPIC => Self::Ethiopic, ffi::G_UNICODE_SCRIPT_GEORGIAN => Self::Georgian, ffi::G_UNICODE_SCRIPT_GOTHIC => Self::Gothic, ffi::G_UNICODE_SCRIPT_GREEK => Self::Greek, ffi::G_UNICODE_SCRIPT_GUJARATI => Self::Gujarati, ffi::G_UNICODE_SCRIPT_GURMUKHI => Self::Gurmukhi, ffi::G_UNICODE_SCRIPT_HAN => Self::Han, ffi::G_UNICODE_SCRIPT_HANGUL => Self::Hangul, ffi::G_UNICODE_SCRIPT_HEBREW => Self::Hebrew, ffi::G_UNICODE_SCRIPT_HIRAGANA => Self::Hiragana, ffi::G_UNICODE_SCRIPT_KANNADA => Self::Kannada, ffi::G_UNICODE_SCRIPT_KATAKANA => Self::Katakana, ffi::G_UNICODE_SCRIPT_KHMER => Self::Khmer, ffi::G_UNICODE_SCRIPT_LAO => Self::Lao, ffi::G_UNICODE_SCRIPT_LATIN => Self::Latin, ffi::G_UNICODE_SCRIPT_MALAYALAM => Self::Malayalam, ffi::G_UNICODE_SCRIPT_MONGOLIAN => Self::Mongolian, ffi::G_UNICODE_SCRIPT_MYANMAR => Self::Myanmar, ffi::G_UNICODE_SCRIPT_OGHAM => Self::Ogham, ffi::G_UNICODE_SCRIPT_OLD_ITALIC => Self::OldItalic, ffi::G_UNICODE_SCRIPT_ORIYA => Self::Oriya, ffi::G_UNICODE_SCRIPT_RUNIC => Self::Runic, ffi::G_UNICODE_SCRIPT_SINHALA => Self::Sinhala, ffi::G_UNICODE_SCRIPT_SYRIAC => Self::Syriac, ffi::G_UNICODE_SCRIPT_TAMIL => Self::Tamil, ffi::G_UNICODE_SCRIPT_TELUGU => Self::Telugu, ffi::G_UNICODE_SCRIPT_THAANA => Self::Thaana, ffi::G_UNICODE_SCRIPT_THAI => Self::Thai, ffi::G_UNICODE_SCRIPT_TIBETAN => Self::Tibetan, ffi::G_UNICODE_SCRIPT_CANADIAN_ABORIGINAL => Self::CanadianAboriginal, ffi::G_UNICODE_SCRIPT_YI => Self::Yi, ffi::G_UNICODE_SCRIPT_TAGALOG => Self::Tagalog, ffi::G_UNICODE_SCRIPT_HANUNOO => Self::Hanunoo, ffi::G_UNICODE_SCRIPT_BUHID => Self::Buhid, ffi::G_UNICODE_SCRIPT_TAGBANWA => Self::Tagbanwa, ffi::G_UNICODE_SCRIPT_BRAILLE => Self::Braille, ffi::G_UNICODE_SCRIPT_CYPRIOT => Self::Cypriot, ffi::G_UNICODE_SCRIPT_LIMBU => Self::Limbu, ffi::G_UNICODE_SCRIPT_OSMANYA => Self::Osmanya, ffi::G_UNICODE_SCRIPT_SHAVIAN => Self::Shavian, ffi::G_UNICODE_SCRIPT_LINEAR_B => Self::LinearB, ffi::G_UNICODE_SCRIPT_TAI_LE => Self::TaiLe, ffi::G_UNICODE_SCRIPT_UGARITIC => Self::Ugaritic, ffi::G_UNICODE_SCRIPT_NEW_TAI_LUE => Self::NewTaiLue, ffi::G_UNICODE_SCRIPT_BUGINESE => Self::Buginese, ffi::G_UNICODE_SCRIPT_GLAGOLITIC => Self::Glagolitic, ffi::G_UNICODE_SCRIPT_TIFINAGH => Self::Tifinagh, ffi::G_UNICODE_SCRIPT_SYLOTI_NAGRI => Self::SylotiNagri, ffi::G_UNICODE_SCRIPT_OLD_PERSIAN => Self::OldPersian, ffi::G_UNICODE_SCRIPT_KHAROSHTHI => Self::Kharoshthi, ffi::G_UNICODE_SCRIPT_UNKNOWN => Self::Unknown, ffi::G_UNICODE_SCRIPT_BALINESE => Self::Balinese, ffi::G_UNICODE_SCRIPT_CUNEIFORM => Self::Cuneiform, ffi::G_UNICODE_SCRIPT_PHOENICIAN => Self::Phoenician, ffi::G_UNICODE_SCRIPT_PHAGS_PA => Self::PhagsPa, ffi::G_UNICODE_SCRIPT_NKO => Self::Nko, ffi::G_UNICODE_SCRIPT_KAYAH_LI => Self::KayahLi, ffi::G_UNICODE_SCRIPT_LEPCHA => Self::Lepcha, ffi::G_UNICODE_SCRIPT_REJANG => Self::Rejang, ffi::G_UNICODE_SCRIPT_SUNDANESE => Self::Sundanese, ffi::G_UNICODE_SCRIPT_SAURASHTRA => Self::Saurashtra, ffi::G_UNICODE_SCRIPT_CHAM => Self::Cham, ffi::G_UNICODE_SCRIPT_OL_CHIKI => Self::OlChiki, ffi::G_UNICODE_SCRIPT_VAI => Self::Vai, ffi::G_UNICODE_SCRIPT_CARIAN => Self::Carian, ffi::G_UNICODE_SCRIPT_LYCIAN => Self::Lycian, ffi::G_UNICODE_SCRIPT_LYDIAN => Self::Lydian, ffi::G_UNICODE_SCRIPT_AVESTAN => Self::Avestan, ffi::G_UNICODE_SCRIPT_BAMUM => Self::Bamum, ffi::G_UNICODE_SCRIPT_EGYPTIAN_HIEROGLYPHS => Self::EgyptianHieroglyphs, ffi::G_UNICODE_SCRIPT_IMPERIAL_ARAMAIC => Self::ImperialAramaic, ffi::G_UNICODE_SCRIPT_INSCRIPTIONAL_PAHLAVI => Self::InscriptionalPahlavi, ffi::G_UNICODE_SCRIPT_INSCRIPTIONAL_PARTHIAN => Self::InscriptionalParthian, ffi::G_UNICODE_SCRIPT_JAVANESE => Self::Javanese, ffi::G_UNICODE_SCRIPT_KAITHI => Self::Kaithi, ffi::G_UNICODE_SCRIPT_LISU => Self::Lisu, ffi::G_UNICODE_SCRIPT_MEETEI_MAYEK => Self::MeeteiMayek, ffi::G_UNICODE_SCRIPT_OLD_SOUTH_ARABIAN => Self::OldSouthArabian, ffi::G_UNICODE_SCRIPT_OLD_TURKIC => Self::OldTurkic, ffi::G_UNICODE_SCRIPT_SAMARITAN => Self::Samaritan, ffi::G_UNICODE_SCRIPT_TAI_THAM => Self::TaiTham, ffi::G_UNICODE_SCRIPT_TAI_VIET => Self::TaiViet, ffi::G_UNICODE_SCRIPT_BATAK => Self::Batak, ffi::G_UNICODE_SCRIPT_BRAHMI => Self::Brahmi, ffi::G_UNICODE_SCRIPT_MANDAIC => Self::Mandaic, ffi::G_UNICODE_SCRIPT_CHAKMA => Self::Chakma, ffi::G_UNICODE_SCRIPT_MEROITIC_CURSIVE => Self::MeroiticCursive, ffi::G_UNICODE_SCRIPT_MEROITIC_HIEROGLYPHS => Self::MeroiticHieroglyphs, ffi::G_UNICODE_SCRIPT_MIAO => Self::Miao, ffi::G_UNICODE_SCRIPT_SHARADA => Self::Sharada, ffi::G_UNICODE_SCRIPT_SORA_SOMPENG => Self::SoraSompeng, ffi::G_UNICODE_SCRIPT_TAKRI => Self::Takri, ffi::G_UNICODE_SCRIPT_BASSA_VAH => Self::BassaVah, ffi::G_UNICODE_SCRIPT_CAUCASIAN_ALBANIAN => Self::CaucasianAlbanian, ffi::G_UNICODE_SCRIPT_DUPLOYAN => Self::Duployan, ffi::G_UNICODE_SCRIPT_ELBASAN => Self::Elbasan, ffi::G_UNICODE_SCRIPT_GRANTHA => Self::Grantha, ffi::G_UNICODE_SCRIPT_KHOJKI => Self::Khojki, ffi::G_UNICODE_SCRIPT_KHUDAWADI => Self::Khudawadi, ffi::G_UNICODE_SCRIPT_LINEAR_A => Self::LinearA, ffi::G_UNICODE_SCRIPT_MAHAJANI => Self::Mahajani, ffi::G_UNICODE_SCRIPT_MANICHAEAN => Self::Manichaean, ffi::G_UNICODE_SCRIPT_MENDE_KIKAKUI => Self::MendeKikakui, ffi::G_UNICODE_SCRIPT_MODI => Self::Modi, ffi::G_UNICODE_SCRIPT_MRO => Self::Mro, ffi::G_UNICODE_SCRIPT_NABATAEAN => Self::Nabataean, ffi::G_UNICODE_SCRIPT_OLD_NORTH_ARABIAN => Self::OldNorthArabian, ffi::G_UNICODE_SCRIPT_OLD_PERMIC => Self::OldPermic, ffi::G_UNICODE_SCRIPT_PAHAWH_HMONG => Self::PahawhHmong, ffi::G_UNICODE_SCRIPT_PALMYRENE => Self::Palmyrene, ffi::G_UNICODE_SCRIPT_PAU_CIN_HAU => Self::PauCinHau, ffi::G_UNICODE_SCRIPT_PSALTER_PAHLAVI => Self::PsalterPahlavi, ffi::G_UNICODE_SCRIPT_SIDDHAM => Self::Siddham, ffi::G_UNICODE_SCRIPT_TIRHUTA => Self::Tirhuta, ffi::G_UNICODE_SCRIPT_WARANG_CITI => Self::WarangCiti, ffi::G_UNICODE_SCRIPT_AHOM => Self::Ahom, ffi::G_UNICODE_SCRIPT_ANATOLIAN_HIEROGLYPHS => Self::AnatolianHieroglyphs, ffi::G_UNICODE_SCRIPT_HATRAN => Self::Hatran, ffi::G_UNICODE_SCRIPT_MULTANI => Self::Multani, ffi::G_UNICODE_SCRIPT_OLD_HUNGARIAN => Self::OldHungarian, ffi::G_UNICODE_SCRIPT_SIGNWRITING => Self::Signwriting, ffi::G_UNICODE_SCRIPT_ADLAM => Self::Adlam, ffi::G_UNICODE_SCRIPT_BHAIKSUKI => Self::Bhaiksuki, ffi::G_UNICODE_SCRIPT_MARCHEN => Self::Marchen, ffi::G_UNICODE_SCRIPT_NEWA => Self::Newa, ffi::G_UNICODE_SCRIPT_OSAGE => Self::Osage, ffi::G_UNICODE_SCRIPT_TANGUT => Self::Tangut, ffi::G_UNICODE_SCRIPT_MASARAM_GONDI => Self::MasaramGondi, ffi::G_UNICODE_SCRIPT_NUSHU => Self::Nushu, ffi::G_UNICODE_SCRIPT_SOYOMBO => Self::Soyombo, ffi::G_UNICODE_SCRIPT_ZANABAZAR_SQUARE => Self::ZanabazarSquare, ffi::G_UNICODE_SCRIPT_DOGRA => Self::Dogra, ffi::G_UNICODE_SCRIPT_GUNJALA_GONDI => Self::GunjalaGondi, ffi::G_UNICODE_SCRIPT_HANIFI_ROHINGYA => Self::HanifiRohingya, ffi::G_UNICODE_SCRIPT_MAKASAR => Self::Makasar, ffi::G_UNICODE_SCRIPT_MEDEFAIDRIN => Self::Medefaidrin, ffi::G_UNICODE_SCRIPT_OLD_SOGDIAN => Self::OldSogdian, ffi::G_UNICODE_SCRIPT_SOGDIAN => Self::Sogdian, ffi::G_UNICODE_SCRIPT_ELYMAIC => Self::Elymaic, ffi::G_UNICODE_SCRIPT_NANDINAGARI => Self::Nandinagari, ffi::G_UNICODE_SCRIPT_NYIAKENG_PUACHUE_HMONG => Self::NyiakengPuachueHmong, ffi::G_UNICODE_SCRIPT_WANCHO => Self::Wancho, ffi::G_UNICODE_SCRIPT_CHORASMIAN => Self::Chorasmian, ffi::G_UNICODE_SCRIPT_DIVES_AKURU => Self::DivesAkuru, ffi::G_UNICODE_SCRIPT_KHITAN_SMALL_SCRIPT => Self::KhitanSmallScript, ffi::G_UNICODE_SCRIPT_YEZIDI => Self::Yezidi, #[cfg(feature = "v2_72")] ffi::G_UNICODE_SCRIPT_CYPRO_MINOAN => Self::CyproMinoan, #[cfg(feature = "v2_72")] ffi::G_UNICODE_SCRIPT_OLD_UYGHUR => Self::OldUyghur, #[cfg(feature = "v2_72")] ffi::G_UNICODE_SCRIPT_TANGSA => Self::Tangsa, #[cfg(feature = "v2_72")] ffi::G_UNICODE_SCRIPT_TOTO => Self::Toto, #[cfg(feature = "v2_72")] ffi::G_UNICODE_SCRIPT_VITHKUQI => Self::Vithkuqi, #[cfg(feature = "v2_72")] ffi::G_UNICODE_SCRIPT_MATH => Self::Math, #[cfg(feature = "v2_74")] ffi::G_UNICODE_SCRIPT_KAWI => Self::Kawi, #[cfg(feature = "v2_74")] ffi::G_UNICODE_SCRIPT_NAG_MUNDARI => Self::NagMundari, #[cfg(feature = "v2_84")] ffi::G_UNICODE_SCRIPT_TODHRI => Self::Todhri, #[cfg(feature = "v2_84")] ffi::G_UNICODE_SCRIPT_GARAY => Self::Garay, #[cfg(feature = "v2_84")] ffi::G_UNICODE_SCRIPT_TULU_TIGALARI => Self::TuluTigalari, #[cfg(feature = "v2_84")] ffi::G_UNICODE_SCRIPT_SUNUWAR => Self::Sunuwar, #[cfg(feature = "v2_84")] ffi::G_UNICODE_SCRIPT_GURUNG_KHEMA => Self::GurungKhema, #[cfg(feature = "v2_84")] ffi::G_UNICODE_SCRIPT_KIRAT_RAI => Self::KiratRai, #[cfg(feature = "v2_84")] ffi::G_UNICODE_SCRIPT_OL_ONAL => Self::OlOnal, value => Self::__Unknown(value), } } } impl StaticType for UnicodeScript { #[inline] #[doc(alias = "g_unicode_script_get_type")] fn static_type() -> crate::Type { unsafe { from_glib(ffi::g_unicode_script_get_type()) } } } impl crate::HasParamSpec for UnicodeScript { type ParamSpec = crate::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> crate::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl crate::value::ValueType for UnicodeScript { type Type = Self; } unsafe impl<'a> crate::value::FromValue<'a> for UnicodeScript { type Checker = crate::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a crate::Value) -> Self { from_glib(crate::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for UnicodeScript { #[inline] fn to_value(&self) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { crate::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> crate::Type { Self::static_type() } } impl From for crate::Value { #[inline] fn from(v: UnicodeScript) -> Self { ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GUnicodeType")] pub enum UnicodeType { #[doc(alias = "G_UNICODE_CONTROL")] Control, #[doc(alias = "G_UNICODE_FORMAT")] Format, #[doc(alias = "G_UNICODE_UNASSIGNED")] Unassigned, #[doc(alias = "G_UNICODE_PRIVATE_USE")] PrivateUse, #[doc(alias = "G_UNICODE_SURROGATE")] Surrogate, #[doc(alias = "G_UNICODE_LOWERCASE_LETTER")] LowercaseLetter, #[doc(alias = "G_UNICODE_MODIFIER_LETTER")] ModifierLetter, #[doc(alias = "G_UNICODE_OTHER_LETTER")] OtherLetter, #[doc(alias = "G_UNICODE_TITLECASE_LETTER")] TitlecaseLetter, #[doc(alias = "G_UNICODE_UPPERCASE_LETTER")] UppercaseLetter, #[doc(alias = "G_UNICODE_SPACING_MARK")] SpacingMark, #[doc(alias = "G_UNICODE_ENCLOSING_MARK")] EnclosingMark, #[doc(alias = "G_UNICODE_NON_SPACING_MARK")] NonSpacingMark, #[doc(alias = "G_UNICODE_DECIMAL_NUMBER")] DecimalNumber, #[doc(alias = "G_UNICODE_LETTER_NUMBER")] LetterNumber, #[doc(alias = "G_UNICODE_OTHER_NUMBER")] OtherNumber, #[doc(alias = "G_UNICODE_CONNECT_PUNCTUATION")] ConnectPunctuation, #[doc(alias = "G_UNICODE_DASH_PUNCTUATION")] DashPunctuation, #[doc(alias = "G_UNICODE_CLOSE_PUNCTUATION")] ClosePunctuation, #[doc(alias = "G_UNICODE_FINAL_PUNCTUATION")] FinalPunctuation, #[doc(alias = "G_UNICODE_INITIAL_PUNCTUATION")] InitialPunctuation, #[doc(alias = "G_UNICODE_OTHER_PUNCTUATION")] OtherPunctuation, #[doc(alias = "G_UNICODE_OPEN_PUNCTUATION")] OpenPunctuation, #[doc(alias = "G_UNICODE_CURRENCY_SYMBOL")] CurrencySymbol, #[doc(alias = "G_UNICODE_MODIFIER_SYMBOL")] ModifierSymbol, #[doc(alias = "G_UNICODE_MATH_SYMBOL")] MathSymbol, #[doc(alias = "G_UNICODE_OTHER_SYMBOL")] OtherSymbol, #[doc(alias = "G_UNICODE_LINE_SEPARATOR")] LineSeparator, #[doc(alias = "G_UNICODE_PARAGRAPH_SEPARATOR")] ParagraphSeparator, #[doc(alias = "G_UNICODE_SPACE_SEPARATOR")] SpaceSeparator, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for UnicodeType { type GlibType = ffi::GUnicodeType; fn into_glib(self) -> ffi::GUnicodeType { match self { Self::Control => ffi::G_UNICODE_CONTROL, Self::Format => ffi::G_UNICODE_FORMAT, Self::Unassigned => ffi::G_UNICODE_UNASSIGNED, Self::PrivateUse => ffi::G_UNICODE_PRIVATE_USE, Self::Surrogate => ffi::G_UNICODE_SURROGATE, Self::LowercaseLetter => ffi::G_UNICODE_LOWERCASE_LETTER, Self::ModifierLetter => ffi::G_UNICODE_MODIFIER_LETTER, Self::OtherLetter => ffi::G_UNICODE_OTHER_LETTER, Self::TitlecaseLetter => ffi::G_UNICODE_TITLECASE_LETTER, Self::UppercaseLetter => ffi::G_UNICODE_UPPERCASE_LETTER, Self::SpacingMark => ffi::G_UNICODE_SPACING_MARK, Self::EnclosingMark => ffi::G_UNICODE_ENCLOSING_MARK, Self::NonSpacingMark => ffi::G_UNICODE_NON_SPACING_MARK, Self::DecimalNumber => ffi::G_UNICODE_DECIMAL_NUMBER, Self::LetterNumber => ffi::G_UNICODE_LETTER_NUMBER, Self::OtherNumber => ffi::G_UNICODE_OTHER_NUMBER, Self::ConnectPunctuation => ffi::G_UNICODE_CONNECT_PUNCTUATION, Self::DashPunctuation => ffi::G_UNICODE_DASH_PUNCTUATION, Self::ClosePunctuation => ffi::G_UNICODE_CLOSE_PUNCTUATION, Self::FinalPunctuation => ffi::G_UNICODE_FINAL_PUNCTUATION, Self::InitialPunctuation => ffi::G_UNICODE_INITIAL_PUNCTUATION, Self::OtherPunctuation => ffi::G_UNICODE_OTHER_PUNCTUATION, Self::OpenPunctuation => ffi::G_UNICODE_OPEN_PUNCTUATION, Self::CurrencySymbol => ffi::G_UNICODE_CURRENCY_SYMBOL, Self::ModifierSymbol => ffi::G_UNICODE_MODIFIER_SYMBOL, Self::MathSymbol => ffi::G_UNICODE_MATH_SYMBOL, Self::OtherSymbol => ffi::G_UNICODE_OTHER_SYMBOL, Self::LineSeparator => ffi::G_UNICODE_LINE_SEPARATOR, Self::ParagraphSeparator => ffi::G_UNICODE_PARAGRAPH_SEPARATOR, Self::SpaceSeparator => ffi::G_UNICODE_SPACE_SEPARATOR, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for UnicodeType { unsafe fn from_glib(value: ffi::GUnicodeType) -> Self { match value { ffi::G_UNICODE_CONTROL => Self::Control, ffi::G_UNICODE_FORMAT => Self::Format, ffi::G_UNICODE_UNASSIGNED => Self::Unassigned, ffi::G_UNICODE_PRIVATE_USE => Self::PrivateUse, ffi::G_UNICODE_SURROGATE => Self::Surrogate, ffi::G_UNICODE_LOWERCASE_LETTER => Self::LowercaseLetter, ffi::G_UNICODE_MODIFIER_LETTER => Self::ModifierLetter, ffi::G_UNICODE_OTHER_LETTER => Self::OtherLetter, ffi::G_UNICODE_TITLECASE_LETTER => Self::TitlecaseLetter, ffi::G_UNICODE_UPPERCASE_LETTER => Self::UppercaseLetter, ffi::G_UNICODE_SPACING_MARK => Self::SpacingMark, ffi::G_UNICODE_ENCLOSING_MARK => Self::EnclosingMark, ffi::G_UNICODE_NON_SPACING_MARK => Self::NonSpacingMark, ffi::G_UNICODE_DECIMAL_NUMBER => Self::DecimalNumber, ffi::G_UNICODE_LETTER_NUMBER => Self::LetterNumber, ffi::G_UNICODE_OTHER_NUMBER => Self::OtherNumber, ffi::G_UNICODE_CONNECT_PUNCTUATION => Self::ConnectPunctuation, ffi::G_UNICODE_DASH_PUNCTUATION => Self::DashPunctuation, ffi::G_UNICODE_CLOSE_PUNCTUATION => Self::ClosePunctuation, ffi::G_UNICODE_FINAL_PUNCTUATION => Self::FinalPunctuation, ffi::G_UNICODE_INITIAL_PUNCTUATION => Self::InitialPunctuation, ffi::G_UNICODE_OTHER_PUNCTUATION => Self::OtherPunctuation, ffi::G_UNICODE_OPEN_PUNCTUATION => Self::OpenPunctuation, ffi::G_UNICODE_CURRENCY_SYMBOL => Self::CurrencySymbol, ffi::G_UNICODE_MODIFIER_SYMBOL => Self::ModifierSymbol, ffi::G_UNICODE_MATH_SYMBOL => Self::MathSymbol, ffi::G_UNICODE_OTHER_SYMBOL => Self::OtherSymbol, ffi::G_UNICODE_LINE_SEPARATOR => Self::LineSeparator, ffi::G_UNICODE_PARAGRAPH_SEPARATOR => Self::ParagraphSeparator, ffi::G_UNICODE_SPACE_SEPARATOR => Self::SpaceSeparator, value => Self::__Unknown(value), } } } impl StaticType for UnicodeType { #[inline] #[doc(alias = "g_unicode_type_get_type")] fn static_type() -> crate::Type { unsafe { from_glib(ffi::g_unicode_type_get_type()) } } } impl crate::HasParamSpec for UnicodeType { type ParamSpec = crate::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> crate::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl crate::value::ValueType for UnicodeType { type Type = Self; } unsafe impl<'a> crate::value::FromValue<'a> for UnicodeType { type Checker = crate::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a crate::Value) -> Self { from_glib(crate::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for UnicodeType { #[inline] fn to_value(&self) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { crate::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> crate::Type { Self::static_type() } } impl From for crate::Value { #[inline] fn from(v: UnicodeType) -> Self { ToValue::to_value(&v) } } #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GUriError")] pub enum UriError { #[doc(alias = "G_URI_ERROR_FAILED")] Failed, #[doc(alias = "G_URI_ERROR_BAD_SCHEME")] BadScheme, #[doc(alias = "G_URI_ERROR_BAD_USER")] BadUser, #[doc(alias = "G_URI_ERROR_BAD_PASSWORD")] BadPassword, #[doc(alias = "G_URI_ERROR_BAD_AUTH_PARAMS")] BadAuthParams, #[doc(alias = "G_URI_ERROR_BAD_HOST")] BadHost, #[doc(alias = "G_URI_ERROR_BAD_PORT")] BadPort, #[doc(alias = "G_URI_ERROR_BAD_PATH")] BadPath, #[doc(alias = "G_URI_ERROR_BAD_QUERY")] BadQuery, #[doc(alias = "G_URI_ERROR_BAD_FRAGMENT")] BadFragment, #[doc(hidden)] __Unknown(i32), } #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl IntoGlib for UriError { type GlibType = ffi::GUriError; #[inline] fn into_glib(self) -> ffi::GUriError { match self { Self::Failed => ffi::G_URI_ERROR_FAILED, Self::BadScheme => ffi::G_URI_ERROR_BAD_SCHEME, Self::BadUser => ffi::G_URI_ERROR_BAD_USER, Self::BadPassword => ffi::G_URI_ERROR_BAD_PASSWORD, Self::BadAuthParams => ffi::G_URI_ERROR_BAD_AUTH_PARAMS, Self::BadHost => ffi::G_URI_ERROR_BAD_HOST, Self::BadPort => ffi::G_URI_ERROR_BAD_PORT, Self::BadPath => ffi::G_URI_ERROR_BAD_PATH, Self::BadQuery => ffi::G_URI_ERROR_BAD_QUERY, Self::BadFragment => ffi::G_URI_ERROR_BAD_FRAGMENT, Self::__Unknown(value) => value, } } } #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl FromGlib for UriError { #[inline] unsafe fn from_glib(value: ffi::GUriError) -> Self { match value { ffi::G_URI_ERROR_FAILED => Self::Failed, ffi::G_URI_ERROR_BAD_SCHEME => Self::BadScheme, ffi::G_URI_ERROR_BAD_USER => Self::BadUser, ffi::G_URI_ERROR_BAD_PASSWORD => Self::BadPassword, ffi::G_URI_ERROR_BAD_AUTH_PARAMS => Self::BadAuthParams, ffi::G_URI_ERROR_BAD_HOST => Self::BadHost, ffi::G_URI_ERROR_BAD_PORT => Self::BadPort, ffi::G_URI_ERROR_BAD_PATH => Self::BadPath, ffi::G_URI_ERROR_BAD_QUERY => Self::BadQuery, ffi::G_URI_ERROR_BAD_FRAGMENT => Self::BadFragment, value => Self::__Unknown(value), } } } #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] impl crate::error::ErrorDomain for UriError { #[inline] fn domain() -> crate::Quark { unsafe { from_glib(ffi::g_uri_error_quark()) } } #[inline] fn code(self) -> i32 { self.into_glib() } #[inline] #[allow(clippy::match_single_binding)] fn from(code: i32) -> Option { match unsafe { from_glib(code) } { Self::__Unknown(_) => Some(Self::Failed), value => Some(value), } } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GVariantClass")] pub enum VariantClass { #[doc(alias = "G_VARIANT_CLASS_BOOLEAN")] Boolean, #[doc(alias = "G_VARIANT_CLASS_BYTE")] Byte, #[doc(alias = "G_VARIANT_CLASS_INT16")] Int16, #[doc(alias = "G_VARIANT_CLASS_UINT16")] Uint16, #[doc(alias = "G_VARIANT_CLASS_INT32")] Int32, #[doc(alias = "G_VARIANT_CLASS_UINT32")] Uint32, #[doc(alias = "G_VARIANT_CLASS_INT64")] Int64, #[doc(alias = "G_VARIANT_CLASS_UINT64")] Uint64, #[doc(alias = "G_VARIANT_CLASS_HANDLE")] Handle, #[doc(alias = "G_VARIANT_CLASS_DOUBLE")] Double, #[doc(alias = "G_VARIANT_CLASS_STRING")] String, #[doc(alias = "G_VARIANT_CLASS_OBJECT_PATH")] ObjectPath, #[doc(alias = "G_VARIANT_CLASS_SIGNATURE")] Signature, #[doc(alias = "G_VARIANT_CLASS_VARIANT")] Variant, #[doc(alias = "G_VARIANT_CLASS_MAYBE")] Maybe, #[doc(alias = "G_VARIANT_CLASS_ARRAY")] Array, #[doc(alias = "G_VARIANT_CLASS_TUPLE")] Tuple, #[doc(alias = "G_VARIANT_CLASS_DICT_ENTRY")] DictEntry, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for VariantClass { type GlibType = ffi::GVariantClass; fn into_glib(self) -> ffi::GVariantClass { match self { Self::Boolean => ffi::G_VARIANT_CLASS_BOOLEAN, Self::Byte => ffi::G_VARIANT_CLASS_BYTE, Self::Int16 => ffi::G_VARIANT_CLASS_INT16, Self::Uint16 => ffi::G_VARIANT_CLASS_UINT16, Self::Int32 => ffi::G_VARIANT_CLASS_INT32, Self::Uint32 => ffi::G_VARIANT_CLASS_UINT32, Self::Int64 => ffi::G_VARIANT_CLASS_INT64, Self::Uint64 => ffi::G_VARIANT_CLASS_UINT64, Self::Handle => ffi::G_VARIANT_CLASS_HANDLE, Self::Double => ffi::G_VARIANT_CLASS_DOUBLE, Self::String => ffi::G_VARIANT_CLASS_STRING, Self::ObjectPath => ffi::G_VARIANT_CLASS_OBJECT_PATH, Self::Signature => ffi::G_VARIANT_CLASS_SIGNATURE, Self::Variant => ffi::G_VARIANT_CLASS_VARIANT, Self::Maybe => ffi::G_VARIANT_CLASS_MAYBE, Self::Array => ffi::G_VARIANT_CLASS_ARRAY, Self::Tuple => ffi::G_VARIANT_CLASS_TUPLE, Self::DictEntry => ffi::G_VARIANT_CLASS_DICT_ENTRY, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for VariantClass { unsafe fn from_glib(value: ffi::GVariantClass) -> Self { match value { ffi::G_VARIANT_CLASS_BOOLEAN => Self::Boolean, ffi::G_VARIANT_CLASS_BYTE => Self::Byte, ffi::G_VARIANT_CLASS_INT16 => Self::Int16, ffi::G_VARIANT_CLASS_UINT16 => Self::Uint16, ffi::G_VARIANT_CLASS_INT32 => Self::Int32, ffi::G_VARIANT_CLASS_UINT32 => Self::Uint32, ffi::G_VARIANT_CLASS_INT64 => Self::Int64, ffi::G_VARIANT_CLASS_UINT64 => Self::Uint64, ffi::G_VARIANT_CLASS_HANDLE => Self::Handle, ffi::G_VARIANT_CLASS_DOUBLE => Self::Double, ffi::G_VARIANT_CLASS_STRING => Self::String, ffi::G_VARIANT_CLASS_OBJECT_PATH => Self::ObjectPath, ffi::G_VARIANT_CLASS_SIGNATURE => Self::Signature, ffi::G_VARIANT_CLASS_VARIANT => Self::Variant, ffi::G_VARIANT_CLASS_MAYBE => Self::Maybe, ffi::G_VARIANT_CLASS_ARRAY => Self::Array, ffi::G_VARIANT_CLASS_TUPLE => Self::Tuple, ffi::G_VARIANT_CLASS_DICT_ENTRY => Self::DictEntry, value => Self::__Unknown(value), } } } glib-0.20.9/src/auto/flags.rs000064400000000000000000000544301046102023000140400ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::{bitflags::bitflags, ffi, prelude::*, translate::*}; #[cfg(feature = "v2_66")] bitflags! { #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GFileSetContentsFlags")] pub struct FileSetContentsFlags: u32 { #[doc(alias = "G_FILE_SET_CONTENTS_NONE")] const NONE = ffi::G_FILE_SET_CONTENTS_NONE as _; #[doc(alias = "G_FILE_SET_CONTENTS_CONSISTENT")] const CONSISTENT = ffi::G_FILE_SET_CONTENTS_CONSISTENT as _; #[doc(alias = "G_FILE_SET_CONTENTS_DURABLE")] const DURABLE = ffi::G_FILE_SET_CONTENTS_DURABLE as _; #[doc(alias = "G_FILE_SET_CONTENTS_ONLY_EXISTING")] const ONLY_EXISTING = ffi::G_FILE_SET_CONTENTS_ONLY_EXISTING as _; } } #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl IntoGlib for FileSetContentsFlags { type GlibType = ffi::GFileSetContentsFlags; #[inline] fn into_glib(self) -> ffi::GFileSetContentsFlags { self.bits() } } #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl FromGlib for FileSetContentsFlags { #[inline] unsafe fn from_glib(value: ffi::GFileSetContentsFlags) -> Self { Self::from_bits_truncate(value) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GFileTest")] pub(crate) struct FileTest: u32 { #[doc(alias = "G_FILE_TEST_IS_REGULAR")] const IS_REGULAR = ffi::G_FILE_TEST_IS_REGULAR as _; #[doc(alias = "G_FILE_TEST_IS_SYMLINK")] const IS_SYMLINK = ffi::G_FILE_TEST_IS_SYMLINK as _; #[doc(alias = "G_FILE_TEST_IS_DIR")] const IS_DIR = ffi::G_FILE_TEST_IS_DIR as _; #[doc(alias = "G_FILE_TEST_IS_EXECUTABLE")] const IS_EXECUTABLE = ffi::G_FILE_TEST_IS_EXECUTABLE as _; #[doc(alias = "G_FILE_TEST_EXISTS")] const EXISTS = ffi::G_FILE_TEST_EXISTS as _; } } #[doc(hidden)] impl IntoGlib for FileTest { type GlibType = ffi::GFileTest; #[inline] fn into_glib(self) -> ffi::GFileTest { self.bits() } } #[doc(hidden)] impl FromGlib for FileTest { #[inline] unsafe fn from_glib(value: ffi::GFileTest) -> Self { Self::from_bits_truncate(value) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GFormatSizeFlags")] pub struct FormatSizeFlags: u32 { #[doc(alias = "G_FORMAT_SIZE_DEFAULT")] const DEFAULT = ffi::G_FORMAT_SIZE_DEFAULT as _; #[doc(alias = "G_FORMAT_SIZE_LONG_FORMAT")] const LONG_FORMAT = ffi::G_FORMAT_SIZE_LONG_FORMAT as _; #[doc(alias = "G_FORMAT_SIZE_IEC_UNITS")] const IEC_UNITS = ffi::G_FORMAT_SIZE_IEC_UNITS as _; #[doc(alias = "G_FORMAT_SIZE_BITS")] const BITS = ffi::G_FORMAT_SIZE_BITS as _; #[cfg(feature = "v2_74")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))] #[doc(alias = "G_FORMAT_SIZE_ONLY_VALUE")] const ONLY_VALUE = ffi::G_FORMAT_SIZE_ONLY_VALUE as _; #[cfg(feature = "v2_74")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))] #[doc(alias = "G_FORMAT_SIZE_ONLY_UNIT")] const ONLY_UNIT = ffi::G_FORMAT_SIZE_ONLY_UNIT as _; } } #[doc(hidden)] impl IntoGlib for FormatSizeFlags { type GlibType = ffi::GFormatSizeFlags; #[inline] fn into_glib(self) -> ffi::GFormatSizeFlags { self.bits() } } #[doc(hidden)] impl FromGlib for FormatSizeFlags { #[inline] unsafe fn from_glib(value: ffi::GFormatSizeFlags) -> Self { Self::from_bits_truncate(value) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GIOCondition")] pub struct IOCondition: u32 { #[doc(alias = "G_IO_IN")] const IN = ffi::G_IO_IN as _; #[doc(alias = "G_IO_OUT")] const OUT = ffi::G_IO_OUT as _; #[doc(alias = "G_IO_PRI")] const PRI = ffi::G_IO_PRI as _; #[doc(alias = "G_IO_ERR")] const ERR = ffi::G_IO_ERR as _; #[doc(alias = "G_IO_HUP")] const HUP = ffi::G_IO_HUP as _; #[doc(alias = "G_IO_NVAL")] const NVAL = ffi::G_IO_NVAL as _; } } #[doc(hidden)] impl IntoGlib for IOCondition { type GlibType = ffi::GIOCondition; #[inline] fn into_glib(self) -> ffi::GIOCondition { self.bits() } } #[doc(hidden)] impl FromGlib for IOCondition { #[inline] unsafe fn from_glib(value: ffi::GIOCondition) -> Self { Self::from_bits_truncate(value) } } impl StaticType for IOCondition { #[inline] #[doc(alias = "g_io_condition_get_type")] fn static_type() -> crate::Type { unsafe { from_glib(ffi::g_io_condition_get_type()) } } } impl crate::HasParamSpec for IOCondition { type ParamSpec = crate::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> crate::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl crate::value::ValueType for IOCondition { type Type = Self; } unsafe impl<'a> crate::value::FromValue<'a> for IOCondition { type Checker = crate::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a crate::Value) -> Self { from_glib(crate::gobject_ffi::g_value_get_flags( value.to_glib_none().0, )) } } impl ToValue for IOCondition { #[inline] fn to_value(&self) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { crate::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> crate::Type { Self::static_type() } } impl From for crate::Value { #[inline] fn from(v: IOCondition) -> Self { ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GKeyFileFlags")] pub struct KeyFileFlags: u32 { #[doc(alias = "G_KEY_FILE_NONE")] const NONE = ffi::G_KEY_FILE_NONE as _; #[doc(alias = "G_KEY_FILE_KEEP_COMMENTS")] const KEEP_COMMENTS = ffi::G_KEY_FILE_KEEP_COMMENTS as _; #[doc(alias = "G_KEY_FILE_KEEP_TRANSLATIONS")] const KEEP_TRANSLATIONS = ffi::G_KEY_FILE_KEEP_TRANSLATIONS as _; } } #[doc(hidden)] impl IntoGlib for KeyFileFlags { type GlibType = ffi::GKeyFileFlags; #[inline] fn into_glib(self) -> ffi::GKeyFileFlags { self.bits() } } #[doc(hidden)] impl FromGlib for KeyFileFlags { #[inline] unsafe fn from_glib(value: ffi::GKeyFileFlags) -> Self { Self::from_bits_truncate(value) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GLogLevelFlags")] pub struct LogLevelFlags: u32 { #[doc(alias = "G_LOG_FLAG_RECURSION")] const FLAG_RECURSION = ffi::G_LOG_FLAG_RECURSION as _; #[doc(alias = "G_LOG_FLAG_FATAL")] const FLAG_FATAL = ffi::G_LOG_FLAG_FATAL as _; #[doc(alias = "G_LOG_LEVEL_ERROR")] const LEVEL_ERROR = ffi::G_LOG_LEVEL_ERROR as _; #[doc(alias = "G_LOG_LEVEL_CRITICAL")] const LEVEL_CRITICAL = ffi::G_LOG_LEVEL_CRITICAL as _; #[doc(alias = "G_LOG_LEVEL_WARNING")] const LEVEL_WARNING = ffi::G_LOG_LEVEL_WARNING as _; #[doc(alias = "G_LOG_LEVEL_MESSAGE")] const LEVEL_MESSAGE = ffi::G_LOG_LEVEL_MESSAGE as _; #[doc(alias = "G_LOG_LEVEL_INFO")] const LEVEL_INFO = ffi::G_LOG_LEVEL_INFO as _; #[doc(alias = "G_LOG_LEVEL_DEBUG")] const LEVEL_DEBUG = ffi::G_LOG_LEVEL_DEBUG as _; #[doc(alias = "G_LOG_LEVEL_MASK")] const LEVEL_MASK = ffi::G_LOG_LEVEL_MASK as _; } } #[doc(hidden)] impl IntoGlib for LogLevelFlags { type GlibType = ffi::GLogLevelFlags; #[inline] fn into_glib(self) -> ffi::GLogLevelFlags { self.bits() } } #[doc(hidden)] impl FromGlib for LogLevelFlags { #[inline] unsafe fn from_glib(value: ffi::GLogLevelFlags) -> Self { Self::from_bits_truncate(value) } } #[cfg(feature = "v2_72")] bitflags! { #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GMainContextFlags")] pub struct MainContextFlags: u32 { #[doc(alias = "G_MAIN_CONTEXT_FLAGS_NONE")] const NONE = ffi::G_MAIN_CONTEXT_FLAGS_NONE as _; #[doc(alias = "G_MAIN_CONTEXT_FLAGS_OWNERLESS_POLLING")] const OWNERLESS_POLLING = ffi::G_MAIN_CONTEXT_FLAGS_OWNERLESS_POLLING as _; } } #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] #[doc(hidden)] impl IntoGlib for MainContextFlags { type GlibType = ffi::GMainContextFlags; #[inline] fn into_glib(self) -> ffi::GMainContextFlags { self.bits() } } #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] #[doc(hidden)] impl FromGlib for MainContextFlags { #[inline] unsafe fn from_glib(value: ffi::GMainContextFlags) -> Self { Self::from_bits_truncate(value) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GOptionFlags")] pub struct OptionFlags: u32 { #[doc(alias = "G_OPTION_FLAG_NONE")] const NONE = ffi::G_OPTION_FLAG_NONE as _; #[doc(alias = "G_OPTION_FLAG_HIDDEN")] const HIDDEN = ffi::G_OPTION_FLAG_HIDDEN as _; #[doc(alias = "G_OPTION_FLAG_IN_MAIN")] const IN_MAIN = ffi::G_OPTION_FLAG_IN_MAIN as _; #[doc(alias = "G_OPTION_FLAG_REVERSE")] const REVERSE = ffi::G_OPTION_FLAG_REVERSE as _; #[doc(alias = "G_OPTION_FLAG_NO_ARG")] const NO_ARG = ffi::G_OPTION_FLAG_NO_ARG as _; #[doc(alias = "G_OPTION_FLAG_FILENAME")] const FILENAME = ffi::G_OPTION_FLAG_FILENAME as _; #[doc(alias = "G_OPTION_FLAG_OPTIONAL_ARG")] const OPTIONAL_ARG = ffi::G_OPTION_FLAG_OPTIONAL_ARG as _; #[doc(alias = "G_OPTION_FLAG_NOALIAS")] const NOALIAS = ffi::G_OPTION_FLAG_NOALIAS as _; #[cfg(feature = "v2_84")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_84")))] #[doc(alias = "G_OPTION_FLAG_DEPRECATED")] const DEPRECATED = ffi::G_OPTION_FLAG_DEPRECATED as _; } } #[doc(hidden)] impl IntoGlib for OptionFlags { type GlibType = ffi::GOptionFlags; #[inline] fn into_glib(self) -> ffi::GOptionFlags { self.bits() } } #[doc(hidden)] impl FromGlib for OptionFlags { #[inline] unsafe fn from_glib(value: ffi::GOptionFlags) -> Self { Self::from_bits_truncate(value) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GRegexCompileFlags")] pub struct RegexCompileFlags: u32 { #[doc(alias = "G_REGEX_DEFAULT")] const DEFAULT = ffi::G_REGEX_DEFAULT as _; #[doc(alias = "G_REGEX_CASELESS")] const CASELESS = ffi::G_REGEX_CASELESS as _; #[doc(alias = "G_REGEX_MULTILINE")] const MULTILINE = ffi::G_REGEX_MULTILINE as _; #[doc(alias = "G_REGEX_DOTALL")] const DOTALL = ffi::G_REGEX_DOTALL as _; #[doc(alias = "G_REGEX_EXTENDED")] const EXTENDED = ffi::G_REGEX_EXTENDED as _; #[doc(alias = "G_REGEX_ANCHORED")] const ANCHORED = ffi::G_REGEX_ANCHORED as _; #[doc(alias = "G_REGEX_DOLLAR_ENDONLY")] const DOLLAR_ENDONLY = ffi::G_REGEX_DOLLAR_ENDONLY as _; #[doc(alias = "G_REGEX_UNGREEDY")] const UNGREEDY = ffi::G_REGEX_UNGREEDY as _; #[doc(alias = "G_REGEX_RAW")] const RAW = ffi::G_REGEX_RAW as _; #[doc(alias = "G_REGEX_NO_AUTO_CAPTURE")] const NO_AUTO_CAPTURE = ffi::G_REGEX_NO_AUTO_CAPTURE as _; #[doc(alias = "G_REGEX_OPTIMIZE")] const OPTIMIZE = ffi::G_REGEX_OPTIMIZE as _; #[doc(alias = "G_REGEX_FIRSTLINE")] const FIRSTLINE = ffi::G_REGEX_FIRSTLINE as _; #[doc(alias = "G_REGEX_DUPNAMES")] const DUPNAMES = ffi::G_REGEX_DUPNAMES as _; #[doc(alias = "G_REGEX_NEWLINE_CR")] const NEWLINE_CR = ffi::G_REGEX_NEWLINE_CR as _; #[doc(alias = "G_REGEX_NEWLINE_LF")] const NEWLINE_LF = ffi::G_REGEX_NEWLINE_LF as _; #[doc(alias = "G_REGEX_NEWLINE_CRLF")] const NEWLINE_CRLF = ffi::G_REGEX_NEWLINE_CRLF as _; #[doc(alias = "G_REGEX_NEWLINE_ANYCRLF")] const NEWLINE_ANYCRLF = ffi::G_REGEX_NEWLINE_ANYCRLF as _; #[doc(alias = "G_REGEX_BSR_ANYCRLF")] const BSR_ANYCRLF = ffi::G_REGEX_BSR_ANYCRLF as _; #[doc(alias = "G_REGEX_JAVASCRIPT_COMPAT")] const JAVASCRIPT_COMPAT = ffi::G_REGEX_JAVASCRIPT_COMPAT as _; } } #[doc(hidden)] impl IntoGlib for RegexCompileFlags { type GlibType = ffi::GRegexCompileFlags; #[inline] fn into_glib(self) -> ffi::GRegexCompileFlags { self.bits() } } #[doc(hidden)] impl FromGlib for RegexCompileFlags { #[inline] unsafe fn from_glib(value: ffi::GRegexCompileFlags) -> Self { Self::from_bits_truncate(value) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GRegexMatchFlags")] pub struct RegexMatchFlags: u32 { #[doc(alias = "G_REGEX_MATCH_DEFAULT")] const DEFAULT = ffi::G_REGEX_MATCH_DEFAULT as _; #[doc(alias = "G_REGEX_MATCH_ANCHORED")] const ANCHORED = ffi::G_REGEX_MATCH_ANCHORED as _; #[doc(alias = "G_REGEX_MATCH_NOTBOL")] const NOTBOL = ffi::G_REGEX_MATCH_NOTBOL as _; #[doc(alias = "G_REGEX_MATCH_NOTEOL")] const NOTEOL = ffi::G_REGEX_MATCH_NOTEOL as _; #[doc(alias = "G_REGEX_MATCH_NOTEMPTY")] const NOTEMPTY = ffi::G_REGEX_MATCH_NOTEMPTY as _; #[doc(alias = "G_REGEX_MATCH_PARTIAL")] const PARTIAL = ffi::G_REGEX_MATCH_PARTIAL as _; #[doc(alias = "G_REGEX_MATCH_NEWLINE_CR")] const NEWLINE_CR = ffi::G_REGEX_MATCH_NEWLINE_CR as _; #[doc(alias = "G_REGEX_MATCH_NEWLINE_LF")] const NEWLINE_LF = ffi::G_REGEX_MATCH_NEWLINE_LF as _; #[doc(alias = "G_REGEX_MATCH_NEWLINE_CRLF")] const NEWLINE_CRLF = ffi::G_REGEX_MATCH_NEWLINE_CRLF as _; #[doc(alias = "G_REGEX_MATCH_NEWLINE_ANY")] const NEWLINE_ANY = ffi::G_REGEX_MATCH_NEWLINE_ANY as _; #[doc(alias = "G_REGEX_MATCH_NEWLINE_ANYCRLF")] const NEWLINE_ANYCRLF = ffi::G_REGEX_MATCH_NEWLINE_ANYCRLF as _; #[doc(alias = "G_REGEX_MATCH_BSR_ANYCRLF")] const BSR_ANYCRLF = ffi::G_REGEX_MATCH_BSR_ANYCRLF as _; #[doc(alias = "G_REGEX_MATCH_BSR_ANY")] const BSR_ANY = ffi::G_REGEX_MATCH_BSR_ANY as _; #[doc(alias = "G_REGEX_MATCH_PARTIAL_SOFT")] const PARTIAL_SOFT = ffi::G_REGEX_MATCH_PARTIAL_SOFT as _; #[doc(alias = "G_REGEX_MATCH_PARTIAL_HARD")] const PARTIAL_HARD = ffi::G_REGEX_MATCH_PARTIAL_HARD as _; #[doc(alias = "G_REGEX_MATCH_NOTEMPTY_ATSTART")] const NOTEMPTY_ATSTART = ffi::G_REGEX_MATCH_NOTEMPTY_ATSTART as _; } } #[doc(hidden)] impl IntoGlib for RegexMatchFlags { type GlibType = ffi::GRegexMatchFlags; #[inline] fn into_glib(self) -> ffi::GRegexMatchFlags { self.bits() } } #[doc(hidden)] impl FromGlib for RegexMatchFlags { #[inline] unsafe fn from_glib(value: ffi::GRegexMatchFlags) -> Self { Self::from_bits_truncate(value) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GSpawnFlags")] pub struct SpawnFlags: u32 { #[doc(alias = "G_SPAWN_DEFAULT")] const DEFAULT = ffi::G_SPAWN_DEFAULT as _; #[doc(alias = "G_SPAWN_LEAVE_DESCRIPTORS_OPEN")] const LEAVE_DESCRIPTORS_OPEN = ffi::G_SPAWN_LEAVE_DESCRIPTORS_OPEN as _; #[doc(alias = "G_SPAWN_DO_NOT_REAP_CHILD")] const DO_NOT_REAP_CHILD = ffi::G_SPAWN_DO_NOT_REAP_CHILD as _; #[doc(alias = "G_SPAWN_SEARCH_PATH")] const SEARCH_PATH = ffi::G_SPAWN_SEARCH_PATH as _; #[doc(alias = "G_SPAWN_STDOUT_TO_DEV_NULL")] const STDOUT_TO_DEV_NULL = ffi::G_SPAWN_STDOUT_TO_DEV_NULL as _; #[doc(alias = "G_SPAWN_STDERR_TO_DEV_NULL")] const STDERR_TO_DEV_NULL = ffi::G_SPAWN_STDERR_TO_DEV_NULL as _; #[doc(alias = "G_SPAWN_CHILD_INHERITS_STDIN")] const CHILD_INHERITS_STDIN = ffi::G_SPAWN_CHILD_INHERITS_STDIN as _; #[doc(alias = "G_SPAWN_FILE_AND_ARGV_ZERO")] const FILE_AND_ARGV_ZERO = ffi::G_SPAWN_FILE_AND_ARGV_ZERO as _; #[doc(alias = "G_SPAWN_SEARCH_PATH_FROM_ENVP")] const SEARCH_PATH_FROM_ENVP = ffi::G_SPAWN_SEARCH_PATH_FROM_ENVP as _; #[doc(alias = "G_SPAWN_CLOEXEC_PIPES")] const CLOEXEC_PIPES = ffi::G_SPAWN_CLOEXEC_PIPES as _; #[cfg(feature = "v2_74")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))] #[doc(alias = "G_SPAWN_CHILD_INHERITS_STDOUT")] const CHILD_INHERITS_STDOUT = ffi::G_SPAWN_CHILD_INHERITS_STDOUT as _; #[cfg(feature = "v2_74")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))] #[doc(alias = "G_SPAWN_CHILD_INHERITS_STDERR")] const CHILD_INHERITS_STDERR = ffi::G_SPAWN_CHILD_INHERITS_STDERR as _; #[cfg(feature = "v2_74")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))] #[doc(alias = "G_SPAWN_STDIN_FROM_DEV_NULL")] const STDIN_FROM_DEV_NULL = ffi::G_SPAWN_STDIN_FROM_DEV_NULL as _; } } #[doc(hidden)] impl IntoGlib for SpawnFlags { type GlibType = ffi::GSpawnFlags; #[inline] fn into_glib(self) -> ffi::GSpawnFlags { self.bits() } } #[doc(hidden)] impl FromGlib for SpawnFlags { #[inline] unsafe fn from_glib(value: ffi::GSpawnFlags) -> Self { Self::from_bits_truncate(value) } } #[cfg(feature = "v2_66")] bitflags! { #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GUriFlags")] pub struct UriFlags: u32 { #[doc(alias = "G_URI_FLAGS_NONE")] const NONE = ffi::G_URI_FLAGS_NONE as _; #[doc(alias = "G_URI_FLAGS_PARSE_RELAXED")] const PARSE_RELAXED = ffi::G_URI_FLAGS_PARSE_RELAXED as _; #[doc(alias = "G_URI_FLAGS_HAS_PASSWORD")] const HAS_PASSWORD = ffi::G_URI_FLAGS_HAS_PASSWORD as _; #[doc(alias = "G_URI_FLAGS_HAS_AUTH_PARAMS")] const HAS_AUTH_PARAMS = ffi::G_URI_FLAGS_HAS_AUTH_PARAMS as _; #[doc(alias = "G_URI_FLAGS_ENCODED")] const ENCODED = ffi::G_URI_FLAGS_ENCODED as _; #[doc(alias = "G_URI_FLAGS_NON_DNS")] const NON_DNS = ffi::G_URI_FLAGS_NON_DNS as _; #[doc(alias = "G_URI_FLAGS_ENCODED_QUERY")] const ENCODED_QUERY = ffi::G_URI_FLAGS_ENCODED_QUERY as _; #[doc(alias = "G_URI_FLAGS_ENCODED_PATH")] const ENCODED_PATH = ffi::G_URI_FLAGS_ENCODED_PATH as _; #[doc(alias = "G_URI_FLAGS_ENCODED_FRAGMENT")] const ENCODED_FRAGMENT = ffi::G_URI_FLAGS_ENCODED_FRAGMENT as _; #[doc(alias = "G_URI_FLAGS_SCHEME_NORMALIZE")] const SCHEME_NORMALIZE = ffi::G_URI_FLAGS_SCHEME_NORMALIZE as _; } } #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl IntoGlib for UriFlags { type GlibType = ffi::GUriFlags; #[inline] fn into_glib(self) -> ffi::GUriFlags { self.bits() } } #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl FromGlib for UriFlags { #[inline] unsafe fn from_glib(value: ffi::GUriFlags) -> Self { Self::from_bits_truncate(value) } } #[cfg(feature = "v2_66")] bitflags! { #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GUriHideFlags")] pub struct UriHideFlags: u32 { #[doc(alias = "G_URI_HIDE_NONE")] const NONE = ffi::G_URI_HIDE_NONE as _; #[doc(alias = "G_URI_HIDE_USERINFO")] const USERINFO = ffi::G_URI_HIDE_USERINFO as _; #[doc(alias = "G_URI_HIDE_PASSWORD")] const PASSWORD = ffi::G_URI_HIDE_PASSWORD as _; #[doc(alias = "G_URI_HIDE_AUTH_PARAMS")] const AUTH_PARAMS = ffi::G_URI_HIDE_AUTH_PARAMS as _; #[doc(alias = "G_URI_HIDE_QUERY")] const QUERY = ffi::G_URI_HIDE_QUERY as _; #[doc(alias = "G_URI_HIDE_FRAGMENT")] const FRAGMENT = ffi::G_URI_HIDE_FRAGMENT as _; } } #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl IntoGlib for UriHideFlags { type GlibType = ffi::GUriHideFlags; #[inline] fn into_glib(self) -> ffi::GUriHideFlags { self.bits() } } #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl FromGlib for UriHideFlags { #[inline] unsafe fn from_glib(value: ffi::GUriHideFlags) -> Self { Self::from_bits_truncate(value) } } #[cfg(feature = "v2_66")] bitflags! { #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GUriParamsFlags")] pub struct UriParamsFlags: u32 { #[doc(alias = "G_URI_PARAMS_NONE")] const NONE = ffi::G_URI_PARAMS_NONE as _; #[doc(alias = "G_URI_PARAMS_CASE_INSENSITIVE")] const CASE_INSENSITIVE = ffi::G_URI_PARAMS_CASE_INSENSITIVE as _; #[doc(alias = "G_URI_PARAMS_WWW_FORM")] const WWW_FORM = ffi::G_URI_PARAMS_WWW_FORM as _; #[doc(alias = "G_URI_PARAMS_PARSE_RELAXED")] const PARSE_RELAXED = ffi::G_URI_PARAMS_PARSE_RELAXED as _; } } #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl IntoGlib for UriParamsFlags { type GlibType = ffi::GUriParamsFlags; #[inline] fn into_glib(self) -> ffi::GUriParamsFlags { self.bits() } } #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] #[doc(hidden)] impl FromGlib for UriParamsFlags { #[inline] unsafe fn from_glib(value: ffi::GUriParamsFlags) -> Self { Self::from_bits_truncate(value) } } glib-0.20.9/src/auto/functions.rs000064400000000000000000000643751046102023000147650ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] use crate::FileSetContentsFlags; use crate::{ ffi, translate::*, Bytes, ChecksumType, Error, FileTest, FormatSizeFlags, Pid, Source, SpawnFlags, UserDirectory, }; use std::boxed::Box as Box_; #[doc(alias = "g_access")] pub fn access(filename: impl AsRef, mode: i32) -> i32 { unsafe { ffi::g_access(filename.as_ref().to_glib_none().0, mode) } } #[doc(alias = "g_base64_decode")] pub fn base64_decode(text: &str) -> Vec { unsafe { let mut out_len = std::mem::MaybeUninit::uninit(); let ret = FromGlibContainer::from_glib_full_num( ffi::g_base64_decode(text.to_glib_none().0, out_len.as_mut_ptr()), out_len.assume_init() as _, ); ret } } //#[doc(alias = "g_base64_decode_inplace")] //pub fn base64_decode_inplace(text: /*Unimplemented*/Vec) -> u8 { // unsafe { TODO: call ffi:g_base64_decode_inplace() } //} //#[doc(alias = "g_base64_decode_step")] //pub fn base64_decode_step(in_: &[u8], out: Vec, state: &mut i32, save: &mut u32) -> usize { // unsafe { TODO: call ffi:g_base64_decode_step() } //} #[doc(alias = "g_base64_encode")] pub fn base64_encode(data: &[u8]) -> crate::GString { let len = data.len() as _; unsafe { from_glib_full(ffi::g_base64_encode(data.to_glib_none().0, len)) } } //#[doc(alias = "g_base64_encode_close")] //pub fn base64_encode_close(break_lines: bool, out: Vec, state: &mut i32, save: &mut i32) -> usize { // unsafe { TODO: call ffi:g_base64_encode_close() } //} //#[doc(alias = "g_base64_encode_step")] //pub fn base64_encode_step(in_: &[u8], break_lines: bool, out: Vec, state: &mut i32, save: &mut i32) -> usize { // unsafe { TODO: call ffi:g_base64_encode_step() } //} #[doc(alias = "glib_check_version")] pub fn check_version( required_major: u32, required_minor: u32, required_micro: u32, ) -> Option { unsafe { from_glib_none(ffi::glib_check_version( required_major, required_minor, required_micro, )) } } #[doc(alias = "g_compute_checksum_for_bytes")] pub fn compute_checksum_for_bytes( checksum_type: ChecksumType, data: &Bytes, ) -> Option { unsafe { from_glib_full(ffi::g_compute_checksum_for_bytes( checksum_type.into_glib(), data.to_glib_none().0, )) } } #[doc(alias = "g_compute_checksum_for_data")] pub fn compute_checksum_for_data( checksum_type: ChecksumType, data: &[u8], ) -> Option { let length = data.len() as _; unsafe { from_glib_full(ffi::g_compute_checksum_for_data( checksum_type.into_glib(), data.to_glib_none().0, length, )) } } #[doc(alias = "g_compute_hmac_for_bytes")] pub fn compute_hmac_for_bytes( digest_type: ChecksumType, key: &Bytes, data: &Bytes, ) -> crate::GString { unsafe { from_glib_full(ffi::g_compute_hmac_for_bytes( digest_type.into_glib(), key.to_glib_none().0, data.to_glib_none().0, )) } } #[doc(alias = "g_compute_hmac_for_data")] pub fn compute_hmac_for_data(digest_type: ChecksumType, key: &[u8], data: &[u8]) -> crate::GString { let key_len = key.len() as _; let length = data.len() as _; unsafe { from_glib_full(ffi::g_compute_hmac_for_data( digest_type.into_glib(), key.to_glib_none().0, key_len, data.to_glib_none().0, length, )) } } #[doc(alias = "g_dcgettext")] pub fn dcgettext(domain: Option<&str>, msgid: &str, category: i32) -> crate::GString { unsafe { from_glib_none(ffi::g_dcgettext( domain.to_glib_none().0, msgid.to_glib_none().0, category, )) } } #[doc(alias = "g_dgettext")] pub fn dgettext(domain: Option<&str>, msgid: &str) -> crate::GString { unsafe { from_glib_none(ffi::g_dgettext( domain.to_glib_none().0, msgid.to_glib_none().0, )) } } #[doc(alias = "g_dngettext")] pub fn dngettext( domain: Option<&str>, msgid: &str, msgid_plural: &str, n: libc::c_ulong, ) -> crate::GString { unsafe { from_glib_none(ffi::g_dngettext( domain.to_glib_none().0, msgid.to_glib_none().0, msgid_plural.to_glib_none().0, n, )) } } #[doc(alias = "g_dpgettext")] pub fn dpgettext(domain: Option<&str>, msgctxtid: &str, msgidoffset: usize) -> crate::GString { unsafe { from_glib_none(ffi::g_dpgettext( domain.to_glib_none().0, msgctxtid.to_glib_none().0, msgidoffset, )) } } #[doc(alias = "g_dpgettext2")] pub fn dpgettext2(domain: Option<&str>, context: &str, msgid: &str) -> crate::GString { unsafe { from_glib_none(ffi::g_dpgettext2( domain.to_glib_none().0, context.to_glib_none().0, msgid.to_glib_none().0, )) } } #[doc(alias = "g_file_set_contents")] pub fn file_set_contents( filename: impl AsRef, contents: &[u8], ) -> Result<(), crate::Error> { let length = contents.len() as _; unsafe { let mut error = std::ptr::null_mut(); let is_ok = ffi::g_file_set_contents( filename.as_ref().to_glib_none().0, contents.to_glib_none().0, length, &mut error, ); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] #[doc(alias = "g_file_set_contents_full")] pub fn file_set_contents_full( filename: impl AsRef, contents: &[u8], flags: FileSetContentsFlags, mode: i32, ) -> Result<(), crate::Error> { let length = contents.len() as _; unsafe { let mut error = std::ptr::null_mut(); let is_ok = ffi::g_file_set_contents_full( filename.as_ref().to_glib_none().0, contents.to_glib_none().0, length, flags.into_glib(), mode, &mut error, ); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_file_test")] #[allow(dead_code)] pub(crate) fn file_test(filename: impl AsRef, test: FileTest) -> bool { unsafe { from_glib(ffi::g_file_test( filename.as_ref().to_glib_none().0, test.into_glib(), )) } } #[doc(alias = "g_filename_display_basename")] pub fn filename_display_basename(filename: impl AsRef) -> crate::GString { unsafe { from_glib_full(ffi::g_filename_display_basename( filename.as_ref().to_glib_none().0, )) } } #[doc(alias = "g_filename_display_name")] pub fn filename_display_name(filename: impl AsRef) -> crate::GString { unsafe { from_glib_full(ffi::g_filename_display_name( filename.as_ref().to_glib_none().0, )) } } #[doc(alias = "g_filename_from_uri")] pub fn filename_from_uri( uri: &str, ) -> Result<(std::path::PathBuf, Option), crate::Error> { unsafe { let mut hostname = std::ptr::null_mut(); let mut error = std::ptr::null_mut(); let ret = ffi::g_filename_from_uri(uri.to_glib_none().0, &mut hostname, &mut error); if error.is_null() { Ok((from_glib_full(ret), from_glib_full(hostname))) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_filename_to_uri")] pub fn filename_to_uri( filename: impl AsRef, hostname: Option<&str>, ) -> Result { unsafe { let mut error = std::ptr::null_mut(); let ret = ffi::g_filename_to_uri( filename.as_ref().to_glib_none().0, hostname.to_glib_none().0, &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_find_program_in_path")] pub fn find_program_in_path(program: impl AsRef) -> Option { unsafe { from_glib_full(ffi::g_find_program_in_path( program.as_ref().to_glib_none().0, )) } } #[doc(alias = "g_format_size")] pub fn format_size(size: u64) -> crate::GString { unsafe { from_glib_full(ffi::g_format_size(size)) } } #[doc(alias = "g_format_size_full")] pub fn format_size_full(size: u64, flags: FormatSizeFlags) -> crate::GString { unsafe { from_glib_full(ffi::g_format_size_full(size, flags.into_glib())) } } #[doc(alias = "g_get_application_name")] #[doc(alias = "get_application_name")] pub fn application_name() -> Option { unsafe { from_glib_none(ffi::g_get_application_name()) } } #[doc(alias = "g_get_codeset")] #[doc(alias = "get_codeset")] pub fn codeset() -> crate::GString { unsafe { from_glib_full(ffi::g_get_codeset()) } } #[cfg(feature = "v2_62")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_62")))] #[doc(alias = "g_get_console_charset")] #[doc(alias = "get_console_charset")] pub fn console_charset() -> Option { unsafe { let mut charset = std::ptr::null(); let ret = from_glib(ffi::g_get_console_charset(&mut charset)); if ret { Some(from_glib_none(charset)) } else { None } } } #[doc(alias = "g_get_current_dir")] #[doc(alias = "get_current_dir")] pub fn current_dir() -> std::path::PathBuf { unsafe { from_glib_full(ffi::g_get_current_dir()) } } #[doc(alias = "g_get_environ")] #[doc(alias = "get_environ")] pub fn environ() -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::g_get_environ()) } } #[doc(alias = "g_get_home_dir")] #[doc(alias = "get_home_dir")] pub fn home_dir() -> std::path::PathBuf { unsafe { from_glib_none(ffi::g_get_home_dir()) } } #[doc(alias = "g_get_host_name")] #[doc(alias = "get_host_name")] pub fn host_name() -> crate::GString { unsafe { from_glib_none(ffi::g_get_host_name()) } } #[doc(alias = "g_get_language_names")] #[doc(alias = "get_language_names")] pub fn language_names() -> Vec { unsafe { FromGlibPtrContainer::from_glib_none(ffi::g_get_language_names()) } } #[cfg(feature = "v2_58")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_58")))] #[doc(alias = "g_get_language_names_with_category")] #[doc(alias = "get_language_names_with_category")] pub fn language_names_with_category(category_name: &str) -> Vec { unsafe { FromGlibPtrContainer::from_glib_none(ffi::g_get_language_names_with_category( category_name.to_glib_none().0, )) } } #[doc(alias = "g_get_locale_variants")] #[doc(alias = "get_locale_variants")] pub fn locale_variants(locale: &str) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::g_get_locale_variants(locale.to_glib_none().0)) } } #[doc(alias = "g_get_monotonic_time")] #[doc(alias = "get_monotonic_time")] pub fn monotonic_time() -> i64 { unsafe { ffi::g_get_monotonic_time() } } #[doc(alias = "g_get_num_processors")] #[doc(alias = "get_num_processors")] pub fn num_processors() -> u32 { unsafe { ffi::g_get_num_processors() } } #[cfg(feature = "v2_64")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_64")))] #[doc(alias = "g_get_os_info")] #[doc(alias = "get_os_info")] pub fn os_info(key_name: &str) -> Option { unsafe { from_glib_full(ffi::g_get_os_info(key_name.to_glib_none().0)) } } #[doc(alias = "g_get_real_name")] #[doc(alias = "get_real_name")] pub fn real_name() -> std::ffi::OsString { unsafe { from_glib_none(ffi::g_get_real_name()) } } #[doc(alias = "g_get_real_time")] #[doc(alias = "get_real_time")] pub fn real_time() -> i64 { unsafe { ffi::g_get_real_time() } } #[doc(alias = "g_get_system_config_dirs")] #[doc(alias = "get_system_config_dirs")] pub fn system_config_dirs() -> Vec { unsafe { FromGlibPtrContainer::from_glib_none(ffi::g_get_system_config_dirs()) } } #[doc(alias = "g_get_system_data_dirs")] #[doc(alias = "get_system_data_dirs")] pub fn system_data_dirs() -> Vec { unsafe { FromGlibPtrContainer::from_glib_none(ffi::g_get_system_data_dirs()) } } #[doc(alias = "g_get_tmp_dir")] #[doc(alias = "get_tmp_dir")] pub fn tmp_dir() -> std::path::PathBuf { unsafe { from_glib_none(ffi::g_get_tmp_dir()) } } #[doc(alias = "g_get_user_cache_dir")] #[doc(alias = "get_user_cache_dir")] pub fn user_cache_dir() -> std::path::PathBuf { unsafe { from_glib_none(ffi::g_get_user_cache_dir()) } } #[doc(alias = "g_get_user_config_dir")] #[doc(alias = "get_user_config_dir")] pub fn user_config_dir() -> std::path::PathBuf { unsafe { from_glib_none(ffi::g_get_user_config_dir()) } } #[doc(alias = "g_get_user_data_dir")] #[doc(alias = "get_user_data_dir")] pub fn user_data_dir() -> std::path::PathBuf { unsafe { from_glib_none(ffi::g_get_user_data_dir()) } } #[doc(alias = "g_get_user_name")] #[doc(alias = "get_user_name")] pub fn user_name() -> std::ffi::OsString { unsafe { from_glib_none(ffi::g_get_user_name()) } } #[doc(alias = "g_get_user_runtime_dir")] #[doc(alias = "get_user_runtime_dir")] pub fn user_runtime_dir() -> std::path::PathBuf { unsafe { from_glib_none(ffi::g_get_user_runtime_dir()) } } #[doc(alias = "g_get_user_special_dir")] #[doc(alias = "get_user_special_dir")] pub fn user_special_dir(directory: UserDirectory) -> Option { unsafe { from_glib_none(ffi::g_get_user_special_dir(directory.into_glib())) } } #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] #[doc(alias = "g_get_user_state_dir")] #[doc(alias = "get_user_state_dir")] pub fn user_state_dir() -> std::path::PathBuf { unsafe { from_glib_none(ffi::g_get_user_state_dir()) } } #[doc(alias = "g_getenv")] pub fn getenv(variable: impl AsRef) -> Option { unsafe { from_glib_none(ffi::g_getenv(variable.as_ref().to_glib_none().0)) } } #[doc(alias = "g_hostname_is_ascii_encoded")] pub fn hostname_is_ascii_encoded(hostname: &str) -> bool { unsafe { from_glib(ffi::g_hostname_is_ascii_encoded(hostname.to_glib_none().0)) } } #[doc(alias = "g_hostname_is_ip_address")] pub fn hostname_is_ip_address(hostname: &str) -> bool { unsafe { from_glib(ffi::g_hostname_is_ip_address(hostname.to_glib_none().0)) } } #[doc(alias = "g_hostname_is_non_ascii")] pub fn hostname_is_non_ascii(hostname: &str) -> bool { unsafe { from_glib(ffi::g_hostname_is_non_ascii(hostname.to_glib_none().0)) } } #[doc(alias = "g_hostname_to_ascii")] pub fn hostname_to_ascii(hostname: &str) -> Option { unsafe { from_glib_full(ffi::g_hostname_to_ascii(hostname.to_glib_none().0)) } } #[doc(alias = "g_hostname_to_unicode")] pub fn hostname_to_unicode(hostname: &str) -> Option { unsafe { from_glib_full(ffi::g_hostname_to_unicode(hostname.to_glib_none().0)) } } #[doc(alias = "g_listenv")] pub fn listenv() -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::g_listenv()) } } #[doc(alias = "g_main_current_source")] pub fn main_current_source() -> Option { unsafe { from_glib_none(ffi::g_main_current_source()) } } #[doc(alias = "g_main_depth")] pub fn main_depth() -> i32 { unsafe { ffi::g_main_depth() } } #[doc(alias = "g_markup_escape_text")] pub fn markup_escape_text(text: &str) -> crate::GString { let length = text.len() as _; unsafe { from_glib_full(ffi::g_markup_escape_text(text.to_glib_none().0, length)) } } #[doc(alias = "g_mkdir_with_parents")] pub fn mkdir_with_parents(pathname: impl AsRef, mode: i32) -> i32 { unsafe { ffi::g_mkdir_with_parents(pathname.as_ref().to_glib_none().0, mode) } } #[doc(alias = "g_on_error_query")] pub fn on_error_query(prg_name: &str) { unsafe { ffi::g_on_error_query(prg_name.to_glib_none().0); } } #[doc(alias = "g_on_error_stack_trace")] pub fn on_error_stack_trace(prg_name: Option<&str>) { unsafe { ffi::g_on_error_stack_trace(prg_name.to_glib_none().0); } } #[doc(alias = "g_path_get_basename")] #[allow(dead_code)] pub(crate) fn path_get_basename(file_name: impl AsRef) -> std::path::PathBuf { unsafe { from_glib_full(ffi::g_path_get_basename( file_name.as_ref().to_glib_none().0, )) } } #[doc(alias = "g_path_get_dirname")] #[allow(dead_code)] pub(crate) fn path_get_dirname(file_name: impl AsRef) -> std::path::PathBuf { unsafe { from_glib_full(ffi::g_path_get_dirname(file_name.as_ref().to_glib_none().0)) } } //#[doc(alias = "g_poll")] //pub fn poll(fds: /*Ignored*/&mut PollFD, nfds: u32, timeout: i32) -> i32 { // unsafe { TODO: call ffi:g_poll() } //} #[doc(alias = "g_random_double")] pub fn random_double() -> f64 { unsafe { ffi::g_random_double() } } #[doc(alias = "g_random_double_range")] pub fn random_double_range(begin: f64, end: f64) -> f64 { unsafe { ffi::g_random_double_range(begin, end) } } #[doc(alias = "g_random_int")] pub fn random_int() -> u32 { unsafe { ffi::g_random_int() } } #[doc(alias = "g_random_int_range")] pub fn random_int_range(begin: i32, end: i32) -> i32 { unsafe { ffi::g_random_int_range(begin, end) } } #[doc(alias = "g_random_set_seed")] pub fn random_set_seed(seed: u32) { unsafe { ffi::g_random_set_seed(seed); } } #[doc(alias = "g_reload_user_special_dirs_cache")] pub fn reload_user_special_dirs_cache() { unsafe { ffi::g_reload_user_special_dirs_cache(); } } #[doc(alias = "g_set_application_name")] pub fn set_application_name(application_name: &str) { unsafe { ffi::g_set_application_name(application_name.to_glib_none().0); } } #[doc(alias = "g_setenv")] pub fn setenv( variable: impl AsRef, value: impl AsRef, overwrite: bool, ) -> Result<(), crate::error::BoolError> { unsafe { crate::result_from_gboolean!( ffi::g_setenv( variable.as_ref().to_glib_none().0, value.as_ref().to_glib_none().0, overwrite.into_glib() ), "Failed to set environment variable" ) } } #[doc(alias = "g_shell_parse_argv")] pub fn shell_parse_argv( command_line: impl AsRef, ) -> Result, crate::Error> { unsafe { let mut argcp = std::mem::MaybeUninit::uninit(); let mut argvp = std::ptr::null_mut(); let mut error = std::ptr::null_mut(); let is_ok = ffi::g_shell_parse_argv( command_line.as_ref().to_glib_none().0, argcp.as_mut_ptr(), &mut argvp, &mut error, ); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(FromGlibContainer::from_glib_full_num( argvp, argcp.assume_init() as _, )) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_shell_quote")] pub fn shell_quote(unquoted_string: impl AsRef) -> std::ffi::OsString { unsafe { from_glib_full(ffi::g_shell_quote( unquoted_string.as_ref().to_glib_none().0, )) } } #[doc(alias = "g_shell_unquote")] pub fn shell_unquote( quoted_string: impl AsRef, ) -> Result { unsafe { let mut error = std::ptr::null_mut(); let ret = ffi::g_shell_unquote(quoted_string.as_ref().to_glib_none().0, &mut error); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } //#[cfg(feature = "v2_82")] //#[cfg_attr(docsrs, doc(cfg(feature = "v2_82")))] //#[doc(alias = "g_sort_array")] //pub fn sort_array(array: /*Unimplemented*/&[&Basic: Pointer], element_size: usize, compare_func: /*Unimplemented*/FnMut(/*Unimplemented*/Option, /*Unimplemented*/Option) -> i32, user_data: /*Unimplemented*/Option) { // unsafe { TODO: call ffi:g_sort_array() } //} #[doc(alias = "g_spaced_primes_closest")] pub fn spaced_primes_closest(num: u32) -> u32 { unsafe { ffi::g_spaced_primes_closest(num) } } #[doc(alias = "g_spawn_async")] pub fn spawn_async( working_directory: Option>, argv: &[&std::path::Path], envp: &[&std::path::Path], flags: SpawnFlags, child_setup: Option>, ) -> Result { let child_setup_data: Box_>> = Box_::new(child_setup); unsafe extern "C" fn child_setup_func(data: ffi::gpointer) { let callback = Box_::from_raw(data as *mut Option>); let callback = (*callback).expect("cannot get closure..."); callback() } let child_setup = if child_setup_data.is_some() { Some(child_setup_func as _) } else { None }; let super_callback0: Box_>> = child_setup_data; unsafe { let mut child_pid = std::mem::MaybeUninit::uninit(); let mut error = std::ptr::null_mut(); let is_ok = ffi::g_spawn_async( working_directory .as_ref() .map(|p| p.as_ref()) .to_glib_none() .0, argv.to_glib_none().0, envp.to_glib_none().0, flags.into_glib(), child_setup, Box_::into_raw(super_callback0) as *mut _, child_pid.as_mut_ptr(), &mut error, ); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(from_glib(child_pid.assume_init())) } else { Err(from_glib_full(error)) } } } //#[cfg(feature = "v2_68")] //#[cfg_attr(docsrs, doc(cfg(feature = "v2_68")))] //#[doc(alias = "g_spawn_async_with_pipes_and_fds")] //pub fn spawn_async_with_pipes_and_fds(working_directory: Option>, argv: &[&std::path::Path], envp: &[&std::path::Path], flags: SpawnFlags, child_setup: Option>, stdin_fd: i32, stdout_fd: i32, stderr_fd: i32, source_fds: &[i32], target_fds: &[i32], n_fds: usize) -> Result<(Pid, i32, i32, i32), crate::Error> { // unsafe { TODO: call ffi:g_spawn_async_with_pipes_and_fds() } //} #[cfg_attr(feature = "v2_70", deprecated = "Since 2.70")] #[allow(deprecated)] #[doc(alias = "g_spawn_check_exit_status")] pub fn spawn_check_exit_status(wait_status: i32) -> Result<(), crate::Error> { unsafe { let mut error = std::ptr::null_mut(); let is_ok = ffi::g_spawn_check_exit_status(wait_status, &mut error); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[cfg(feature = "v2_70")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_70")))] #[doc(alias = "g_spawn_check_wait_status")] pub fn spawn_check_wait_status(wait_status: i32) -> Result<(), crate::Error> { unsafe { let mut error = std::ptr::null_mut(); let is_ok = ffi::g_spawn_check_wait_status(wait_status, &mut error); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] #[doc(alias = "g_spawn_command_line_async")] pub fn spawn_command_line_async( command_line: impl AsRef, ) -> Result<(), crate::Error> { unsafe { let mut error = std::ptr::null_mut(); let is_ok = ffi::g_spawn_command_line_async(command_line.as_ref().to_glib_none().0, &mut error); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } //#[doc(alias = "g_spawn_command_line_sync")] //pub fn spawn_command_line_sync(command_line: impl AsRef, standard_output: Vec, standard_error: Vec) -> Result { // unsafe { TODO: call ffi:g_spawn_command_line_sync() } //} //#[doc(alias = "g_spawn_sync")] //pub fn spawn_sync(working_directory: Option>, argv: &[&std::path::Path], envp: &[&std::path::Path], flags: SpawnFlags, child_setup: Option<&mut dyn (FnMut())>, standard_output: Vec, standard_error: Vec) -> Result { // unsafe { TODO: call ffi:g_spawn_sync() } //} //#[doc(alias = "g_stat")] //pub fn stat(filename: impl AsRef, buf: /*Ignored*/&mut StatBuf) -> i32 { // unsafe { TODO: call ffi:g_stat() } //} //#[cfg(unix)] //#[cfg_attr(docsrs, doc(cfg(unix)))] //#[cfg(feature = "v2_64")] //#[cfg_attr(docsrs, doc(cfg(feature = "v2_64")))] //#[doc(alias = "g_unix_get_passwd_entry")] //pub fn unix_get_passwd_entry(user_name: &str) -> Result, crate::Error> { // unsafe { TODO: call ffi:g_unix_get_passwd_entry() } //} #[doc(alias = "g_unlink")] pub fn unlink(filename: impl AsRef) -> i32 { unsafe { ffi::g_unlink(filename.as_ref().to_glib_none().0) } } #[doc(alias = "g_unsetenv")] pub fn unsetenv(variable: impl AsRef) { unsafe { ffi::g_unsetenv(variable.as_ref().to_glib_none().0); } } #[doc(alias = "g_usleep")] pub fn usleep(microseconds: libc::c_ulong) { unsafe { ffi::g_usleep(microseconds); } } #[doc(alias = "g_uuid_string_is_valid")] pub fn uuid_string_is_valid(str: &str) -> bool { unsafe { from_glib(ffi::g_uuid_string_is_valid(str.to_glib_none().0)) } } #[doc(alias = "g_uuid_string_random")] pub fn uuid_string_random() -> crate::GString { unsafe { from_glib_full(ffi::g_uuid_string_random()) } } glib-0.20.9/src/auto/key_file.rs000064400000000000000000000360271046102023000145350ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::{ffi, translate::*, Bytes, Error, KeyFileFlags}; crate::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct KeyFile(Shared); match fn { ref => |ptr| ffi::g_key_file_ref(ptr), unref => |ptr| ffi::g_key_file_unref(ptr), type_ => || ffi::g_key_file_get_type(), } } impl KeyFile { #[doc(alias = "g_key_file_new")] pub fn new() -> KeyFile { unsafe { from_glib_full(ffi::g_key_file_new()) } } #[doc(alias = "g_key_file_get_comment")] #[doc(alias = "get_comment")] pub fn comment( &self, group_name: Option<&str>, key: Option<&str>, ) -> Result { unsafe { let mut error = std::ptr::null_mut(); let ret = ffi::g_key_file_get_comment( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_double")] #[doc(alias = "get_double")] pub fn double(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = std::ptr::null_mut(); let ret = ffi::g_key_file_get_double( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(ret) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_double_list")] #[doc(alias = "get_double_list")] pub fn double_list(&self, group_name: &str, key: &str) -> Result, crate::Error> { unsafe { let mut length = std::mem::MaybeUninit::uninit(); let mut error = std::ptr::null_mut(); let ret = ffi::g_key_file_get_double_list( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, length.as_mut_ptr(), &mut error, ); if error.is_null() { Ok(FromGlibContainer::from_glib_container_num( ret, length.assume_init() as _, )) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_int64")] #[doc(alias = "get_int64")] pub fn int64(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = std::ptr::null_mut(); let ret = ffi::g_key_file_get_int64( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(ret) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_integer")] #[doc(alias = "get_integer")] pub fn integer(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = std::ptr::null_mut(); let ret = ffi::g_key_file_get_integer( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(ret) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_integer_list")] #[doc(alias = "get_integer_list")] pub fn integer_list(&self, group_name: &str, key: &str) -> Result, crate::Error> { unsafe { let mut length = std::mem::MaybeUninit::uninit(); let mut error = std::ptr::null_mut(); let ret = ffi::g_key_file_get_integer_list( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, length.as_mut_ptr(), &mut error, ); if error.is_null() { Ok(FromGlibContainer::from_glib_container_num( ret, length.assume_init() as _, )) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_locale_for_key")] #[doc(alias = "get_locale_for_key")] pub fn locale_for_key( &self, group_name: &str, key: &str, locale: Option<&str>, ) -> Option { unsafe { from_glib_full(ffi::g_key_file_get_locale_for_key( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, locale.to_glib_none().0, )) } } #[doc(alias = "g_key_file_get_start_group")] #[doc(alias = "get_start_group")] pub fn start_group(&self) -> Option { unsafe { from_glib_full(ffi::g_key_file_get_start_group(self.to_glib_none().0)) } } #[doc(alias = "g_key_file_get_uint64")] #[doc(alias = "get_uint64")] pub fn uint64(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = std::ptr::null_mut(); let ret = ffi::g_key_file_get_uint64( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(ret) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_value")] #[doc(alias = "get_value")] pub fn value(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = std::ptr::null_mut(); let ret = ffi::g_key_file_get_value( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_has_group")] pub fn has_group(&self, group_name: &str) -> bool { unsafe { from_glib(ffi::g_key_file_has_group( self.to_glib_none().0, group_name.to_glib_none().0, )) } } #[doc(alias = "g_key_file_load_from_bytes")] pub fn load_from_bytes(&self, bytes: &Bytes, flags: KeyFileFlags) -> Result<(), crate::Error> { unsafe { let mut error = std::ptr::null_mut(); let is_ok = ffi::g_key_file_load_from_bytes( self.to_glib_none().0, bytes.to_glib_none().0, flags.into_glib(), &mut error, ); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_load_from_data")] pub fn load_from_data(&self, data: &str, flags: KeyFileFlags) -> Result<(), crate::Error> { let length = data.len() as _; unsafe { let mut error = std::ptr::null_mut(); let is_ok = ffi::g_key_file_load_from_data( self.to_glib_none().0, data.to_glib_none().0, length, flags.into_glib(), &mut error, ); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_load_from_file")] pub fn load_from_file( &self, file: impl AsRef, flags: KeyFileFlags, ) -> Result<(), crate::Error> { unsafe { let mut error = std::ptr::null_mut(); let is_ok = ffi::g_key_file_load_from_file( self.to_glib_none().0, file.as_ref().to_glib_none().0, flags.into_glib(), &mut error, ); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_remove_comment")] pub fn remove_comment( &self, group_name: Option<&str>, key: Option<&str>, ) -> Result<(), crate::Error> { unsafe { let mut error = std::ptr::null_mut(); let is_ok = ffi::g_key_file_remove_comment( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_remove_group")] pub fn remove_group(&self, group_name: &str) -> Result<(), crate::Error> { unsafe { let mut error = std::ptr::null_mut(); let is_ok = ffi::g_key_file_remove_group( self.to_glib_none().0, group_name.to_glib_none().0, &mut error, ); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_remove_key")] pub fn remove_key(&self, group_name: &str, key: &str) -> Result<(), crate::Error> { unsafe { let mut error = std::ptr::null_mut(); let is_ok = ffi::g_key_file_remove_key( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_set_boolean")] pub fn set_boolean(&self, group_name: &str, key: &str, value: bool) { unsafe { ffi::g_key_file_set_boolean( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, value.into_glib(), ); } } //#[doc(alias = "g_key_file_set_boolean_list")] //pub fn set_boolean_list(&self, group_name: &str, key: &str, list: /*Unimplemented*/&CArray TypeId { ns_id: 0, id: 1 }) { // unsafe { TODO: call ffi:g_key_file_set_boolean_list() } //} #[doc(alias = "g_key_file_set_comment")] pub fn set_comment( &self, group_name: Option<&str>, key: Option<&str>, comment: &str, ) -> Result<(), crate::Error> { unsafe { let mut error = std::ptr::null_mut(); let is_ok = ffi::g_key_file_set_comment( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, comment.to_glib_none().0, &mut error, ); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_set_double")] pub fn set_double(&self, group_name: &str, key: &str, value: f64) { unsafe { ffi::g_key_file_set_double( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, value, ); } } #[doc(alias = "g_key_file_set_int64")] pub fn set_int64(&self, group_name: &str, key: &str, value: i64) { unsafe { ffi::g_key_file_set_int64( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, value, ); } } #[doc(alias = "g_key_file_set_integer")] pub fn set_integer(&self, group_name: &str, key: &str, value: i32) { unsafe { ffi::g_key_file_set_integer( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, value, ); } } #[doc(alias = "g_key_file_set_list_separator")] pub fn set_list_separator(&self, separator: crate::Char) { unsafe { ffi::g_key_file_set_list_separator(self.to_glib_none().0, separator.into_glib()); } } #[doc(alias = "g_key_file_set_locale_string")] pub fn set_locale_string(&self, group_name: &str, key: &str, locale: &str, string: &str) { unsafe { ffi::g_key_file_set_locale_string( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, locale.to_glib_none().0, string.to_glib_none().0, ); } } #[doc(alias = "g_key_file_set_string")] pub fn set_string(&self, group_name: &str, key: &str, string: &str) { unsafe { ffi::g_key_file_set_string( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, string.to_glib_none().0, ); } } #[doc(alias = "g_key_file_set_uint64")] pub fn set_uint64(&self, group_name: &str, key: &str, value: u64) { unsafe { ffi::g_key_file_set_uint64( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, value, ); } } #[doc(alias = "g_key_file_set_value")] pub fn set_value(&self, group_name: &str, key: &str, value: &str) { unsafe { ffi::g_key_file_set_value( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, value.to_glib_none().0, ); } } } impl Default for KeyFile { fn default() -> Self { Self::new() } } glib-0.20.9/src/auto/main_context.rs000064400000000000000000000126721046102023000154360ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] use crate::MainContextFlags; use crate::{ffi, translate::*}; crate::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MainContext(Shared); match fn { ref => |ptr| ffi::g_main_context_ref(ptr), unref => |ptr| ffi::g_main_context_unref(ptr), type_ => || ffi::g_main_context_get_type(), } } impl MainContext { #[doc(alias = "g_main_context_new")] pub fn new() -> MainContext { unsafe { from_glib_full(ffi::g_main_context_new()) } } #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] #[doc(alias = "g_main_context_new_with_flags")] #[doc(alias = "new_with_flags")] pub fn with_flags(flags: MainContextFlags) -> MainContext { unsafe { from_glib_full(ffi::g_main_context_new_with_flags(flags.into_glib())) } } //#[doc(alias = "g_main_context_add_poll")] //pub fn add_poll(&self, fd: /*Ignored*/&mut PollFD, priority: i32) { // unsafe { TODO: call ffi:g_main_context_add_poll() } //} //#[doc(alias = "g_main_context_check")] //pub fn check(&self, max_priority: i32, fds: /*Ignored*/&[PollFD]) -> bool { // unsafe { TODO: call ffi:g_main_context_check() } //} #[doc(alias = "g_main_context_dispatch")] pub fn dispatch(&self) { unsafe { ffi::g_main_context_dispatch(self.to_glib_none().0); } } //#[doc(alias = "g_main_context_find_source_by_funcs_user_data")] //pub fn find_source_by_funcs_user_data(&self, funcs: /*Ignored*/&mut SourceFuncs, user_data: /*Unimplemented*/Option) -> Source { // unsafe { TODO: call ffi:g_main_context_find_source_by_funcs_user_data() } //} //#[doc(alias = "g_main_context_find_source_by_user_data")] //pub fn find_source_by_user_data(&self, user_data: /*Unimplemented*/Option) -> Source { // unsafe { TODO: call ffi:g_main_context_find_source_by_user_data() } //} //#[doc(alias = "g_main_context_get_poll_func")] //#[doc(alias = "get_poll_func")] //pub fn poll_func(&self) -> /*Unimplemented*/Fn(/*Ignored*/PollFD, u32) -> i32 { // unsafe { TODO: call ffi:g_main_context_get_poll_func() } //} #[doc(alias = "g_main_context_is_owner")] pub fn is_owner(&self) -> bool { unsafe { from_glib(ffi::g_main_context_is_owner(self.to_glib_none().0)) } } #[doc(alias = "g_main_context_iteration")] pub fn iteration(&self, may_block: bool) -> bool { unsafe { from_glib(ffi::g_main_context_iteration( self.to_glib_none().0, may_block.into_glib(), )) } } #[doc(alias = "g_main_context_pending")] pub fn pending(&self) -> bool { unsafe { from_glib(ffi::g_main_context_pending(self.to_glib_none().0)) } } //#[cfg(feature = "v2_64")] //#[cfg_attr(docsrs, doc(cfg(feature = "v2_64")))] //#[doc(alias = "g_main_context_pusher_new")] //pub fn pusher_new(&self) -> /*Unknown conversion*//*Unimplemented*/MainContextPusher { // unsafe { TODO: call ffi:g_main_context_pusher_new() } //} //#[doc(alias = "g_main_context_query")] //pub fn query(&self, max_priority: i32, fds: /*Ignored*/Vec) -> (i32, i32) { // unsafe { TODO: call ffi:g_main_context_query() } //} //#[doc(alias = "g_main_context_remove_poll")] //pub fn remove_poll(&self, fd: /*Ignored*/&mut PollFD) { // unsafe { TODO: call ffi:g_main_context_remove_poll() } //} //#[doc(alias = "g_main_context_set_poll_func")] //pub fn set_poll_func(&self, func: /*Unimplemented*/Fn(/*Ignored*/PollFD, u32) -> i32) { // unsafe { TODO: call ffi:g_main_context_set_poll_func() } //} //#[cfg_attr(feature = "v2_58", deprecated = "Since 2.58")] //#[allow(deprecated)] //#[doc(alias = "g_main_context_wait")] //pub fn wait(&self, cond: /*Ignored*/&mut Cond, mutex: /*Ignored*/&mut Mutex) -> bool { // unsafe { TODO: call ffi:g_main_context_wait() } //} #[doc(alias = "g_main_context_wakeup")] pub fn wakeup(&self) { unsafe { ffi::g_main_context_wakeup(self.to_glib_none().0); } } #[doc(alias = "g_main_context_default")] #[allow(clippy::should_implement_trait)] pub fn default() -> MainContext { unsafe { from_glib_none(ffi::g_main_context_default()) } } #[doc(alias = "g_main_context_get_thread_default")] #[doc(alias = "get_thread_default")] pub fn thread_default() -> Option { unsafe { from_glib_none(ffi::g_main_context_get_thread_default()) } } //#[cfg(feature = "v2_64")] //#[cfg_attr(docsrs, doc(cfg(feature = "v2_64")))] //#[doc(alias = "g_main_context_pusher_free")] //pub fn pusher_free(pusher: /*Unknown conversion*//*Unimplemented*/MainContextPusher) { // unsafe { TODO: call ffi:g_main_context_pusher_free() } //} #[doc(alias = "g_main_context_ref_thread_default")] pub fn ref_thread_default() -> MainContext { unsafe { from_glib_full(ffi::g_main_context_ref_thread_default()) } } } impl Default for MainContext { fn default() -> Self { Self::new() } } unsafe impl Send for MainContext {} unsafe impl Sync for MainContext {} glib-0.20.9/src/auto/main_loop.rs000064400000000000000000000030321046102023000147110ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::{ffi, translate::*, MainContext}; crate::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MainLoop(Shared); match fn { ref => |ptr| ffi::g_main_loop_ref(ptr), unref => |ptr| ffi::g_main_loop_unref(ptr), type_ => || ffi::g_main_loop_get_type(), } } impl MainLoop { #[doc(alias = "g_main_loop_new")] pub fn new(context: Option<&MainContext>, is_running: bool) -> MainLoop { unsafe { from_glib_full(ffi::g_main_loop_new( context.to_glib_none().0, is_running.into_glib(), )) } } #[doc(alias = "g_main_loop_get_context")] #[doc(alias = "get_context")] pub fn context(&self) -> MainContext { unsafe { from_glib_none(ffi::g_main_loop_get_context(self.to_glib_none().0)) } } #[doc(alias = "g_main_loop_is_running")] pub fn is_running(&self) -> bool { unsafe { from_glib(ffi::g_main_loop_is_running(self.to_glib_none().0)) } } #[doc(alias = "g_main_loop_quit")] pub fn quit(&self) { unsafe { ffi::g_main_loop_quit(self.to_glib_none().0); } } #[doc(alias = "g_main_loop_run")] pub fn run(&self) { unsafe { ffi::g_main_loop_run(self.to_glib_none().0); } } } unsafe impl Send for MainLoop {} unsafe impl Sync for MainLoop {} glib-0.20.9/src/auto/markup_parse_context.rs000064400000000000000000000070741046102023000172030ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::{ffi, translate::*, Error}; crate::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MarkupParseContext(Shared); match fn { ref => |ptr| ffi::g_markup_parse_context_ref(ptr), unref => |ptr| ffi::g_markup_parse_context_unref(ptr), type_ => || ffi::g_markup_parse_context_get_type(), } } impl MarkupParseContext { //#[doc(alias = "g_markup_parse_context_new")] //pub fn new(parser: /*Ignored*/&MarkupParser, flags: /*Ignored*/MarkupParseFlags, user_data: /*Unimplemented*/Option) -> MarkupParseContext { // unsafe { TODO: call ffi:g_markup_parse_context_new() } //} #[doc(alias = "g_markup_parse_context_end_parse")] pub fn end_parse(&self) -> Result<(), crate::Error> { unsafe { let mut error = std::ptr::null_mut(); let is_ok = ffi::g_markup_parse_context_end_parse(self.to_glib_none().0, &mut error); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_markup_parse_context_get_element")] #[doc(alias = "get_element")] pub fn element(&self) -> crate::GString { unsafe { from_glib_none(ffi::g_markup_parse_context_get_element( self.to_glib_none().0, )) } } #[doc(alias = "g_markup_parse_context_get_element_stack")] #[doc(alias = "get_element_stack")] pub fn element_stack(&self) -> Vec { unsafe { FromGlibPtrContainer::from_glib_none(ffi::g_markup_parse_context_get_element_stack( self.to_glib_none().0, )) } } #[doc(alias = "g_markup_parse_context_get_position")] #[doc(alias = "get_position")] pub fn position(&self) -> (i32, i32) { unsafe { let mut line_number = std::mem::MaybeUninit::uninit(); let mut char_number = std::mem::MaybeUninit::uninit(); ffi::g_markup_parse_context_get_position( self.to_glib_none().0, line_number.as_mut_ptr(), char_number.as_mut_ptr(), ); (line_number.assume_init(), char_number.assume_init()) } } #[doc(alias = "g_markup_parse_context_parse")] pub fn parse(&self, text: &str) -> Result<(), crate::Error> { let text_len = text.len() as _; unsafe { let mut error = std::ptr::null_mut(); let is_ok = ffi::g_markup_parse_context_parse( self.to_glib_none().0, text.to_glib_none().0, text_len, &mut error, ); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } //#[doc(alias = "g_markup_parse_context_pop")] //pub fn pop(&self) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:g_markup_parse_context_pop() } //} //#[doc(alias = "g_markup_parse_context_push")] //pub fn push(&self, parser: /*Ignored*/&MarkupParser, user_data: /*Unimplemented*/Option) { // unsafe { TODO: call ffi:g_markup_parse_context_push() } //} } glib-0.20.9/src/auto/mod.rs000064400000000000000000000110151046102023000135130ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT mod checksum; pub use self::checksum::Checksum; mod date_time; pub use self::date_time::DateTime; mod key_file; pub use self::key_file::KeyFile; mod main_context; pub use self::main_context::MainContext; mod main_loop; pub use self::main_loop::MainLoop; mod markup_parse_context; pub use self::markup_parse_context::MarkupParseContext; mod regex; pub use self::regex::Regex; mod source; pub use self::source::Source; mod time_zone; pub use self::time_zone::TimeZone; #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] mod uri; #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] pub use self::uri::Uri; mod enums; pub use self::enums::ChecksumType; pub use self::enums::ConvertError; pub use self::enums::DateMonth; pub use self::enums::DateWeekday; pub use self::enums::FileError; pub use self::enums::KeyFileError; pub use self::enums::LogWriterOutput; pub use self::enums::MarkupError; pub use self::enums::NormalizeMode; pub use self::enums::OptionArg; pub use self::enums::SeekType; pub use self::enums::TimeType; pub use self::enums::UnicodeBreakType; pub use self::enums::UnicodeScript; pub use self::enums::UnicodeType; #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] pub use self::enums::UriError; pub use self::enums::VariantClass; mod flags; #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] pub use self::flags::FileSetContentsFlags; pub(crate) use self::flags::FileTest; pub use self::flags::FormatSizeFlags; pub use self::flags::IOCondition; pub use self::flags::KeyFileFlags; pub use self::flags::LogLevelFlags; #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] pub use self::flags::MainContextFlags; pub use self::flags::OptionFlags; pub use self::flags::RegexCompileFlags; pub use self::flags::RegexMatchFlags; pub use self::flags::SpawnFlags; #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] pub use self::flags::UriFlags; #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] pub use self::flags::UriHideFlags; #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] pub use self::flags::UriParamsFlags; mod alias; pub use self::alias::DateDay; pub use self::alias::DateYear; pub use self::alias::Time; pub(crate) mod functions; mod constants; pub use self::constants::CSET_a_2_z; pub use self::constants::CSET_A_2_Z; pub use self::constants::CSET_DIGITS; pub use self::constants::KEY_FILE_DESKTOP_GROUP; pub use self::constants::KEY_FILE_DESKTOP_KEY_ACTIONS; pub use self::constants::KEY_FILE_DESKTOP_KEY_CATEGORIES; pub use self::constants::KEY_FILE_DESKTOP_KEY_COMMENT; pub use self::constants::KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE; pub use self::constants::KEY_FILE_DESKTOP_KEY_EXEC; pub use self::constants::KEY_FILE_DESKTOP_KEY_GENERIC_NAME; pub use self::constants::KEY_FILE_DESKTOP_KEY_HIDDEN; pub use self::constants::KEY_FILE_DESKTOP_KEY_ICON; pub use self::constants::KEY_FILE_DESKTOP_KEY_MIME_TYPE; pub use self::constants::KEY_FILE_DESKTOP_KEY_NAME; pub use self::constants::KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN; pub use self::constants::KEY_FILE_DESKTOP_KEY_NO_DISPLAY; pub use self::constants::KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN; pub use self::constants::KEY_FILE_DESKTOP_KEY_PATH; pub use self::constants::KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY; pub use self::constants::KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS; pub use self::constants::KEY_FILE_DESKTOP_KEY_TERMINAL; pub use self::constants::KEY_FILE_DESKTOP_KEY_TRY_EXEC; pub use self::constants::KEY_FILE_DESKTOP_KEY_TYPE; pub use self::constants::KEY_FILE_DESKTOP_KEY_URL; pub use self::constants::KEY_FILE_DESKTOP_KEY_VERSION; pub use self::constants::KEY_FILE_DESKTOP_TYPE_APPLICATION; pub use self::constants::KEY_FILE_DESKTOP_TYPE_DIRECTORY; pub use self::constants::KEY_FILE_DESKTOP_TYPE_LINK; pub use self::constants::OPTION_REMAINING; pub use self::constants::STR_DELIMITERS; #[cfg(feature = "v2_60")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_60")))] pub use self::constants::TEST_OPTION_ISOLATE_DIRS; #[cfg(feature = "v2_84")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_84")))] pub use self::constants::TEST_OPTION_NONFATAL_ASSERTIONS; #[cfg(feature = "v2_84")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_84")))] pub use self::constants::TEST_OPTION_NO_PRGNAME; pub use self::constants::URI_RESERVED_CHARS_GENERIC_DELIMITERS; pub use self::constants::URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS; glib-0.20.9/src/auto/regex.rs000064400000000000000000000057531046102023000140620ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::{ffi, translate::*, Error, RegexCompileFlags, RegexMatchFlags}; crate::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Regex(Shared); match fn { ref => |ptr| ffi::g_regex_ref(ptr), unref => |ptr| ffi::g_regex_unref(ptr), type_ => || ffi::g_regex_get_type(), } } impl Regex { #[doc(alias = "g_regex_new")] pub fn new( pattern: &str, compile_options: RegexCompileFlags, match_options: RegexMatchFlags, ) -> Result, crate::Error> { unsafe { let mut error = std::ptr::null_mut(); let ret = ffi::g_regex_new( pattern.to_glib_none().0, compile_options.into_glib(), match_options.into_glib(), &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_regex_get_capture_count")] #[doc(alias = "get_capture_count")] pub fn capture_count(&self) -> i32 { unsafe { ffi::g_regex_get_capture_count(self.to_glib_none().0) } } #[doc(alias = "g_regex_get_compile_flags")] #[doc(alias = "get_compile_flags")] pub fn compile_flags(&self) -> RegexCompileFlags { unsafe { from_glib(ffi::g_regex_get_compile_flags(self.to_glib_none().0)) } } #[doc(alias = "g_regex_get_has_cr_or_lf")] #[doc(alias = "get_has_cr_or_lf")] pub fn has_cr_or_lf(&self) -> bool { unsafe { from_glib(ffi::g_regex_get_has_cr_or_lf(self.to_glib_none().0)) } } #[doc(alias = "g_regex_get_match_flags")] #[doc(alias = "get_match_flags")] pub fn match_flags(&self) -> RegexMatchFlags { unsafe { from_glib(ffi::g_regex_get_match_flags(self.to_glib_none().0)) } } #[doc(alias = "g_regex_get_max_backref")] #[doc(alias = "get_max_backref")] pub fn max_backref(&self) -> i32 { unsafe { ffi::g_regex_get_max_backref(self.to_glib_none().0) } } #[doc(alias = "g_regex_get_max_lookbehind")] #[doc(alias = "get_max_lookbehind")] pub fn max_lookbehind(&self) -> i32 { unsafe { ffi::g_regex_get_max_lookbehind(self.to_glib_none().0) } } #[doc(alias = "g_regex_get_pattern")] #[doc(alias = "get_pattern")] pub fn pattern(&self) -> crate::GString { unsafe { from_glib_none(ffi::g_regex_get_pattern(self.to_glib_none().0)) } } //#[doc(alias = "g_regex_replace_eval")] //pub fn replace_eval(&self, string: &[&str], start_position: i32, match_options: RegexMatchFlags, eval: /*Unimplemented*/FnMut(&MatchInfo, /*Ignored*/String) -> bool, user_data: /*Unimplemented*/Option) -> Result { // unsafe { TODO: call ffi:g_regex_replace_eval() } //} } glib-0.20.9/src/auto/source.rs000064400000000000000000000105271046102023000142430ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::{ffi, translate::*, MainContext}; crate::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Source(Shared); match fn { ref => |ptr| ffi::g_source_ref(ptr), unref => |ptr| ffi::g_source_unref(ptr), type_ => || ffi::g_source_get_type(), } } impl Source { //#[doc(alias = "g_source_new")] //pub fn new(source_funcs: /*Ignored*/&mut SourceFuncs, struct_size: u32) -> Source { // unsafe { TODO: call ffi:g_source_new() } //} #[doc(alias = "g_source_add_child_source")] pub fn add_child_source(&self, child_source: &Source) { unsafe { ffi::g_source_add_child_source(self.to_glib_none().0, child_source.to_glib_none().0); } } //#[doc(alias = "g_source_add_poll")] //pub fn add_poll(&self, fd: /*Ignored*/&mut PollFD) { // unsafe { TODO: call ffi:g_source_add_poll() } //} //#[doc(alias = "g_source_add_unix_fd")] //pub fn add_unix_fd(&self, fd: i32, events: IOCondition) -> /*Unimplemented*/Basic: Pointer { // unsafe { TODO: call ffi:g_source_add_unix_fd() } //} #[doc(alias = "g_source_destroy")] pub fn destroy(&self) { unsafe { ffi::g_source_destroy(self.to_glib_none().0); } } #[doc(alias = "g_source_get_can_recurse")] #[doc(alias = "get_can_recurse")] pub fn can_recurse(&self) -> bool { unsafe { from_glib(ffi::g_source_get_can_recurse(self.to_glib_none().0)) } } #[doc(alias = "g_source_get_context")] #[doc(alias = "get_context")] pub fn context(&self) -> Option { unsafe { from_glib_none(ffi::g_source_get_context(self.to_glib_none().0)) } } #[doc(alias = "g_source_get_name")] #[doc(alias = "get_name")] pub fn name(&self) -> Option { unsafe { from_glib_none(ffi::g_source_get_name(self.to_glib_none().0)) } } #[doc(alias = "g_source_get_priority")] #[doc(alias = "get_priority")] pub fn priority(&self) -> i32 { unsafe { ffi::g_source_get_priority(self.to_glib_none().0) } } #[doc(alias = "g_source_get_ready_time")] #[doc(alias = "get_ready_time")] pub fn ready_time(&self) -> i64 { unsafe { ffi::g_source_get_ready_time(self.to_glib_none().0) } } #[doc(alias = "g_source_get_time")] #[doc(alias = "get_time")] pub fn time(&self) -> i64 { unsafe { ffi::g_source_get_time(self.to_glib_none().0) } } #[doc(alias = "g_source_is_destroyed")] pub fn is_destroyed(&self) -> bool { unsafe { from_glib(ffi::g_source_is_destroyed(self.to_glib_none().0)) } } //#[doc(alias = "g_source_modify_unix_fd")] //pub fn modify_unix_fd(&self, tag: /*Unimplemented*/Basic: Pointer, new_events: IOCondition) { // unsafe { TODO: call ffi:g_source_modify_unix_fd() } //} //#[doc(alias = "g_source_query_unix_fd")] //pub fn query_unix_fd(&self, tag: /*Unimplemented*/Basic: Pointer) -> IOCondition { // unsafe { TODO: call ffi:g_source_query_unix_fd() } //} #[doc(alias = "g_source_remove_child_source")] pub fn remove_child_source(&self, child_source: &Source) { unsafe { ffi::g_source_remove_child_source(self.to_glib_none().0, child_source.to_glib_none().0); } } //#[doc(alias = "g_source_remove_poll")] //pub fn remove_poll(&self, fd: /*Ignored*/&mut PollFD) { // unsafe { TODO: call ffi:g_source_remove_poll() } //} //#[doc(alias = "g_source_remove_unix_fd")] //pub fn remove_unix_fd(&self, tag: /*Unimplemented*/Basic: Pointer) { // unsafe { TODO: call ffi:g_source_remove_unix_fd() } //} //#[doc(alias = "g_source_remove_by_funcs_user_data")] //pub fn remove_by_funcs_user_data(funcs: /*Ignored*/&mut SourceFuncs, user_data: /*Unimplemented*/Option) -> bool { // unsafe { TODO: call ffi:g_source_remove_by_funcs_user_data() } //} //#[doc(alias = "g_source_remove_by_user_data")] //pub fn remove_by_user_data(user_data: /*Unimplemented*/Option) -> bool { // unsafe { TODO: call ffi:g_source_remove_by_user_data() } //} } unsafe impl Send for Source {} unsafe impl Sync for Source {} glib-0.20.9/src/auto/time_zone.rs000064400000000000000000000060311046102023000147270ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::{ffi, translate::*, TimeType}; crate::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct TimeZone(Shared); match fn { ref => |ptr| ffi::g_time_zone_ref(ptr), unref => |ptr| ffi::g_time_zone_unref(ptr), type_ => || ffi::g_time_zone_get_type(), } } impl TimeZone { #[cfg_attr(feature = "v2_68", deprecated = "Since 2.68")] #[allow(deprecated)] #[doc(alias = "g_time_zone_new")] pub fn new(identifier: Option<&str>) -> TimeZone { unsafe { from_glib_full(ffi::g_time_zone_new(identifier.to_glib_none().0)) } } #[cfg(feature = "v2_68")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_68")))] #[doc(alias = "g_time_zone_new_identifier")] #[doc(alias = "new_identifier")] pub fn from_identifier(identifier: Option<&str>) -> Option { unsafe { from_glib_full(ffi::g_time_zone_new_identifier(identifier.to_glib_none().0)) } } #[doc(alias = "g_time_zone_new_local")] #[doc(alias = "new_local")] pub fn local() -> TimeZone { unsafe { from_glib_full(ffi::g_time_zone_new_local()) } } #[cfg(feature = "v2_58")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_58")))] #[doc(alias = "g_time_zone_new_offset")] #[doc(alias = "new_offset")] pub fn from_offset(seconds: i32) -> TimeZone { unsafe { from_glib_full(ffi::g_time_zone_new_offset(seconds)) } } #[doc(alias = "g_time_zone_new_utc")] #[doc(alias = "new_utc")] pub fn utc() -> TimeZone { unsafe { from_glib_full(ffi::g_time_zone_new_utc()) } } #[doc(alias = "g_time_zone_find_interval")] pub fn find_interval(&self, type_: TimeType, time_: i64) -> i32 { unsafe { ffi::g_time_zone_find_interval(self.to_glib_none().0, type_.into_glib(), time_) } } #[doc(alias = "g_time_zone_get_abbreviation")] #[doc(alias = "get_abbreviation")] pub fn abbreviation(&self, interval: i32) -> crate::GString { unsafe { from_glib_none(ffi::g_time_zone_get_abbreviation( self.to_glib_none().0, interval, )) } } #[cfg(feature = "v2_58")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_58")))] #[doc(alias = "g_time_zone_get_identifier")] #[doc(alias = "get_identifier")] pub fn identifier(&self) -> crate::GString { unsafe { from_glib_none(ffi::g_time_zone_get_identifier(self.to_glib_none().0)) } } #[doc(alias = "g_time_zone_get_offset")] #[doc(alias = "get_offset")] pub fn offset(&self, interval: i32) -> i32 { unsafe { ffi::g_time_zone_get_offset(self.to_glib_none().0, interval) } } #[doc(alias = "g_time_zone_is_dst")] pub fn is_dst(&self, interval: i32) -> bool { unsafe { from_glib(ffi::g_time_zone_is_dst(self.to_glib_none().0, interval)) } } } unsafe impl Send for TimeZone {} unsafe impl Sync for TimeZone {} glib-0.20.9/src/auto/uri.rs000064400000000000000000000413011046102023000135340ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::{ffi, translate::*, Bytes, Error, UriFlags, UriHideFlags}; crate::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Uri(Shared); match fn { ref => |ptr| ffi::g_uri_ref(ptr), unref => |ptr| ffi::g_uri_unref(ptr), type_ => || ffi::g_uri_get_type(), } } impl Uri { #[doc(alias = "g_uri_get_auth_params")] #[doc(alias = "get_auth_params")] pub fn auth_params(&self) -> Option { unsafe { from_glib_none(ffi::g_uri_get_auth_params(self.to_glib_none().0)) } } #[doc(alias = "g_uri_get_flags")] #[doc(alias = "get_flags")] pub fn flags(&self) -> UriFlags { unsafe { from_glib(ffi::g_uri_get_flags(self.to_glib_none().0)) } } #[doc(alias = "g_uri_get_fragment")] #[doc(alias = "get_fragment")] pub fn fragment(&self) -> Option { unsafe { from_glib_none(ffi::g_uri_get_fragment(self.to_glib_none().0)) } } #[doc(alias = "g_uri_get_host")] #[doc(alias = "get_host")] pub fn host(&self) -> Option { unsafe { from_glib_none(ffi::g_uri_get_host(self.to_glib_none().0)) } } #[doc(alias = "g_uri_get_password")] #[doc(alias = "get_password")] pub fn password(&self) -> Option { unsafe { from_glib_none(ffi::g_uri_get_password(self.to_glib_none().0)) } } #[doc(alias = "g_uri_get_path")] #[doc(alias = "get_path")] pub fn path(&self) -> crate::GString { unsafe { from_glib_none(ffi::g_uri_get_path(self.to_glib_none().0)) } } #[doc(alias = "g_uri_get_port")] #[doc(alias = "get_port")] pub fn port(&self) -> i32 { unsafe { ffi::g_uri_get_port(self.to_glib_none().0) } } #[doc(alias = "g_uri_get_query")] #[doc(alias = "get_query")] pub fn query(&self) -> Option { unsafe { from_glib_none(ffi::g_uri_get_query(self.to_glib_none().0)) } } #[doc(alias = "g_uri_get_scheme")] #[doc(alias = "get_scheme")] pub fn scheme(&self) -> crate::GString { unsafe { from_glib_none(ffi::g_uri_get_scheme(self.to_glib_none().0)) } } #[doc(alias = "g_uri_get_user")] #[doc(alias = "get_user")] pub fn user(&self) -> Option { unsafe { from_glib_none(ffi::g_uri_get_user(self.to_glib_none().0)) } } #[doc(alias = "g_uri_get_userinfo")] #[doc(alias = "get_userinfo")] pub fn userinfo(&self) -> Option { unsafe { from_glib_none(ffi::g_uri_get_userinfo(self.to_glib_none().0)) } } #[doc(alias = "g_uri_parse_relative")] pub fn parse_relative(&self, uri_ref: &str, flags: UriFlags) -> Result { unsafe { let mut error = std::ptr::null_mut(); let ret = ffi::g_uri_parse_relative( self.to_glib_none().0, uri_ref.to_glib_none().0, flags.into_glib(), &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_uri_to_string")] #[doc(alias = "to_string")] pub fn to_str(&self) -> crate::GString { unsafe { from_glib_full(ffi::g_uri_to_string(self.to_glib_none().0)) } } #[doc(alias = "g_uri_to_string_partial")] pub fn to_string_partial(&self, flags: UriHideFlags) -> crate::GString { unsafe { from_glib_full(ffi::g_uri_to_string_partial( self.to_glib_none().0, flags.into_glib(), )) } } #[doc(alias = "g_uri_build")] pub fn build( flags: UriFlags, scheme: &str, userinfo: Option<&str>, host: Option<&str>, port: i32, path: &str, query: Option<&str>, fragment: Option<&str>, ) -> Uri { unsafe { from_glib_full(ffi::g_uri_build( flags.into_glib(), scheme.to_glib_none().0, userinfo.to_glib_none().0, host.to_glib_none().0, port, path.to_glib_none().0, query.to_glib_none().0, fragment.to_glib_none().0, )) } } #[doc(alias = "g_uri_build_with_user")] pub fn build_with_user( flags: UriFlags, scheme: &str, user: Option<&str>, password: Option<&str>, auth_params: Option<&str>, host: Option<&str>, port: i32, path: &str, query: Option<&str>, fragment: Option<&str>, ) -> Uri { unsafe { from_glib_full(ffi::g_uri_build_with_user( flags.into_glib(), scheme.to_glib_none().0, user.to_glib_none().0, password.to_glib_none().0, auth_params.to_glib_none().0, host.to_glib_none().0, port, path.to_glib_none().0, query.to_glib_none().0, fragment.to_glib_none().0, )) } } #[doc(alias = "g_uri_escape_bytes")] pub fn escape_bytes(unescaped: &[u8], reserved_chars_allowed: Option<&str>) -> crate::GString { let length = unescaped.len() as _; unsafe { from_glib_full(ffi::g_uri_escape_bytes( unescaped.to_glib_none().0, length, reserved_chars_allowed.to_glib_none().0, )) } } #[doc(alias = "g_uri_escape_string")] pub fn escape_string( unescaped: &str, reserved_chars_allowed: Option<&str>, allow_utf8: bool, ) -> crate::GString { unsafe { from_glib_full(ffi::g_uri_escape_string( unescaped.to_glib_none().0, reserved_chars_allowed.to_glib_none().0, allow_utf8.into_glib(), )) } } #[doc(alias = "g_uri_is_valid")] pub fn is_valid(uri_string: &str, flags: UriFlags) -> Result<(), crate::Error> { unsafe { let mut error = std::ptr::null_mut(); let is_ok = ffi::g_uri_is_valid(uri_string.to_glib_none().0, flags.into_glib(), &mut error); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_uri_join")] pub fn join( flags: UriFlags, scheme: Option<&str>, userinfo: Option<&str>, host: Option<&str>, port: i32, path: &str, query: Option<&str>, fragment: Option<&str>, ) -> crate::GString { unsafe { from_glib_full(ffi::g_uri_join( flags.into_glib(), scheme.to_glib_none().0, userinfo.to_glib_none().0, host.to_glib_none().0, port, path.to_glib_none().0, query.to_glib_none().0, fragment.to_glib_none().0, )) } } #[doc(alias = "g_uri_join_with_user")] pub fn join_with_user( flags: UriFlags, scheme: Option<&str>, user: Option<&str>, password: Option<&str>, auth_params: Option<&str>, host: Option<&str>, port: i32, path: &str, query: Option<&str>, fragment: Option<&str>, ) -> crate::GString { unsafe { from_glib_full(ffi::g_uri_join_with_user( flags.into_glib(), scheme.to_glib_none().0, user.to_glib_none().0, password.to_glib_none().0, auth_params.to_glib_none().0, host.to_glib_none().0, port, path.to_glib_none().0, query.to_glib_none().0, fragment.to_glib_none().0, )) } } #[doc(alias = "g_uri_list_extract_uris")] pub fn list_extract_uris(uri_list: &str) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::g_uri_list_extract_uris( uri_list.to_glib_none().0, )) } } #[doc(alias = "g_uri_parse")] pub fn parse(uri_string: &str, flags: UriFlags) -> Result { unsafe { let mut error = std::ptr::null_mut(); let ret = ffi::g_uri_parse(uri_string.to_glib_none().0, flags.into_glib(), &mut error); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } //#[doc(alias = "g_uri_parse_params")] //pub fn parse_params(params: &str, separators: &str, flags: UriParamsFlags) -> Result { // unsafe { TODO: call ffi:g_uri_parse_params() } //} #[doc(alias = "g_uri_parse_scheme")] pub fn parse_scheme(uri: &str) -> Option { unsafe { from_glib_full(ffi::g_uri_parse_scheme(uri.to_glib_none().0)) } } #[doc(alias = "g_uri_peek_scheme")] pub fn peek_scheme(uri: &str) -> Option { unsafe { from_glib_none(ffi::g_uri_peek_scheme(uri.to_glib_none().0)) } } #[doc(alias = "g_uri_resolve_relative")] pub fn resolve_relative( base_uri_string: Option<&str>, uri_ref: &str, flags: UriFlags, ) -> Result { unsafe { let mut error = std::ptr::null_mut(); let ret = ffi::g_uri_resolve_relative( base_uri_string.to_glib_none().0, uri_ref.to_glib_none().0, flags.into_glib(), &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_uri_split")] pub fn split( uri_ref: &str, flags: UriFlags, ) -> Result< ( Option, Option, Option, i32, crate::GString, Option, Option, ), crate::Error, > { unsafe { let mut scheme = std::ptr::null_mut(); let mut userinfo = std::ptr::null_mut(); let mut host = std::ptr::null_mut(); let mut port = std::mem::MaybeUninit::uninit(); let mut path = std::ptr::null_mut(); let mut query = std::ptr::null_mut(); let mut fragment = std::ptr::null_mut(); let mut error = std::ptr::null_mut(); let is_ok = ffi::g_uri_split( uri_ref.to_glib_none().0, flags.into_glib(), &mut scheme, &mut userinfo, &mut host, port.as_mut_ptr(), &mut path, &mut query, &mut fragment, &mut error, ); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(( from_glib_full(scheme), from_glib_full(userinfo), from_glib_full(host), port.assume_init(), from_glib_full(path), from_glib_full(query), from_glib_full(fragment), )) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_uri_split_network")] pub fn split_network( uri_string: &str, flags: UriFlags, ) -> Result<(Option, Option, i32), crate::Error> { unsafe { let mut scheme = std::ptr::null_mut(); let mut host = std::ptr::null_mut(); let mut port = std::mem::MaybeUninit::uninit(); let mut error = std::ptr::null_mut(); let is_ok = ffi::g_uri_split_network( uri_string.to_glib_none().0, flags.into_glib(), &mut scheme, &mut host, port.as_mut_ptr(), &mut error, ); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(( from_glib_full(scheme), from_glib_full(host), port.assume_init(), )) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_uri_split_with_user")] pub fn split_with_user( uri_ref: &str, flags: UriFlags, ) -> Result< ( Option, Option, Option, Option, Option, i32, crate::GString, Option, Option, ), crate::Error, > { unsafe { let mut scheme = std::ptr::null_mut(); let mut user = std::ptr::null_mut(); let mut password = std::ptr::null_mut(); let mut auth_params = std::ptr::null_mut(); let mut host = std::ptr::null_mut(); let mut port = std::mem::MaybeUninit::uninit(); let mut path = std::ptr::null_mut(); let mut query = std::ptr::null_mut(); let mut fragment = std::ptr::null_mut(); let mut error = std::ptr::null_mut(); let is_ok = ffi::g_uri_split_with_user( uri_ref.to_glib_none().0, flags.into_glib(), &mut scheme, &mut user, &mut password, &mut auth_params, &mut host, port.as_mut_ptr(), &mut path, &mut query, &mut fragment, &mut error, ); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(( from_glib_full(scheme), from_glib_full(user), from_glib_full(password), from_glib_full(auth_params), from_glib_full(host), port.assume_init(), from_glib_full(path), from_glib_full(query), from_glib_full(fragment), )) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_uri_unescape_bytes")] pub fn unescape_bytes( escaped_string: &str, illegal_characters: Option<&str>, ) -> Result { let length = escaped_string.len() as _; unsafe { let mut error = std::ptr::null_mut(); let ret = ffi::g_uri_unescape_bytes( escaped_string.to_glib_none().0, length, illegal_characters.to_glib_none().0, &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_uri_unescape_segment")] pub fn unescape_segment( escaped_string: Option<&str>, escaped_string_end: Option<&str>, illegal_characters: Option<&str>, ) -> Option { unsafe { from_glib_full(ffi::g_uri_unescape_segment( escaped_string.to_glib_none().0, escaped_string_end.to_glib_none().0, illegal_characters.to_glib_none().0, )) } } #[doc(alias = "g_uri_unescape_string")] pub fn unescape_string( escaped_string: &str, illegal_characters: Option<&str>, ) -> Option { unsafe { from_glib_full(ffi::g_uri_unescape_string( escaped_string.to_glib_none().0, illegal_characters.to_glib_none().0, )) } } } impl std::fmt::Display for Uri { #[inline] fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.write_str(&self.to_str()) } } unsafe impl Send for Uri {} unsafe impl Sync for Uri {} glib-0.20.9/src/auto/versions.txt000064400000000000000000000002041046102023000147750ustar 00000000000000Generated by gir (https://github.com/gtk-rs/gir @ 2b05eaddce95) from gir-files (https://github.com/gtk-rs/gir-files @ 5089b7ff80cd) glib-0.20.9/src/boxed.rs000064400000000000000000000611731046102023000130770ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! `IMPL` Boxed wrapper implementation. use std::{ cmp, fmt, hash::{Hash, Hasher}, marker::PhantomData, ops::{Deref, DerefMut}, ptr, }; use crate::translate::*; // rustdoc-stripper-ignore-next /// Wrapper implementations for Boxed types. See `wrapper!`. #[macro_export] macro_rules! glib_boxed_wrapper { ([$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty, @copy $copy_arg:ident $copy_expr:expr, @free $free_arg:ident $free_expr:expr $(, @type_ $get_type_expr:expr)?) => { $crate::glib_boxed_wrapper!(@generic_impl [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name); $crate::glib_boxed_wrapper!( @memory_manager_impl $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr ); $crate::glib_boxed_wrapper!(@value_impl $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name $(, @type_ $get_type_expr)?); }; (@generic_impl [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty) => { $(#[$attr])* #[doc = "\n\nGLib type: Boxed type with copy-on-clone semantics."] #[repr(transparent)] $visibility struct $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? { inner: $crate::boxed::Boxed<$ffi_name, Self>, } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $name $(<$($generic),+>)? { #[doc = "Return the inner pointer to the underlying C value."] #[inline] pub fn as_ptr(&self) -> *mut $ffi_name { unsafe { *(self as *const Self as *const *const $ffi_name) as *mut $ffi_name } } #[doc = "Borrows the underlying C value."] #[inline] pub unsafe fn from_glib_ptr_borrow(ptr: &*mut $ffi_name) -> &Self { debug_assert_eq!( std::mem::size_of::(), std::mem::size_of::<$crate::ffi::gpointer>() ); debug_assert!(!ptr.is_null()); &*(ptr as *const *mut $ffi_name as *const Self) } #[doc = "Borrows the underlying C value mutably."] #[inline] pub unsafe fn from_glib_ptr_borrow_mut(ptr: &mut *mut $ffi_name) -> &mut Self { debug_assert_eq!( std::mem::size_of::(), std::mem::size_of::<$crate::ffi::gpointer>() ); debug_assert!(!ptr.is_null()); &mut *(ptr as *mut *mut $ffi_name as *mut Self) } } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::clone::Clone for $name $(<$($generic),+>)? { #[doc = "Copies the boxed type with the type-specific copy function."] #[inline] fn clone(&self) -> Self { Self { inner: std::clone::Clone::clone(&self.inner), } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::GlibPtrDefault for $name $(<$($generic),+>)? { type GlibType = *mut $ffi_name; } #[doc(hidden)] unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::TransparentPtrType for $name $(<$($generic),+>)? {} #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibPtr<'a, *const $ffi_name> for $name $(<$($generic),+>)? { type Storage = std::marker::PhantomData<&'a $crate::boxed::Boxed<$ffi_name, Self>>; #[inline] fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *const $ffi_name, Self> { let stash = $crate::translate::ToGlibPtr::to_glib_none(&self.inner); $crate::translate::Stash(stash.0, stash.1) } #[inline] fn to_glib_full(&self) -> *const $ffi_name { $crate::translate::ToGlibPtr::to_glib_full(&self.inner) } } #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibPtr<'a, *mut $ffi_name> for $name $(<$($generic),+>)? { type Storage = std::marker::PhantomData<&'a $crate::boxed::Boxed<$ffi_name, Self>>; #[inline] fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *mut $ffi_name, Self> { let stash = $crate::translate::ToGlibPtr::to_glib_none(&self.inner); $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.inner) as *mut _ } } #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibPtrMut<'a, *mut $ffi_name> for $name $(<$($generic),+>)? { type Storage = std::marker::PhantomData<&'a mut $crate::boxed::Boxed<$ffi_name, Self>>; #[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.inner); $crate::translate::StashMut(stash.0, stash.1) } } #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibContainerFromSlice<'a, *mut *const $ffi_name> for $name $(<$($generic),+>)? { type Storage = (std::marker::PhantomData<&'a [Self]>, Option>); fn to_glib_none_from_slice(t: &'a [Self]) -> (*mut *const $ffi_name, Self::Storage) { let mut v_ptr = Vec::with_capacity(t.len() + 1); unsafe { let ptr = v_ptr.as_mut_ptr(); std::ptr::copy_nonoverlapping(t.as_ptr() as *mut *const $ffi_name, ptr, t.len()); std::ptr::write(ptr.add(t.len()), std::ptr::null_mut()); v_ptr.set_len(t.len() + 1); } (v_ptr.as_ptr() as *mut *const $ffi_name, (std::marker::PhantomData, Some(v_ptr))) } fn to_glib_container_from_slice(t: &'a [Self]) -> (*mut *const $ffi_name, Self::Storage) { let v_ptr = unsafe { let v_ptr = $crate::ffi::g_malloc(std::mem::size_of::<*const $ffi_name>() * (t.len() + 1)) as *mut *const $ffi_name; std::ptr::copy_nonoverlapping(t.as_ptr() as *mut *const $ffi_name, v_ptr, t.len()); std::ptr::write(v_ptr.add(t.len()), std::ptr::null_mut()); v_ptr }; (v_ptr, (std::marker::PhantomData, None)) } fn to_glib_full_from_slice(t: &[Self]) -> *mut *const $ffi_name { unsafe { let v_ptr = $crate::ffi::g_malloc(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)); } std::ptr::write(v_ptr.add(t.len()), std::ptr::null_mut()); v_ptr } } } #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibContainerFromSlice<'a, *const *const $ffi_name> for $name $(<$($generic),+>)? { type Storage = (std::marker::PhantomData<&'a [Self]>, Option>); fn to_glib_none_from_slice(t: &'a [Self]) -> (*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 [Self]) -> (*const *const $ffi_name, Self::Storage) { // Can't have consumer free a *const pointer unimplemented!() } fn to_glib_full_from_slice(_: &[Self]) -> *const *const $ffi_name { // Can't have consumer free a *const pointer unimplemented!() } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrNone<*mut $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn from_glib_none(ptr: *mut $ffi_name) -> Self { Self { inner: $crate::translate::from_glib_none(ptr), } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrNone<*const $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn from_glib_none(ptr: *const $ffi_name) -> Self { Self { inner: $crate::translate::from_glib_none(ptr), } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrFull<*mut $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn from_glib_full(ptr: *mut $ffi_name) -> Self { Self { inner: $crate::translate::from_glib_full(ptr), } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrFull<*const $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn from_glib_full(ptr: *const $ffi_name) -> Self { Self { inner: $crate::translate::from_glib_full(ptr), } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrBorrow<*mut $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn from_glib_borrow(ptr: *mut $ffi_name) -> $crate::translate::Borrowed { $crate::translate::Borrowed::new( Self { inner: $crate::translate::from_glib_borrow::<_, $crate::boxed::Boxed<_, _>>(ptr).into_inner(), } ) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrBorrow<*const $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn from_glib_borrow(ptr: *const $ffi_name) -> $crate::translate::Borrowed { $crate::translate::from_glib_borrow::<_, Self>(ptr as *mut $ffi_name) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name $(<$($generic),+>)? { 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); let res_ptr = res.as_mut_ptr(); for i in 0..num { ::std::ptr::write(res_ptr.add(i), $crate::translate::from_glib_none(std::ptr::read(ptr.add(i)))); } res.set_len(num); res } unsafe fn from_glib_container_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { let res = $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); $crate::ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { if num == 0 || ptr.is_null() { $crate::ffi::g_free(ptr as *mut _); return Vec::new(); } let mut res = Vec::with_capacity(num); let res_ptr = res.as_mut_ptr(); ::std::ptr::copy_nonoverlapping(ptr as *mut Self, res_ptr, num); res.set_len(num); $crate::ffi::g_free(ptr as *mut _); res } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrArrayContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name $(<$($generic),+>)? { 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 $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::IntoGlibPtr<*mut $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn into_glib_ptr(self) -> *mut $ffi_name { let s = std::mem::ManuallyDrop::new(self); $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(&*s).0 as *mut _ } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::IntoGlibPtr<*const $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn into_glib_ptr(self) -> *const $ffi_name { let s = std::mem::ManuallyDrop::new(self); $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(&*s).0 as *const _ } } }; (@value_impl $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty) => { }; (@value_impl $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty, @type_ $get_type_expr:expr) => { impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::prelude::StaticType for $name $(<$($generic),+>)? { #[inline] fn static_type() -> $crate::types::Type { #[allow(unused_unsafe)] #[allow(clippy::macro_metavars_in_unsafe)] unsafe { $crate::translate::from_glib($get_type_expr) } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::value::ValueType for $name $(<$($generic),+>)? { type Type = Self; } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::value::ValueTypeOptional for $name $(<$($generic),+>)? { } #[doc(hidden)] unsafe impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::value::FromValue<'a> for $name $(<$($generic),+>)? { type Checker = $crate::value::GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a $crate::Value) -> Self { let ptr = $crate::gobject_ffi::g_value_dup_boxed($crate::translate::ToGlibPtr::to_glib_none(value).0); debug_assert!(!ptr.is_null()); >::from_glib_full(ptr as *mut $ffi_name) } } #[doc(hidden)] unsafe impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::value::FromValue<'a> for &'a $name $(<$($generic),+>)? { type Checker = $crate::value::GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a $crate::Value) -> Self { let value = &*(value as *const $crate::Value as *const $crate::gobject_ffi::GValue); <$name $(<$($generic),+>)?>::from_glib_ptr_borrow(&*(&value.data[0].v_pointer as *const $crate::ffi::gpointer as *const *mut $ffi_name)) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::value::ToValue for $name $(<$($generic),+>)? { #[inline] fn to_value(&self) -> $crate::Value { unsafe { let mut value = $crate::Value::from_type_unchecked(::static_type()); $crate::gobject_ffi::g_value_take_boxed( $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_full(self) as *mut _, ); value } } #[inline] fn value_type(&self) -> $crate::Type { ::static_type() } } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::convert::From<$name $(<$($generic),+>)?> for $crate::Value { #[inline] fn from(o: $name $(<$($generic),+>)?) -> Self { unsafe { let mut value = $crate::Value::from_type_unchecked(<$name $(<$($generic),+>)? as $crate::prelude::StaticType>::static_type()); $crate::gobject_ffi::g_value_take_boxed( $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::translate::IntoGlibPtr::<*mut $ffi_name>::into_glib_ptr(o) as *mut _, ); value } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::value::ToValueOptional for $name $(<$($generic),+>)? { #[inline] fn to_value_optional(s: Option<&Self>) -> $crate::Value { let mut value = $crate::Value::for_value_type::(); unsafe { $crate::gobject_ffi::g_value_take_boxed( $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_full(&s) as *mut _, ); } value } } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::prelude::HasParamSpec for $name $(<$($generic),+>)? { type ParamSpec = $crate::ParamSpecBoxed; type SetValue = Self; type BuilderFn = fn(&str) -> $crate::ParamSpecBoxedBuilder; fn param_spec_builder() -> Self::BuilderFn { |name| Self::ParamSpec::builder(name) } } }; (@memory_manager_impl $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty, @copy $copy_arg:ident $copy_expr:expr, @free $free_arg:ident $free_expr:expr) => { #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::boxed::BoxedMemoryManager for $name $(<$($generic),+>)? { type Target = $ffi_name; #[inline] unsafe fn copy($copy_arg: *const Self::Target) -> *mut Self::Target { $copy_expr } #[inline] #[allow(clippy::no_effect)] unsafe fn free($free_arg: *mut Self::Target) { $free_expr; } } }; } // The safety docs really belong in the wrapper!() macro for Boxed /// Memory management functions for a boxed type. pub trait BoxedMemoryManager: 'static { type Target; /// Makes a copy. unsafe fn copy(ptr: *const Self::Target) -> *mut Self::Target; /// Frees the object. unsafe fn free(ptr: *mut Self::Target); } /// Encapsulates memory management logic for boxed types. #[repr(transparent)] pub struct Boxed> { inner: ptr::NonNull, _dummy: PhantomData<*mut MM>, } impl<'a, T: 'static, MM: BoxedMemoryManager> ToGlibPtr<'a, *const T> for Boxed { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const T, Self> { let ptr = self.inner.as_ptr(); Stash(ptr, PhantomData) } #[inline] fn to_glib_full(&self) -> *const T { let ptr = self.inner.as_ptr(); unsafe { MM::copy(ptr) } } } impl<'a, T: 'static, MM: BoxedMemoryManager> ToGlibPtrMut<'a, *mut T> for Boxed { type Storage = PhantomData<&'a mut Self>; #[inline] fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut T, Self> { let ptr = self.inner.as_ptr(); StashMut(ptr, PhantomData) } } impl> FromGlibPtrNone<*mut T> for Boxed { #[inline] unsafe fn from_glib_none(ptr: *mut T) -> Self { debug_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 { debug_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 { debug_assert!(!ptr.is_null()); Self { inner: ptr::NonNull::new_unchecked(ptr), _dummy: PhantomData, } } } impl> FromGlibPtrFull<*const T> for Boxed { #[inline] unsafe fn from_glib_full(ptr: *const T) -> Self { debug_assert!(!ptr.is_null()); Self { inner: ptr::NonNull::new_unchecked(ptr as *mut T), _dummy: PhantomData, } } } impl> FromGlibPtrBorrow<*mut T> for Boxed { #[inline] unsafe fn from_glib_borrow(ptr: *mut T) -> Borrowed { debug_assert!(!ptr.is_null()); Borrowed::new(Self { inner: ptr::NonNull::new_unchecked(ptr), _dummy: PhantomData, }) } } impl> Drop for Boxed { #[inline] fn drop(&mut self) { unsafe { MM::free(self.inner.as_ptr()); } } } 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 { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl> Ord for Boxed { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { self.to_glib_none().0.cmp(&other.to_glib_none().0) } } impl> PartialEq for Boxed { #[inline] fn eq(&self, other: &Self) -> bool { self.to_glib_none().0 == other.to_glib_none().0 } } impl> Eq for Boxed {} impl> Hash for Boxed { #[inline] 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; #[inline] 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 { #[inline] 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.20.9/src/boxed_any_object.rs000064400000000000000000000172071046102023000152730ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ any::Any, cell::{Ref, RefMut}, fmt, }; use crate as glib; use crate::{subclass::prelude::*, Object}; #[derive(Debug)] pub enum BorrowError { InvalidType, AlreadyBorrowed(std::cell::BorrowError), } impl std::error::Error for BorrowError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { Self::InvalidType => None, Self::AlreadyBorrowed(err) => Some(err), } } } impl fmt::Display for BorrowError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { Self::InvalidType => fmt.write_str("type of the inner value is not as requested"), Self::AlreadyBorrowed(_) => fmt.write_str("value is already mutably borrowed"), } } } impl From for BorrowError { fn from(err: std::cell::BorrowError) -> Self { Self::AlreadyBorrowed(err) } } #[derive(Debug)] pub enum BorrowMutError { InvalidType, AlreadyMutBorrowed(std::cell::BorrowMutError), } impl std::error::Error for BorrowMutError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { Self::InvalidType => None, Self::AlreadyMutBorrowed(err) => Some(err), } } } impl fmt::Display for BorrowMutError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { Self::InvalidType => fmt.write_str("type of the inner value is not as requested"), Self::AlreadyMutBorrowed(_) => fmt.write_str("value is already immutably borrowed"), } } } impl From for BorrowMutError { fn from(err: std::cell::BorrowMutError) -> Self { Self::AlreadyMutBorrowed(err) } } mod imp { use std::{any::Any, cell::RefCell}; use crate as glib; use crate::subclass::prelude::*; #[derive(Debug)] pub struct BoxedAnyObject { pub value: RefCell>, } #[glib::object_subclass] impl ObjectSubclass for BoxedAnyObject { const NAME: &'static str = "BoxedAnyObject"; const ALLOW_NAME_CONFLICT: bool = true; type Type = super::BoxedAnyObject; } impl Default for BoxedAnyObject { fn default() -> Self { Self { value: RefCell::new(Box::new(None::)), } } } impl ObjectImpl for BoxedAnyObject {} } glib::wrapper! { // rustdoc-stripper-ignore-next /// This is a subclass of `glib::object::Object` capable of storing any Rust type. /// It let's you insert a Rust type anywhere a `glib::object::Object` is needed. /// The inserted value can then be borrowed as a Rust type, by using the various /// provided methods. /// /// # Examples /// ``` /// use glib::prelude::*; /// use glib::BoxedAnyObject; /// use std::cell::Ref; /// /// struct Author { /// name: String, /// subscribers: usize /// } /// // BoxedAnyObject can contain any custom type /// let boxed = BoxedAnyObject::new(Author { /// name: String::from("GLibAuthor"), /// subscribers: 1000 /// }); /// /// // The value can be retrieved with `borrow` /// let author: Ref = boxed.borrow(); /// ``` /// /// ```ignore /// use gio::ListStore; /// /// // The boxed data can be stored as a `glib::object::Object` /// let list = ListStore::new::(); /// list.append(&boxed); /// ``` pub struct BoxedAnyObject(ObjectSubclass); } impl BoxedAnyObject { // rustdoc-stripper-ignore-next /// Creates a new `BoxedAnyObject` containing `value` pub fn new(value: T) -> Self { let obj: Self = Object::new(); obj.replace(value); obj } // rustdoc-stripper-ignore-next /// Replaces the wrapped value with a new one, returning the old value, without deinitializing either one. /// The returned value is inside a `Box` and must be manually downcasted if needed. #[track_caller] pub fn replace(&self, t: T) -> Box { self.imp().value.replace(Box::new(t) as Box) } // rustdoc-stripper-ignore-next /// Immutably borrows the wrapped value, returning an error if the value is currently mutably /// borrowed or if it's not of type `T`. /// /// The borrow lasts until the returned `Ref` exits scope. Multiple immutable borrows can be /// taken out at the same time. /// /// This is the non-panicking variant of [`borrow`](#method.borrow). pub fn try_borrow(&self) -> Result, BorrowError> { // The required function is only available on nightly: // https://doc.rust-lang.org/std/cell/struct.Ref.html#method.filter_map. // As a workaround, I check if everything is safe, then I unwrap let borrowed = self.imp().value.try_borrow()?; borrowed .as_ref() .downcast_ref::() .ok_or(BorrowError::InvalidType)?; Ok(self.borrow()) // Now this won't panic } // rustdoc-stripper-ignore-next /// Mutably borrows the wrapped value, returning an error if the value is currently borrowed. /// or if it's not of type `T`. /// /// The borrow lasts until the returned `RefMut` or all `RefMut`s derived /// from it exit scope. The value cannot be borrowed while this borrow is /// active. /// /// This is the non-panicking variant of [`borrow_mut`](#method.borrow_mut). pub fn try_borrow_mut(&mut self) -> Result, BorrowMutError> { // The required function is only available on nightly: // https://doc.rust-lang.org/std/cell/struct.Ref.html#method.filter_map // As a workaround, I check if everything is safe, then I unwrap. let mut borrowed_mut = self.imp().value.try_borrow_mut()?; borrowed_mut .as_mut() .downcast_mut::() .ok_or(BorrowMutError::InvalidType)?; drop(borrowed_mut); Ok(self.borrow_mut()) // Now this won't panic } // rustdoc-stripper-ignore-next /// Immutably borrows the wrapped value. /// /// The borrow lasts until the returned `Ref` exits scope. Multiple /// immutable borrows can be taken out at the same time. /// /// # Panics /// /// Panics if the value is currently mutably borrowed or if it's not of type `T`. /// /// For a non-panicking variant, use /// [`try_borrow`](#method.try_borrow). #[track_caller] pub fn borrow(&self) -> Ref<'_, T> { Ref::map(self.imp().value.borrow(), |value| { value .as_ref() .downcast_ref::() .expect("can't downcast value to requested type") }) } // rustdoc-stripper-ignore-next /// Mutably borrows the wrapped value. /// /// The borrow lasts until the returned `RefMut` or all `RefMut`s derived /// from it exit scope. The value cannot be borrowed while this borrow is /// active. /// /// # Panics /// /// Panics if the value is currently borrowed or if it's not of type `T`. /// /// For a non-panicking variant, use /// [`try_borrow_mut`](#method.try_borrow_mut). #[track_caller] pub fn borrow_mut(&self) -> RefMut<'_, T> { RefMut::map(self.imp().value.borrow_mut(), |value| { value .as_mut() .downcast_mut::() .expect("can't downcast value to requested type") }) } } glib-0.20.9/src/boxed_inline.rs000064400000000000000000000736631046102023000144440ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! `IMPL` BoxedInline wrapper implementation. // rustdoc-stripper-ignore-next /// Wrapper implementations for BoxedInline types. See `wrapper!`. #[macro_export] macro_rules! glib_boxed_inline_wrapper { ([$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty $(, @type_ $get_type_expr:expr)?) => { $(#[$attr])* #[doc = "\n\nGLib type: Inline allocated boxed type with stack copy semantics."] #[repr(transparent)] $visibility struct $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? { pub(crate) inner: $ffi_name, $(pub(crate) phantom: std::marker::PhantomData<$($generic),+>,)? } #[allow(clippy::incorrect_clone_impl_on_copy_type)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::clone::Clone for $name $(<$($generic),+>)? { #[doc = "Copies the inline boxed type by value with the type-specific copy function."] #[inline] fn clone(&self) -> Self { Self { inner: std::clone::Clone::clone(&self.inner), $(phantom: std::marker::PhantomData::<$($generic),+>)? } } } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::marker::Copy for $name $(<$($generic),+>)? {} $crate::glib_boxed_inline_wrapper!( @generic_impl $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name, @copy ptr unsafe { let copy = $crate::ffi::g_malloc(std::mem::size_of::<$ffi_name>()) as *mut $ffi_name; std::ptr::copy_nonoverlapping(ptr, copy, 1); copy }, @free ptr unsafe { $crate::ffi::g_free(ptr as *mut _); }, @init _ptr (), @copy_into dest src std::ptr::copy_nonoverlapping(src, dest, 1), @clear _ptr () ); $crate::glib_boxed_inline_wrapper!(@value_impl $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name $(, @type_ $get_type_expr)?); }; ([$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty, @copy $copy_arg:ident $copy_expr:expr, @free $free_arg:ident $free_expr:expr $(, @type_ $get_type_expr:expr)?) => { $(#[$attr])* #[doc = "\n\nGLib type: Inline allocated boxed type with stack copy semantics."] #[repr(transparent)] $visibility struct $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? { pub(crate) inner: $ffi_name, $(pub(crate) phantom: std::marker::PhantomData<$($generic),+>,)? } #[allow(clippy::incorrect_clone_impl_on_copy_type)] #[allow(clippy::non_canonical_clone_impl)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::clone::Clone for $name $(<$($generic),+>)? { #[doc = "Copies the inline boxed type by value with the type-specific copy function."] #[inline] fn clone(&self) -> Self { Self { inner: std::clone::Clone::clone(&self.inner), $(phantom: std::marker::PhantomData::<$($generic),+>)? } } } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::marker::Copy for $name $(<$($generic),+>)? {} $crate::glib_boxed_inline_wrapper!( @generic_impl $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr, @init _ptr (), @copy_into dest src std::ptr::copy_nonoverlapping(src, dest, 1), @clear _ptr () ); $crate::glib_boxed_inline_wrapper!(@value_impl $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name $(, @type_ $get_type_expr)?); }; ([$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty, @init $init_arg:ident $init_expr:expr, @copy_into $copy_into_arg_dest:ident $copy_into_arg_src:ident $copy_into_expr:expr, @clear $clear_arg:ident $clear_expr:expr $(, @type_ $get_type_expr:expr)?) => { $(#[$attr])* #[doc = "\n\nGLib type: Inline allocated boxed type with stack copy semantics."] #[repr(transparent)] $visibility struct $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? { pub(crate) inner: $ffi_name, $(pub(crate) phantom: std::marker::PhantomData<$($generic),+>,)? } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::clone::Clone for $name $(<$($generic),+>)? { #[doc = "Copies the inline boxed type by value with the type-specific copy function."] #[inline] fn clone(&self) -> Self { unsafe { $crate::translate::from_glib_none(&self.inner as *const $ffi_name) } } } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? Drop for $name $(<$($generic),+>)? { #[inline] fn drop(&mut self) { unsafe { let clear = |$clear_arg: *mut $ffi_name| $clear_expr; clear(&mut self.inner as *mut $ffi_name); } } } $crate::glib_boxed_inline_wrapper!( @generic_impl $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name, @copy ptr unsafe { let copy = $crate::ffi::g_malloc(std::mem::size_of::<$ffi_name>()) as *mut $ffi_name; let c = |$copy_into_arg_dest, $copy_into_arg_src| $copy_into_expr; c(copy, ptr); copy }, @free ptr unsafe { let c = |$clear_arg| $clear_expr; c(ptr); $crate::ffi::g_free(ptr as *mut _); }, @init $init_arg $init_expr, @copy_into $copy_into_arg_dest $copy_into_arg_src $copy_into_expr, @clear $clear_arg $clear_expr ); $crate::glib_boxed_inline_wrapper!(@value_impl $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name $(, @type_ $get_type_expr)?); }; ([$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty, @copy $copy_arg:ident $copy_expr:expr, @free $free_arg:ident $free_expr:expr, @init $init_arg:ident $init_expr:expr, @copy_into $copy_into_arg_dest:ident $copy_into_arg_src:ident $copy_into_expr:expr, @clear $clear_arg:ident $clear_expr:expr $(, @type_ $get_type_expr:expr)?) => { $(#[$attr])* #[doc = "\n\nGLib type: Inline allocated boxed type with stack copy semantics."] #[repr(transparent)] $visibility struct $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? { pub(crate) inner: $ffi_name, $(pub(crate) phantom: std::marker::PhantomData<$($generic),+>,)? } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::clone::Clone for $name $(<$($generic),+>)? { #[doc = "Copies the inline boxed type by value with the type-specific copy function."] #[inline] fn clone(&self) -> Self { unsafe { $crate::translate::from_glib_none(&self.inner as *const $ffi_name) } } } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? Drop for $name $(<$($generic),+>)? { #[inline] fn drop(&mut self) { unsafe { let clear = |$clear_arg: *mut $ffi_name| $clear_expr; clear(&mut self.inner as *mut $ffi_name); } } } $crate::glib_boxed_inline_wrapper!( @generic_impl $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr, @init $init_arg $init_expr, @copy_into $copy_into_arg_dest $copy_into_arg_src $copy_into_expr, @clear $clear_arg $clear_expr ); $crate::glib_boxed_inline_wrapper!(@value_impl $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name $(, @type_ $get_type_expr)?); }; (@generic_impl $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty, @copy $copy_arg:ident $copy_expr:expr, @free $free_arg:ident $free_expr:expr, @init $init_arg:ident $init_expr:expr, @copy_into $copy_into_arg_dest:ident $copy_into_arg_src:ident $copy_into_expr:expr, @clear $clear_arg:ident $clear_expr:expr) => { impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $name $(<$($generic),+>)? { #[inline] pub fn as_ptr(&self) -> *mut $ffi_name { &self.inner as *const $ffi_name as *mut _ } #[doc = "Borrows the underlying C value."] #[inline] pub unsafe fn from_glib_ptr_borrow<'a>(ptr: *const $ffi_name) -> &'a Self { debug_assert!(!ptr.is_null()); &*(ptr as *const Self) } #[doc = "Borrows the underlying C value mutably."] #[inline] pub unsafe fn from_glib_ptr_borrow_mut<'a>(ptr: *mut $ffi_name) -> &'a mut Self { debug_assert!(!ptr.is_null()); &mut *(ptr as *mut Self) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::GlibPtrDefault for $name $(<$($generic),+>)? { type GlibType = *mut $ffi_name; } #[doc(hidden)] unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::TransparentType for $name $(<$($generic),+>)? { type GlibType = $ffi_name; } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::Uninitialized for $name $(<$($generic),+>)? { #[inline] unsafe fn uninitialized() -> Self { let mut v = std::mem::MaybeUninit::zeroed(); let init = |$init_arg: *mut $ffi_name| $init_expr; init(v.as_mut_ptr()); Self { inner: v.assume_init(), $(phantom: std::marker::PhantomData::<$($generic),+>)? } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::UnsafeFrom<$ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn unsafe_from(t: $ffi_name) -> Self { Self { inner: t, $(phantom: std::marker::PhantomData::<$($generic),+>)? } } } #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibPtr<'a, *const $ffi_name> for $name $(<$($generic),+>)? { type Storage = std::marker::PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *const $ffi_name, Self> { $crate::translate::Stash(&self.inner as *const $ffi_name, std::marker::PhantomData) } #[inline] fn to_glib_full(&self) -> *const $ffi_name { unsafe { let copy = |$copy_arg: *const $ffi_name| $copy_expr; copy(&self.inner as *const $ffi_name) } } } #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibPtrMut<'a, *mut $ffi_name> for $name $(<$($generic),+>)? { type Storage = std::marker::PhantomData<&'a mut Self>; #[inline] fn to_glib_none_mut(&'a mut self) -> $crate::translate::StashMut<'a, *mut $ffi_name, Self> { let ptr = &mut self.inner as *mut $ffi_name; $crate::translate::StashMut(ptr, std::marker::PhantomData) } } #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibContainerFromSlice<'a, *mut *const $ffi_name> for $name $(<$($generic),+>)? { type Storage = (std::marker::PhantomData<&'a [Self]>, Option>); fn to_glib_none_from_slice(t: &'a [Self]) -> (*mut *const $ffi_name, Self::Storage) { let mut v: Vec<_> = t.iter().map(|s| &s.inner as *const $ffi_name).collect(); v.push(std::ptr::null_mut() as *const $ffi_name); (v.as_mut_ptr(), (std::marker::PhantomData, Some(v))) } fn to_glib_container_from_slice(t: &'a [Self]) -> (*mut *const $ffi_name, Self::Storage) { let v_ptr = unsafe { let v_ptr = $crate::ffi::g_malloc(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), &s.inner as *const $ffi_name); } std::ptr::write(v_ptr.add(t.len()), std::ptr::null_mut()); v_ptr }; (v_ptr, (std::marker::PhantomData, None)) } fn to_glib_full_from_slice(t: &[Self]) -> *mut *const $ffi_name { unsafe { let v_ptr = $crate::ffi::g_malloc(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)); } std::ptr::write(v_ptr.add(t.len()), std::ptr::null_mut()); v_ptr } } } #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibContainerFromSlice<'a, *const *const $ffi_name> for $name $(<$($generic),+>)? { type Storage = (std::marker::PhantomData<&'a [Self]>, Option>); #[inline] fn to_glib_none_from_slice(t: &'a [Self]) -> (*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 [Self]) -> (*const *const $ffi_name, Self::Storage) { // Can't have consumer free a *const pointer unimplemented!() } fn to_glib_full_from_slice(_: &[Self]) -> *const *const $ffi_name { // Can't have consumer free a *const pointer unimplemented!() } } #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibContainerFromSlice<'a, *mut $ffi_name> for $name $(<$($generic),+>)? { type Storage = std::marker::PhantomData<&'a [Self]>; #[inline] fn to_glib_none_from_slice(t: &'a [Self]) -> (*mut $ffi_name, Self::Storage) { (t.as_ptr() as *mut $ffi_name, std::marker::PhantomData) } fn to_glib_container_from_slice(t: &'a [Self]) -> (*mut $ffi_name, Self::Storage) { ( $crate::translate::ToGlibContainerFromSlice::<'a, *mut $ffi_name>::to_glib_full_from_slice(t), std::marker::PhantomData, ) } fn to_glib_full_from_slice(t: &[Self]) -> *mut $ffi_name { let v_ptr = unsafe { let v_ptr = $crate::ffi::g_malloc(std::mem::size_of::<$ffi_name>()) as *mut $ffi_name; for (i, s) in t.iter().enumerate() { let copy_into = |$copy_into_arg_dest: *mut $ffi_name, $copy_into_arg_src: *const $ffi_name| $copy_into_expr; copy_into(v_ptr.add(i), &s.inner as *const $ffi_name); } v_ptr }; v_ptr } } #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibContainerFromSlice<'a, *const $ffi_name> for $name $(<$($generic),+>)? { type Storage = std::marker::PhantomData<&'a [Self]>; #[inline] fn to_glib_none_from_slice(t: &'a [Self]) -> (*const $ffi_name, Self::Storage) { let (ptr, stash) = $crate::translate::ToGlibContainerFromSlice::<'a, *mut $ffi_name>::to_glib_none_from_slice(t); (ptr as *const $ffi_name, stash) } fn to_glib_container_from_slice(_: &'a [Self]) -> (*const $ffi_name, Self::Storage) { // Can't have consumer free a *const pointer unimplemented!() } fn to_glib_full_from_slice(_: &[Self]) -> *const $ffi_name { // Can't have consumer free a *const pointer unimplemented!() } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrNone<*mut $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn from_glib_none(ptr: *mut $ffi_name) -> Self { debug_assert!(!ptr.is_null()); let mut v = ::uninitialized(); let copy_into = |$copy_into_arg_dest: *mut $ffi_name, $copy_into_arg_src: *const $ffi_name| $copy_into_expr; copy_into(&mut v.inner as *mut $ffi_name, ptr as *const $ffi_name); v } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrNone<*const $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn from_glib_none(ptr: *const $ffi_name) -> Self { $crate::translate::from_glib_none::<_, Self>(ptr as *mut $ffi_name) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrFull<*mut $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn from_glib_full(ptr: *mut $ffi_name) -> Self { debug_assert!(!ptr.is_null()); let mut v = ::uninitialized(); let copy_into = |$copy_into_arg_dest: *mut $ffi_name, $copy_into_arg_src: *const $ffi_name| $copy_into_expr; copy_into(&mut v.inner as *mut $ffi_name, ptr as *const $ffi_name); let free = |$free_arg: *mut $ffi_name| $free_expr; free(ptr); v } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrFull<*const $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn from_glib_full(ptr: *const $ffi_name) -> Self { $crate::translate::from_glib_full::<_, Self>(ptr as *mut $ffi_name) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrBorrow<*mut $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn from_glib_borrow(ptr: *mut $ffi_name) -> $crate::translate::Borrowed { debug_assert!(!ptr.is_null()); $crate::translate::Borrowed::new(Self { inner: std::ptr::read(ptr), $(phantom: std::marker::PhantomData::<$($generic),+>)? }) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrBorrow<*const $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn from_glib_borrow(ptr: *const $ffi_name) -> $crate::translate::Borrowed { $crate::translate::from_glib_borrow::<_, Self>(ptr as *mut $ffi_name) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibContainerAsVec<*mut $ffi_name, *mut $ffi_name> for $name $(<$($generic),+>)? { unsafe fn from_glib_none_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec { $crate::translate::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 { $crate::translate::FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr as *const _, num) } unsafe fn from_glib_full_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec { $crate::translate::FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr as *const _, num) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibContainerAsVec<*mut $ffi_name, *const $ffi_name> for $name $(<$($generic),+>)? { 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); let res_ptr = res.as_mut_ptr(); for i in 0..num { ::std::ptr::write(res_ptr.add(i), $crate::translate::from_glib_none(ptr.add(i))); } res.set_len(num); res } unsafe fn from_glib_container_num_as_vec(ptr: *const $ffi_name, num: usize) -> Vec { let res = $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); $crate::ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *const $ffi_name, num: usize) -> Vec { if num == 0 || ptr.is_null() { $crate::ffi::g_free(ptr as *mut _); return Vec::new(); } let mut res = Vec::with_capacity(num); let res_ptr = res.as_mut_ptr(); ::std::ptr::copy_nonoverlapping(ptr as *mut Self, res_ptr, num); res.set_len(num); $crate::ffi::g_free(ptr as *mut _); res } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name $(<$($generic),+>)? { 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); let res_ptr = res.as_mut_ptr(); for i in 0..num { ::std::ptr::write(res_ptr.add(i), $crate::translate::from_glib_none(::std::ptr::read(ptr.add(i)))); } res.set_len(num); res } unsafe fn from_glib_container_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { let res = $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); $crate::ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { if num == 0 || ptr.is_null() { $crate::ffi::g_free(ptr as *mut _); return Vec::new(); } let mut res = Vec::::with_capacity(num); let res_ptr = res.as_mut_ptr(); for i in 0..num { ::std::ptr::write(res_ptr.add(i), $crate::translate::from_glib_full(::std::ptr::read(ptr.add(i)))); } res.set_len(num); $crate::ffi::g_free(ptr as *mut _); res } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrArrayContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name $(<$($generic),+>)? { 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 $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::IntoGlibPtr<*mut $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn into_glib_ptr(self) -> *mut $ffi_name { $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_full(&self) as *mut _ } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::IntoGlibPtr<*const $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn into_glib_ptr(self) -> *const $ffi_name { $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_full(&self) } } }; (@value_impl $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty) => { }; (@value_impl $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty, @type_ $get_type_expr:expr) => { impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::prelude::StaticType for $name $(<$($generic),+>)? { #[inline] fn static_type() -> $crate::types::Type { #[allow(unused_unsafe)] #[allow(clippy::macro_metavars_in_unsafe)] unsafe { $crate::translate::from_glib($get_type_expr) } } } #[doc(hidden)] impl$(<$($generic: 'static + $($bound $(+ $bound2)*)?),+>)? $crate::value::ValueType for $name $(<$($generic),+>)? { type Type = Self; } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::value::ValueTypeOptional for $name $(<$($generic),+>)? { } #[doc(hidden)] unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::value::FromValue<'_> for $name $(<$($generic),+>)? { type Checker = $crate::value::GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'_ $crate::Value) -> Self { let ptr = $crate::gobject_ffi::g_value_get_boxed($crate::translate::ToGlibPtr::to_glib_none(value).0); debug_assert!(!ptr.is_null()); >::from_glib_none(ptr as *const $ffi_name) } } #[doc(hidden)] unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::value::FromValue<'_> for &'_ $name $(<$($generic),+>)? { type Checker = $crate::value::GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'_ $crate::Value) -> Self { let ptr = $crate::gobject_ffi::g_value_get_boxed($crate::translate::ToGlibPtr::to_glib_none(value).0); debug_assert!(!ptr.is_null()); &*(ptr as *const $ffi_name as *const $name $(<$($generic),+>)?) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::value::ToValue for $name $(<$($generic),+>)? { #[inline] fn to_value(&self) -> $crate::Value { unsafe { let mut value = $crate::Value::from_type_unchecked(::static_type()); $crate::gobject_ffi::g_value_set_boxed( $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(self).0 as *mut _, ); value } } #[inline] fn value_type(&self) -> $crate::Type { ::static_type() } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? ::std::convert::From<$name $(<$($generic),+>)?> for $crate::Value { #[inline] fn from(v: $name $(<$($generic),+>)?) -> Self { $crate::value::ToValue::to_value(&v) } } #[doc(hidden)] impl $(<$($generic: 'static + $($bound $(+ $bound2)*)?),+>)? $crate::value::ToValueOptional for $name $(<$($generic),+>)? { #[inline] fn to_value_optional(s: Option<&Self>) -> $crate::Value { let mut value = $crate::Value::for_value_type::(); unsafe { $crate::gobject_ffi::g_value_set_boxed( $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(&s).0 as *mut _, ); } value } } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::prelude::HasParamSpec for $name $(<$($generic),+>)? { type ParamSpec = $crate::ParamSpecBoxed; type SetValue = Self; type BuilderFn = fn(&str) -> $crate::ParamSpecBoxedBuilder; fn param_spec_builder() -> Self::BuilderFn { |name| Self::ParamSpec::builder(name) } } }; } glib-0.20.9/src/bridged_logging.rs000064400000000000000000000344351046102023000151050ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::{gstr, log as glib_log, log_structured_array, translate::*, LogField}; // rustdoc-stripper-ignore-next /// Enumeration of the possible formatting behaviours for a /// [`GlibLogger`](struct.GlibLogger.html). /// /// In order to use this type, `glib` must be built with the `log` feature /// enabled. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum GlibLoggerFormat { // rustdoc-stripper-ignore-next /// A simple format, writing only the message on output. Plain, // rustdoc-stripper-ignore-next /// A simple format, writing file, line and message on output. LineAndFile, // rustdoc-stripper-ignore-next /// A logger using glib structured logging. Structured, } // rustdoc-stripper-ignore-next /// Enumeration of the possible domain handling behaviours for a /// [`GlibLogger`](struct.GlibLogger.html). /// /// In order to use this type, `glib` must be built with the `log` feature /// enabled. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum GlibLoggerDomain { // rustdoc-stripper-ignore-next /// Logs will have no domain specified. None, // rustdoc-stripper-ignore-next /// Logs will use the `target` of the log crate as a domain; this allows /// Rust code, like `warn!(target: "my-domain", "...");` to log to the glib /// logger using the specified domain. CrateTarget, // rustdoc-stripper-ignore-next /// Logs will use the crate path as the log domain. CratePath, } // rustdoc-stripper-ignore-next /// An implementation of a [`log`](https://crates.io/crates/log) compatible /// logger which logs over glib logging facilities. /// /// In order to use this type, `glib` must be built with the `log` feature /// enabled. /// /// Use this if you want to use glib as the main logging output in your application, /// and want to route all logging happening through the log crate to glib logging. /// If you want the opposite, see /// [`rust_log_handler`](fn.rust_log_handler.html). /// /// NOTE: This should never be used when /// [`rust_log_handler`](fn.rust_log_handler.html) has /// been registered as a default glib log handler, otherwise a stack overflow /// will occur. /// /// Example: /// /// ```no_compile /// static glib_logger: glib::GlibLogger = glib::GlibLogger::new( /// glib::GlibLoggerFormat::Plain, /// glib::GlibLoggerDomain::CrateTarget, /// ); /// /// log::set_logger(&glib_logger); /// log::set_max_level(log::LevelFilter::Debug); /// /// log::info!("This line will get logged by glib"); /// ``` #[derive(Debug)] pub struct GlibLogger { format: GlibLoggerFormat, domain: GlibLoggerDomain, } impl GlibLogger { // rustdoc-stripper-ignore-next /// Creates a new instance of [`GlibLogger`](struct.GlibLogger.html). /// See documentation of [`GlibLogger`](struct.GlibLogger.html) for more /// information. /// /// Example: /// /// ```no_compile /// static glib_logger: glib::GlibLogger = glib::GlibLogger::new( /// glib::GlibLoggerFormat::Plain, /// glib::GlibLoggerDomain::CrateTarget, /// ); /// /// log::set_logger(&glib_logger); /// log::set_max_level(log::LevelFilter::Debug); /// /// log::info!("This line will get logged by glib"); /// ``` pub const fn new(format: GlibLoggerFormat, domain: GlibLoggerDomain) -> Self { Self { format, domain } } fn level_to_glib(level: rs_log::Level) -> crate::LogLevel { match level { // Errors are mapped to critical to avoid automatic termination rs_log::Level::Error => crate::LogLevel::Critical, rs_log::Level::Warn => crate::LogLevel::Warning, rs_log::Level::Info => crate::LogLevel::Info, rs_log::Level::Debug => crate::LogLevel::Debug, // There is no equivalent to trace level in glib rs_log::Level::Trace => crate::LogLevel::Debug, } } #[doc(alias = "g_log")] fn write_log(domain: Option<&str>, level: rs_log::Level, message: &std::fmt::Arguments<'_>) { unsafe { use std::fmt::Write; let mut message_builder = crate::GStringBuilder::default(); if write!(&mut message_builder, "{}", message).is_err() { return; } let message = message_builder.into_string(); crate::ffi::g_log( domain.to_glib_none().0, GlibLogger::level_to_glib(level).into_glib(), b"%s\0".as_ptr() as *const _, ToGlibPtr::<*const std::os::raw::c_char>::to_glib_none(&message).0, ); } } fn write_log_structured( domain: Option<&str>, level: rs_log::Level, file: Option<&str>, line: Option, func: Option<&str>, message: &str, ) { // Write line number into a static array to avoid allocating its string // representation. 16 bytes allow 10^15 lines, which should be more than // sufficient. let mut line_buffer = [0u8; 16]; let line = { use std::io::{Cursor, Write}; let mut c = Cursor::new(line_buffer.as_mut_slice()); match line { Some(lineno) => write!(&mut c, "{lineno}").ok(), None => write!(&mut c, "").ok(), }; let pos = c.position() as usize; &line_buffer[..pos] }; let glib_level = GlibLogger::level_to_glib(level); let fields = [ LogField::new(gstr!("PRIORITY"), glib_level.priority().as_bytes()), LogField::new( gstr!("CODE_FILE"), file.unwrap_or("").as_bytes(), ), LogField::new(gstr!("CODE_LINE"), line), LogField::new( gstr!("CODE_FUNC"), func.unwrap_or("").as_bytes(), ), LogField::new(gstr!("MESSAGE"), message.as_bytes()), LogField::new(gstr!("GLIB_DOMAIN"), domain.unwrap_or("default").as_bytes()), ]; log_structured_array(glib_level, &fields); } } impl rs_log::Log for GlibLogger { fn enabled(&self, _: &rs_log::Metadata) -> bool { true } fn log(&self, record: &rs_log::Record) { if !self.enabled(record.metadata()) { return; } let domain = match &self.domain { GlibLoggerDomain::None => None, GlibLoggerDomain::CrateTarget => Some(record.metadata().target()), GlibLoggerDomain::CratePath => record.module_path(), }; match self.format { GlibLoggerFormat::Plain => { GlibLogger::write_log(domain, record.level(), record.args()); } GlibLoggerFormat::LineAndFile => { match (record.file(), record.line()) { (Some(file), Some(line)) => { GlibLogger::write_log( domain, record.level(), &format_args!("{}:{}: {}", file, line, record.args()), ); } (Some(file), None) => { GlibLogger::write_log( domain, record.level(), &format_args!("{}: {}", file, record.args()), ); } _ => { GlibLogger::write_log(domain, record.level(), record.args()); } }; } GlibLoggerFormat::Structured => { let args = record.args(); let args_str; let message = if let Some(s) = args.as_str() { s } else { args_str = args.to_string(); &args_str }; GlibLogger::write_log_structured( domain, record.level(), record.file(), record.line(), record.module_path(), message, ); } }; } fn flush(&self) {} } // rustdoc-stripper-ignore-next /// Provides a glib log handler which routes all logging messages to the /// [`log crate`](https://crates.io/crates/log). /// /// In order to use this function, `glib` must be built with the `log` feature /// enabled. /// /// Use this function if you want to use the log crate as the main logging /// output in your application, and want to route all logging happening in /// glib to the log crate. If you want the opposite, use [`GlibLogger`](struct.GlibLogger.html). /// /// NOTE: This should never be used when [`GlibLogger`](struct.GlibLogger.html) is /// registered as a logger, otherwise a stack overflow will occur. /// /// ```no_run /// glib::log_set_default_handler(glib::rust_log_handler); /// ``` pub fn rust_log_handler(domain: Option<&str>, level: glib_log::LogLevel, message: &str) { let level = match level { glib_log::LogLevel::Error | glib_log::LogLevel::Critical => rs_log::Level::Error, glib_log::LogLevel::Warning => rs_log::Level::Warn, glib_log::LogLevel::Message | glib_log::LogLevel::Info => rs_log::Level::Info, glib_log::LogLevel::Debug => rs_log::Level::Debug, }; rs_log::log!(target: domain.unwrap_or(""), level, "{}", message); } // rustdoc-stripper-ignore-next /// A macro which behaves exactly as `log::error!` except that it sets the /// current log target to the contents of a `G_LOG_DOMAIN` constant (and fails /// to build if not defined). /// /// In order to use this macro, `glib` must be built with the `log_macros` /// feature enabled and the [`GlibLogger`](struct.GlibLogger.html) must have been /// initialized using [`GlibLoggerDomain::CrateTarget`](enum.GlibLoggerDomain.html). /// /// ```no_run /// static G_LOG_DOMAIN: &str = "my-domain"; /// /// glib::error!("This will be logged under 'my-domain'"); /// ``` #[macro_export] #[cfg(any(docsrs, feature = "log_macros"))] #[cfg_attr(docsrs, doc(cfg(feature = "log_macros")))] macro_rules! error { (target: $target:expr, $($arg:tt)+) => ( $crate::rs_log::log!(target: $target, $crate::rs_log::Level::Error, $($arg)+); ); ($($arg:tt)+) => ( $crate::rs_log::log!(target: G_LOG_DOMAIN, $crate::rs_log::Level::Error, $($arg)+); ) } // rustdoc-stripper-ignore-next /// A macro which behaves exactly as `log::warn!` except that it sets the /// current log target to the contents of a `G_LOG_DOMAIN` constant (and fails /// to build if not defined). /// /// In order to use this macro, `glib` must be built with the `log_macros` /// feature enabled and the [`GlibLogger`](struct.GlibLogger.html) must have been /// initialized using [`GlibLoggerDomain::CrateTarget`](enum.GlibLoggerDomain.html). /// /// ```no_run /// static G_LOG_DOMAIN: &str = "my-domain"; /// /// glib::warn!("This will be logged under 'my-domain'"); /// ``` #[macro_export] #[cfg(any(docsrs, feature = "log_macros"))] #[cfg_attr(docsrs, doc(cfg(feature = "log_macros")))] macro_rules! warn { (target: $target:expr, $($arg:tt)+) => ( $crate::rs_log::log!(target: $target, $crate::rs_log::Level::Warn, $($arg)+); ); ($($arg:tt)+) => ( $crate::rs_log::log!(target: G_LOG_DOMAIN, $crate::rs_log::Level::Warn, $($arg)+); ) } // rustdoc-stripper-ignore-next /// A macro which behaves exactly as `log::info!` except that it sets the /// current log target to the contents of a `G_LOG_DOMAIN` constant (and fails /// to build if not defined). /// /// In order to use this macro, `glib` must be built with the `log_macros` /// feature enabled and the [`GlibLogger`](struct.GlibLogger.html) must have been /// initialized using [`GlibLoggerDomain::CrateTarget`](enum.GlibLoggerDomain.html). /// /// ```no_run /// static G_LOG_DOMAIN: &str = "my-domain"; /// /// glib::info!("This will be logged under 'my-domain'"); /// ``` #[macro_export] #[cfg(any(docsrs, feature = "log_macros"))] #[cfg_attr(docsrs, doc(cfg(feature = "log_macros")))] macro_rules! info { (target: $target:expr, $($arg:tt)+) => ( $crate::rs_log::log!(target: $target, $crate::rs_log::Level::Info, $($arg)+); ); ($($arg:tt)+) => ( $crate::rs_log::log!(target: G_LOG_DOMAIN, $crate::rs_log::Level::Info, $($arg)+); ) } // rustdoc-stripper-ignore-next /// A macro which behaves exactly as `log::debug!` except that it sets the /// current log target to the contents of a `G_LOG_DOMAIN` constant (and fails /// to build if not defined). /// /// In order to use this macro, `glib` must be built with the `log_macros` /// feature enabled and the [`GlibLogger`](struct.GlibLogger.html) must have been /// initialized using [`GlibLoggerDomain::CrateTarget`](enum.GlibLoggerDomain.html). /// /// ```no_run /// static G_LOG_DOMAIN: &str = "my-domain"; /// /// glib::debug!("This will be logged under 'my-domain'"); /// ``` #[macro_export] #[cfg(any(docsrs, feature = "log_macros"))] #[cfg_attr(docsrs, doc(cfg(feature = "log_macros")))] macro_rules! debug { (target: $target:expr, $($arg:tt)+) => ( $crate::rs_log::log!(target: $target, $crate::rs_log::Level::Debug, $($arg)+); ); ($($arg:tt)+) => ( $crate::rs_log::log!(target: G_LOG_DOMAIN, $crate::rs_log::Level::Debug, $($arg)+); ) } // rustdoc-stripper-ignore-next /// A macro which behaves exactly as `log::trace!` except that it sets the /// current log target to the contents of a `G_LOG_DOMAIN` constant (and fails /// to build if not defined). /// /// In order to use this macro, `glib` must be built with the `log_macros` /// feature enabled and the [`GlibLogger`](struct.GlibLogger.html) must have been /// initialized using [`GlibLoggerDomain::CrateTarget`](enum.GlibLoggerDomain.html). /// /// ```no_run /// static G_LOG_DOMAIN: &str = "my-domain"; /// /// glib::trace!("This will be logged under 'my-domain'"); /// ``` #[macro_export] #[cfg(any(docsrs, feature = "log_macros"))] #[cfg_attr(docsrs, doc(cfg(feature = "log_macros")))] macro_rules! trace { (target: $target:expr, $($arg:tt)+) => ( $crate::rs_log::log!(target: $target, $crate::rs_log::Level::Trace, $($arg)+); ); ($($arg:tt)+) => ( $crate::rs_log::log!(target: G_LOG_DOMAIN, $crate::rs_log::Level::Trace, $($arg)+); ) } glib-0.20.9/src/byte_array.rs000064400000000000000000000076361046102023000141430ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! # Examples //! //! ``` //! use glib::prelude::*; // or `use gtk::prelude::*;` //! use glib::ByteArray; //! //! let ba = ByteArray::from(b"abc"); //! assert_eq!(ba, "abc".as_bytes()); //! ``` use std::{ borrow::Borrow, cmp::Ordering, fmt, hash::{Hash, Hasher}, ops::Deref, slice, }; use crate::{ffi, translate::*}; wrapper! { #[doc(alias = "GByteArray")] pub struct ByteArray(Shared); match fn { ref => |ptr| ffi::g_byte_array_ref(ptr), unref => |ptr| ffi::g_byte_array_unref(ptr), type_ => || ffi::g_byte_array_get_type(), } } impl Deref for ByteArray { type Target = [u8]; #[inline] fn deref(&self) -> &[u8] { unsafe { let self_ptr: *const ffi::GByteArray = self.to_glib_none().0; let ptr = (*self_ptr).data; let len = (*self_ptr).len as usize; debug_assert!(!ptr.is_null() || len == 0); if ptr.is_null() { &[] } else { slice::from_raw_parts(ptr as *const u8, len) } } } } impl AsRef<[u8]> for ByteArray { #[inline] 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 value = value.borrow(); unsafe { let ba = ffi::g_byte_array_new(); ffi::g_byte_array_append(ba, value.as_ptr(), value.len() as u32); from_glib_full(ba) } } } impl fmt::Debug for ByteArray { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_list().entries(self.as_ref()).finish() } } macro_rules! impl_cmp { ($lhs:ty, $rhs: ty) => { #[allow(clippy::redundant_slicing)] #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialEq<$rhs> for $lhs { #[inline] fn eq(&self, other: &$rhs) -> bool { self[..].eq(&other[..]) } } #[allow(clippy::redundant_slicing)] #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialEq<$lhs> for $rhs { #[inline] fn eq(&self, other: &$lhs) -> bool { self[..].eq(&other[..]) } } #[allow(clippy::redundant_slicing)] #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialOrd<$rhs> for $lhs { #[inline] fn partial_cmp(&self, other: &$rhs) -> Option { self[..].partial_cmp(&other[..]) } } #[allow(clippy::redundant_slicing)] #[allow(clippy::extra_unused_lifetimes)] 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) { Hash::hash_slice(&self[..], state) } } #[cfg(test)] mod tests { use std::collections::HashSet; use super::*; #[test] fn various() { let ba = ByteArray::from(b"foobar"); assert_eq!(ba, b"foobar" as &[u8]); } #[test] fn hash() { let b1 = ByteArray::from(b"this is a test"); let b2 = ByteArray::from(b"this is a test"); let b3 = ByteArray::from(b"test"); let mut set = HashSet::new(); set.insert(b1); assert!(set.contains(&b2)); assert!(!set.contains(&b3)); } } glib-0.20.9/src/bytes.rs000064400000000000000000000230741046102023000131220ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ borrow::Borrow, cmp::Ordering, fmt, hash::{Hash, Hasher}, mem, ops::{Bound, Deref, RangeBounds}, slice, }; use crate::{ffi, translate::*}; wrapper! { // rustdoc-stripper-ignore-next /// A shared immutable byte slice (the equivalent of `Rc<[u8]>`). /// /// `From` implementations that take references (e.g. `&[u8]`) copy the /// data. The `from_static` constructor avoids copying static data. /// /// ``` /// use glib::Bytes; /// /// let v = vec![1, 2, 3]; /// let b = Bytes::from(&v); /// assert_eq!(v, b); /// /// let s = b"xyz"; /// let b = Bytes::from_static(s); /// assert_eq!(&s[..], b); /// ``` #[doc(alias = "GBytes")] pub struct Bytes(Shared); match fn { ref => |ptr| ffi::g_bytes_ref(ptr), unref => |ptr| ffi::g_bytes_unref(ptr), type_ => || ffi::g_bytes_get_type(), } } impl Bytes { // rustdoc-stripper-ignore-next /// Copies `data` into a new shared slice. #[doc(alias = "g_bytes_new")] #[inline] fn new>(data: T) -> Bytes { let data = data.as_ref(); unsafe { from_glib_full(ffi::g_bytes_new(data.as_ptr() as *const _, data.len())) } } // rustdoc-stripper-ignore-next /// Creates a view into static `data` without copying. #[doc(alias = "g_bytes_new_static")] #[inline] pub fn from_static(data: &'static [u8]) -> Bytes { unsafe { from_glib_full(ffi::g_bytes_new_static( data.as_ptr() as *const _, data.len(), )) } } // rustdoc-stripper-ignore-next /// Takes ownership of `data` and creates a new `Bytes` without copying. #[doc(alias = "g_bytes_new")] pub fn from_owned + Send + 'static>(data: T) -> Bytes { let data: Box = Box::new(data); let (size, data_ptr) = { let data = (*data).as_ref(); (data.len(), data.as_ptr()) }; unsafe extern "C" fn drop_box + Send + 'static>(b: ffi::gpointer) { let _: Box = Box::from_raw(b as *mut _); } unsafe { from_glib_full(ffi::g_bytes_new_with_free_func( data_ptr as *const _, size, Some(drop_box::), Box::into_raw(data) as *mut _, )) } } // rustdoc-stripper-ignore-next /// Returns the underlying data of the `Bytes`. /// /// If there is no other reference to `self` then this does not copy the data, otherwise /// it is copied into newly allocated heap memory. #[doc(alias = "g_bytes_unref_to_data")] pub fn into_data(self) -> crate::collections::Slice { unsafe { let mut size = mem::MaybeUninit::uninit(); let ret = ffi::g_bytes_unref_to_data(self.into_glib_ptr(), size.as_mut_ptr()); crate::collections::Slice::from_glib_full_num(ret as *mut u8, size.assume_init()) } } fn calculate_offset_size(&self, range: impl RangeBounds) -> (usize, usize) { let len = self.len(); let start_offset = match range.start_bound() { Bound::Included(v) => *v, Bound::Excluded(v) => v.checked_add(1).expect("Invalid start offset"), Bound::Unbounded => 0, }; assert!(start_offset < len, "Start offset after valid range"); let end_offset = match range.end_bound() { Bound::Included(v) => v.checked_add(1).expect("Invalid end offset"), Bound::Excluded(v) => *v, Bound::Unbounded => len, }; assert!(end_offset <= len, "End offset after valid range"); let size = end_offset.saturating_sub(start_offset); (start_offset, size) } // rustdoc-stripper-ignore-next /// Creates a new `Bytes` that references the given `range` of `bytes`. #[doc(alias = "g_bytes_new_from_bytes")] pub fn from_bytes(bytes: &Self, range: impl RangeBounds) -> Self { let (offset, size) = bytes.calculate_offset_size(range); unsafe { from_glib_full(ffi::g_bytes_new_from_bytes( bytes.to_glib_none().0, offset, size, )) } } } unsafe impl Send for Bytes {} unsafe impl Sync for Bytes {} impl<'a, T: ?Sized + Borrow<[u8]> + 'a> From<&'a T> for Bytes { #[inline] 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", &ToGlibPtr::<*const _>::to_glib_none(self).0) .field("data", &&self[..]) .finish() } } impl AsRef<[u8]> for Bytes { #[inline] fn as_ref(&self) -> &[u8] { self } } impl Deref for Bytes { type Target = [u8]; #[inline] fn deref(&self) -> &[u8] { unsafe { let mut len = 0; let ptr = ffi::g_bytes_get_data(self.to_glib_none().0, &mut len); if ptr.is_null() || len == 0 { &[] } else { slice::from_raw_parts(ptr as *const u8, len) } } } } impl PartialEq for Bytes { #[doc(alias = "g_bytes_equal")] #[inline] fn eq(&self, other: &Self) -> bool { unsafe { from_glib(ffi::g_bytes_equal( ToGlibPtr::<*const _>::to_glib_none(self).0 as *const _, ToGlibPtr::<*const _>::to_glib_none(other).0 as *const _, )) } } } impl Eq for Bytes {} impl PartialOrd for Bytes { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for Bytes { #[inline] fn cmp(&self, other: &Self) -> Ordering { unsafe { let ret = ffi::g_bytes_compare( ToGlibPtr::<*const _>::to_glib_none(self).0 as *const _, ToGlibPtr::<*const _>::to_glib_none(other).0 as *const _, ); ret.cmp(&0) } } } macro_rules! impl_cmp { ($lhs:ty, $rhs: ty) => { #[allow(clippy::redundant_slicing)] #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialEq<$rhs> for $lhs { #[inline] fn eq(&self, other: &$rhs) -> bool { self[..].eq(&other[..]) } } #[allow(clippy::redundant_slicing)] #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialEq<$lhs> for $rhs { #[inline] fn eq(&self, other: &$lhs) -> bool { self[..].eq(&other[..]) } } #[allow(clippy::redundant_slicing)] #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialOrd<$rhs> for $lhs { #[inline] fn partial_cmp(&self, other: &$rhs) -> Option { self[..].partial_cmp(&other[..]) } } #[allow(clippy::redundant_slicing)] #[allow(clippy::extra_unused_lifetimes)] 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 { #[inline] fn hash(&self, state: &mut H) { self.len().hash(state); Hash::hash_slice(self, state) } } #[cfg(test)] mod tests { use std::collections::HashSet; use super::*; #[test] fn eq() { let abc: &[u8] = b"abc"; let def: &[u8] = b"def"; let a1 = Bytes::from(abc); let a2 = Bytes::from(abc); let d = Bytes::from(def); assert_eq!(a1, a2); assert_eq!(def, d); assert_ne!(a1, d); assert_ne!(a1, def); } #[test] fn ord() { let abc: &[u8] = b"abc"; let def: &[u8] = b"def"; let a = Bytes::from(abc); let d = Bytes::from(def); assert!(a < d); assert!(a < def); assert!(abc < d); assert!(d > a); assert!(d > abc); assert!(def > a); } #[test] fn hash() { let b1 = Bytes::from(b"this is a test"); let b2 = Bytes::from(b"this is a test"); let b3 = Bytes::from(b"test"); let mut set = HashSet::new(); set.insert(b1); assert!(set.contains(&b2)); assert!(!set.contains(&b3)); } #[test] fn from_static() { let b1 = Bytes::from_static(b"this is a test"); let b2 = Bytes::from(b"this is a test"); assert_eq!(b1, b2); } #[test] fn from_owned() { let b = Bytes::from_owned(vec![1, 2, 3]); assert_eq!(b, [1u8, 2u8, 3u8].as_ref()); } #[test] fn from_bytes() { let b1 = Bytes::from_owned(vec![1, 2, 3]); let b2 = Bytes::from_bytes(&b1, 1..=1); assert_eq!(b2, [2u8].as_ref()); let b2 = Bytes::from_bytes(&b1, 1..); assert_eq!(b2, [2u8, 3u8].as_ref()); let b2 = Bytes::from_bytes(&b1, ..2); assert_eq!(b2, [1u8, 2u8].as_ref()); let b2 = Bytes::from_bytes(&b1, ..); assert_eq!(b2, [1u8, 2u8, 3u8].as_ref()); } #[test] pub fn into_data() { let b = Bytes::from(b"this is a test"); let d = b.into_data(); assert_eq!(d.as_slice(), b"this is a test"); } } glib-0.20.9/src/char.rs000064400000000000000000000127441046102023000127130ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::num::TryFromIntError; use libc::{c_char, c_uchar}; use crate::translate::*; // rustdoc-stripper-ignore-next /// Wrapper for values where C functions expect a plain C `char` /// /// Consider the following C function prototype from glib: /// /// ```C /// void g_key_file_set_list_separator (GKeyFile *key_file, gchar separator); /// ``` /// /// This function plainly expects a byte as the `separator` argument. However, /// having this function exposed to Rust as the following would be inconvenient: /// /// ```ignore /// impl KeyFile { /// pub fn set_list_separator(&self, separator: libc:c_char) { } /// } /// ``` /// /// This would be inconvenient because users would have to do the conversion from a Rust `char` to an `libc::c_char` by hand, which is just a type alias /// for `i8` on most system. /// /// This `Char` type is a wrapper over an `libc::c_char`, so that we can pass it to Glib or C functions. /// The check for whether a Rust `char` (a Unicode scalar value) actually fits in a `libc::c_char` is /// done in the `new` function; see its documentation for details. /// /// The inner `libc::c_char` (which is equivalent to `i8`) can be extracted with `.0`, or /// by calling `my_char.into_glib()`. /// /// # Examples /// ``` /// use glib::Char; /// use std::convert::TryFrom; /// /// Char::from(b'a'); /// Char::try_from('a').unwrap(); /// assert!(Char::try_from('☔').is_err()); /// ``` /// /// ```ignore /// extern "C" fn have_a_byte(b: libc::c_char); /// /// have_a_byte(Char::from(b'a').into_glib()); /// ``` #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct Char(pub c_char); impl TryFrom for Char { type Error = TryFromIntError; #[allow(clippy::unnecessary_cast)] fn try_from(c: char) -> Result { Ok(Self(u8::try_from(u32::from(c))? as c_char)) } } impl From for char { fn from(c: Char) -> char { c.0 as u8 as char } } impl From for Char { #[allow(clippy::unnecessary_cast)] fn from(c: u8) -> Char { Char(c as c_char) } } impl From for u8 { #[allow(clippy::unnecessary_cast)] fn from(c: Char) -> u8 { c.0 as u8 } } #[doc(hidden)] impl FromGlib for Char { #[inline] unsafe fn from_glib(value: c_char) -> Self { Self(value) } } #[doc(hidden)] impl IntoGlib for Char { type GlibType = c_char; #[inline] fn into_glib(self) -> c_char { self.0 } } // rustdoc-stripper-ignore-next /// Wrapper for values where C functions expect a plain C `unsigned char` /// /// This `UChar` type is a wrapper over an `libc::c_uchar`, so that we can pass it to Glib or C functions. /// The check for whether a Rust `char` (a Unicode scalar value) actually fits in a `libc::c_uchar` is /// done in the `new` function; see its documentation for details. /// /// The inner `libc::c_uchar` (which is equivalent to `u8`) can be extracted with `.0`, or /// by calling `my_char.into_glib()`. /// /// # Examples /// ``` /// use glib::UChar; /// use std::convert::TryFrom; /// /// UChar::from(b'a'); /// UChar::try_from('a').unwrap(); /// assert!(UChar::try_from('☔').is_err()); /// ``` /// /// ```ignore /// extern "C" fn have_a_byte(b: libc::c_uchar); /// /// have_a_byte(UChar::from(b'a').into_glib()); /// ``` #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct UChar(pub c_uchar); impl TryFrom for UChar { type Error = TryFromIntError; #[allow(clippy::unnecessary_cast)] fn try_from(c: char) -> Result { Ok(Self(u8::try_from(u32::from(c))? as c_uchar)) } } impl From for char { fn from(c: UChar) -> char { c.0 as _ } } impl From for UChar { #[allow(clippy::unnecessary_cast)] fn from(c: u8) -> UChar { UChar(c as _) } } impl From for u8 { fn from(c: UChar) -> u8 { c.0 as _ } } #[doc(hidden)] impl FromGlib for UChar { #[inline] unsafe fn from_glib(value: c_uchar) -> Self { Self(value) } } #[doc(hidden)] impl IntoGlib for UChar { type GlibType = c_uchar; #[inline] fn into_glib(self) -> c_uchar { self.0 } } #[cfg(test)] mod tests { use super::*; #[test] #[allow(clippy::unnecessary_cast)] fn converts_single_byte_chars() { assert_eq!(Char::try_from(0 as char), Ok(Char(0 as c_char))); assert_eq!(UChar::try_from(0 as char), Ok(UChar(0 as c_uchar))); assert_eq!(UChar::try_from(255 as char), Ok(UChar(255 as c_uchar))); assert_eq!(UChar::try_from('ñ'), Ok(UChar(241 as c_uchar))); } #[test] fn refuses_multibyte_chars() { assert!(Char::try_from('☔').is_err()); // no umbrella for you assert!(UChar::try_from('☔').is_err()); } #[test] #[allow(clippy::unnecessary_cast)] fn into_i8() { assert_eq!(Char::from(b'A').into_glib(), 65 as c_char); } #[test] #[allow(clippy::unnecessary_cast)] fn into_u8() { assert_eq!(UChar::from(b'A').into_glib(), 65 as c_uchar); } #[test] #[allow(clippy::unnecessary_cast)] fn into_char() { assert_eq!(char::from(Char(65 as c_char)), 'A'); assert_eq!('ñ', UChar(241 as c_uchar).into()); } #[test] #[allow(clippy::unnecessary_cast)] fn convert_from_glib() { assert_eq!(Char(65 as c_char), unsafe { from_glib(65 as c_char) }); assert_eq!(UChar(241 as c_uchar), unsafe { from_glib(241 as c_uchar) }); } } glib-0.20.9/src/checksum.rs000064400000000000000000000036641046102023000136010ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use libc::size_t; use crate::{ffi, translate::*, Checksum}; impl Checksum { #[doc(alias = "g_checksum_get_digest")] #[doc(alias = "get_digest")] pub fn digest(self) -> Vec { unsafe { //Don't forget update when `ChecksumType` contains type bigger that Sha512. let mut digest_len: size_t = 512 / 8; let mut vec = Vec::with_capacity(digest_len as _); ffi::g_checksum_get_digest( mut_override(self.to_glib_none().0), vec.as_mut_ptr(), &mut digest_len, ); vec.set_len(digest_len); vec } } #[doc(alias = "g_checksum_get_string")] #[doc(alias = "get_string")] pub fn string(self) -> Option { unsafe { from_glib_none(ffi::g_checksum_get_string(mut_override( self.to_glib_none().0, ))) } } } #[cfg(test)] mod tests { use crate::{Checksum, ChecksumType}; const CS_TYPE: ChecksumType = ChecksumType::Md5; const CS_VALUE: &str = "fc3ff98e8c6a0d3087d515c0473f8677"; const CS_SLICE: &[u8] = &[ 0xfc, 0x3f, 0xf9, 0x8e, 0x8c, 0x6a, 0x0d, 0x30, 0x87, 0xd5, 0x15, 0xc0, 0x47, 0x3f, 0x86, 0x77, ]; #[test] fn update() { let mut cs = Checksum::new(CS_TYPE).unwrap(); cs.update(b"hello world!"); assert_eq!(cs.string().unwrap(), CS_VALUE); } #[test] fn update_multi_call() { let mut cs = Checksum::new(CS_TYPE).unwrap(); cs.update(b"hello "); cs.update(b"world!"); assert_eq!(cs.string().unwrap(), CS_VALUE); } #[test] #[doc(alias = "get_digest")] fn digest() { let mut cs = Checksum::new(CS_TYPE).unwrap(); cs.update(b"hello world!"); let vec = cs.digest(); assert_eq!(vec, CS_SLICE); } } glib-0.20.9/src/clone.rs000064400000000000000000000040621046102023000130700ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::prelude::*; use std::{ marker::PhantomData, rc::{self, Rc}, sync::{self, Arc}, }; // rustdoc-stripper-ignore-next /// Trait for generalizing downgrading a strong reference to a weak reference. pub trait Downgrade where Self: Sized, { // rustdoc-stripper-ignore-next /// Weak reference type. type Weak: Upgrade; // rustdoc-stripper-ignore-next /// Downgrade to a weak reference. fn downgrade(&self) -> Self::Weak; } // rustdoc-stripper-ignore-next /// Trait for generalizing upgrading a weak reference to a strong reference. pub trait Upgrade where Self: Sized, { // rustdoc-stripper-ignore-next /// Strong reference type. type Strong; // rustdoc-stripper-ignore-next /// Try upgrading a weak reference to a strong reference. fn upgrade(&self) -> Option; } impl Upgrade for crate::WeakRef { type Strong = T; fn upgrade(&self) -> Option { self.upgrade() } } impl Downgrade for PhantomData { type Weak = PhantomData; fn downgrade(&self) -> Self::Weak { PhantomData } } impl Downgrade for &T { type Weak = T::Weak; fn downgrade(&self) -> Self::Weak { T::downgrade(*self) } } impl Downgrade for Arc { type Weak = sync::Weak; fn downgrade(&self) -> Self::Weak { Arc::downgrade(self) } } impl Upgrade for PhantomData { type Strong = PhantomData; fn upgrade(&self) -> Option { Some(PhantomData) } } impl Upgrade for sync::Weak { type Strong = Arc; fn upgrade(&self) -> Option { self.upgrade() } } impl Downgrade for Rc { type Weak = rc::Weak; fn downgrade(&self) -> Self::Weak { Rc::downgrade(self) } } impl Upgrade for rc::Weak { type Strong = Rc; fn upgrade(&self) -> Option { self.upgrade() } } glib-0.20.9/src/closure.rs000064400000000000000000000346531046102023000134550ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // TODO: support marshaller. use std::{mem, ptr, slice}; use libc::{c_uint, c_void}; use crate::{gobject_ffi, prelude::*, translate::*, Type, Value}; wrapper! { #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] #[doc(alias = "GClosure")] pub struct Closure(Shared); match fn { ref => |ptr| { gobject_ffi::g_closure_ref(ptr); gobject_ffi::g_closure_sink(ptr); }, unref => |ptr| gobject_ffi::g_closure_unref(ptr), type_ => || gobject_ffi::g_closure_get_type(), } } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct RustClosure(Closure); impl RustClosure { // rustdoc-stripper-ignore-next /// Creates a new closure around a Rust closure. /// /// See [`glib::closure!`](macro@crate::closure) for a way to create a closure with concrete /// types. /// /// # Panics /// /// Invoking the closure with wrong argument types or returning the wrong return value type /// will panic. /// /// # Example /// /// ``` /// use glib::prelude::*; /// /// let closure = glib::RustClosure::new(|values| { /// let x = values[0].get::().unwrap(); /// Some((x + 1).to_value()) /// }); /// /// assert_eq!( /// closure.invoke::(&[&1i32]), /// 2, /// ); /// ``` #[doc(alias = "g_closure_new")] pub fn new Option + Send + Sync + 'static>(callback: F) -> Self { Self(Closure::new(callback)) } // rustdoc-stripper-ignore-next /// Creates a new closure around a Rust closure. /// /// See [`glib::closure_local!`](crate::closure_local) for a way to create a closure with /// concrete types. /// /// # Panics /// /// Invoking the closure with wrong argument types or returning the wrong return value type /// will panic. /// /// Invoking the closure from a different thread than this one will panic. #[doc(alias = "g_closure_new")] pub fn new_local Option + 'static>(callback: F) -> Self { Self(Closure::new_local(callback)) } // rustdoc-stripper-ignore-next /// Invokes the closure with the given arguments. /// /// For invalidated closures this returns the "default" value of the return type. For nullable /// types this is `None`, which means that e.g. requesting `R = String` will panic will `R = /// Option` will return `None`. /// /// # Panics /// /// The argument types and return value type must match the ones expected by the closure or /// otherwise this function panics. #[doc(alias = "g_closure_invoke")] pub fn invoke(&self, values: &[&dyn ToValue]) -> R { let values = values .iter() .copied() .map(ToValue::to_value) .collect::>(); R::try_from_closure_return_value(self.invoke_with_values(R::static_type(), &values)) .expect("Invalid return value") } // rustdoc-stripper-ignore-next /// Invokes the closure with the given arguments. /// /// For invalidated closures this returns the "default" value of the return type. /// /// # Panics /// /// The argument types and return value type must match the ones expected by the closure or /// otherwise this function panics. #[doc(alias = "g_closure_invoke")] pub fn invoke_with_values(&self, return_type: Type, values: &[Value]) -> Option { unsafe { self.0.invoke_with_values(return_type, values) } } // rustdoc-stripper-ignore-next /// Invalidates the closure. /// /// Invoking an invalidated closure has no effect. #[doc(alias = "g_closure_invalidate")] pub fn invalidate(&self) { self.0.invalidate(); } } impl From for Closure { #[inline] fn from(c: RustClosure) -> Self { c.0 } } impl AsRef for RustClosure { #[inline] fn as_ref(&self) -> &Closure { &self.0 } } impl AsRef for Closure { #[inline] fn as_ref(&self) -> &Closure { self } } impl Closure { // rustdoc-stripper-ignore-next /// Creates a new closure around a Rust closure. /// /// Note that [`RustClosure`] provides more convenient and non-unsafe API for invoking /// closures. This type mostly exists for FFI interop. /// /// # Panics /// /// Invoking the closure with wrong argument types or returning the wrong return value type /// will panic. /// /// /// # Example /// /// ``` /// use glib::prelude::*; /// /// let closure = glib::Closure::new(|values| { /// let x = values[0].get::().unwrap(); /// Some((x + 1).to_value()) /// }); /// /// // Invoking non-Rust closures is unsafe because of possibly missing /// // argument and return value type checks. /// let res = unsafe { /// closure /// .invoke_with_values(glib::Type::I32, &[1i32.to_value()]) /// .and_then(|v| v.get::().ok()) /// .expect("Invalid return value") /// }; /// /// assert_eq!(res, 2); /// ``` #[doc(alias = "g_closure_new")] pub fn new Option + Send + Sync + 'static>(callback: F) -> Self { unsafe { Self::new_unsafe(callback) } } // rustdoc-stripper-ignore-next /// Creates a new closure around a Rust closure. /// /// Note that [`RustClosure`] provides more convenient and non-unsafe API for invoking /// closures. This type mostly exists for FFI interop. /// /// # Panics /// /// Invoking the closure with wrong argument types or returning the wrong return value type /// will panic. /// /// Invoking the closure from a different thread than this one will panic. #[doc(alias = "g_closure_new")] pub fn new_local Option + 'static>(callback: F) -> Self { let callback = crate::thread_guard::ThreadGuard::new(callback); unsafe { Self::new_unsafe(move |values| (callback.get_ref())(values)) } } // rustdoc-stripper-ignore-next /// Creates a new closure around a Rust closure. /// /// # Safety /// /// The captured variables of the closure must stay valid as long as the return value of this /// constructor does, and it must be valid to call the closure from any thread that is used by /// callers. #[doc(alias = "g_closure_new")] pub unsafe fn new_unsafe Option>(callback: F) -> Self { unsafe extern "C" fn marshal( _closure: *mut gobject_ffi::GClosure, return_value: *mut gobject_ffi::GValue, n_param_values: c_uint, param_values: *const gobject_ffi::GValue, _invocation_hint: *mut c_void, marshal_data: *mut c_void, ) where F: Fn(&[Value]) -> Option, { let values = if n_param_values == 0 { &[] } else { slice::from_raw_parts(param_values as *const _, n_param_values as usize) }; let callback: &F = &*(marshal_data as *mut _); let result = callback(values); if return_value.is_null() { assert!( result.is_none(), "Closure returned a return value but the caller did not expect one" ); } else { let return_value = &mut *(return_value as *mut Value); match result { Some(result) => { assert!( result.type_().is_a(return_value.type_()), "Closure returned a value of type {} but caller expected {}", result.type_(), return_value.type_() ); *return_value = result; } None if return_value.type_() == Type::INVALID => (), None => { panic!( "Closure returned no value but the caller expected a value of type {}", return_value.type_() ); } } } } unsafe extern "C" fn finalize( notify_data: *mut c_void, _closure: *mut gobject_ffi::GClosure, ) where F: Fn(&[Value]) -> Option, { let _callback: Box = Box::from_raw(notify_data as *mut _); // callback is dropped here. } // Due to bitfields we have to do our own calculations here for the size of the GClosure: // - 4: 32 bits in guint bitfields at the beginning // - padding due to alignment needed for the following pointer // - 3 * size_of<*mut c_void>: 3 pointers // We don't store any custom data ourselves in the GClosure let size = u32::max(4, mem::align_of::<*mut c_void>() as u32) + 3 * mem::size_of::<*mut c_void>() as u32; let closure = gobject_ffi::g_closure_new_simple(size, ptr::null_mut()); let callback = Box::new(callback); let ptr: *mut F = Box::into_raw(callback); let ptr: *mut c_void = ptr as *mut _; gobject_ffi::g_closure_set_meta_marshal(closure, ptr, Some(marshal::)); gobject_ffi::g_closure_add_finalize_notifier(closure, ptr, Some(finalize::)); from_glib_none(closure) } // rustdoc-stripper-ignore-next /// Invokes the closure with the given arguments. /// /// For invalidated closures this returns the "default" value of the return type. /// /// # Safety /// /// The argument types and return value type must match the ones expected by the closure or /// otherwise the behaviour is undefined. /// /// Closures created from Rust via e.g. [`Closure::new`] will panic on type mismatches but /// this is not guaranteed for closures created from other languages. #[doc(alias = "g_closure_invoke")] pub unsafe fn invoke_with_values(&self, return_type: Type, values: &[Value]) -> Option { let mut result = if return_type == Type::UNIT { Value::uninitialized() } else { Value::from_type(return_type) }; let result_ptr = if return_type == Type::UNIT { ptr::null_mut() } else { result.to_glib_none_mut().0 }; gobject_ffi::g_closure_invoke( self.to_glib_none().0, result_ptr, values.len() as u32, mut_override(values.as_ptr()) as *mut gobject_ffi::GValue, ptr::null_mut(), ); if return_type == Type::UNIT { None } else { Some(result) } } // rustdoc-stripper-ignore-next /// Invalidates the closure. /// /// Invoking an invalidated closure has no effect. #[doc(alias = "g_closure_invalidate")] pub fn invalidate(&self) { unsafe { gobject_ffi::g_closure_invalidate(self.to_glib_none().0); } } } pub trait IntoClosureReturnValue { fn into_closure_return_value(self) -> Option; } impl IntoClosureReturnValue for () { #[inline] fn into_closure_return_value(self) -> Option { None } } impl> IntoClosureReturnValue for T { #[inline] fn into_closure_return_value(self) -> Option { Some(self.into()) } } pub trait TryFromClosureReturnValue: StaticType + Sized + 'static { fn try_from_closure_return_value(v: Option) -> Result; } impl TryFromClosureReturnValue for () { #[inline] fn try_from_closure_return_value(v: Option) -> Result { match v { None => Ok(()), Some(v) => Err(bool_error!( "Invalid return value: expected (), got {}", v.type_() )), } } } impl crate::value::FromValue<'a> + StaticType + 'static> TryFromClosureReturnValue for T { #[inline] fn try_from_closure_return_value(v: Option) -> Result { v.ok_or_else(|| { bool_error!( "Invalid return value: expected {}, got ()", T::static_type() ) }) .and_then(|v| { v.get_owned::().map_err(|_| { bool_error!( "Invalid return value: expected {}, got {}", T::static_type(), v.type_() ) }) }) } } unsafe impl Send for Closure {} unsafe impl Sync for Closure {} #[cfg(test)] mod tests { use std::sync::{ atomic::{AtomicUsize, Ordering}, Arc, }; use super::*; #[allow(clippy::unnecessary_wraps)] fn closure_fn(values: &[Value]) -> Option { assert_eq!(values.len(), 2); let string_arg = values[0].get::<&str>(); assert_eq!(string_arg, Ok("test")); let int_arg = values[1].get::(); assert_eq!(int_arg, Ok(42)); Some(24.to_value()) } #[test] fn test_closure() { let call_count = Arc::new(AtomicUsize::new(0)); let count = call_count.clone(); let closure = RustClosure::new(move |values| { count.fetch_add(1, Ordering::Relaxed); assert_eq!(values.len(), 2); let string_arg = values[0].get::<&str>(); assert_eq!(string_arg, Ok("test")); let int_arg = values[1].get::(); assert_eq!(int_arg, Ok(42)); None }); closure.invoke::<()>(&[&"test", &42]); assert_eq!(call_count.load(Ordering::Relaxed), 1); closure.invoke::<()>(&[&"test", &42]); assert_eq!(call_count.load(Ordering::Relaxed), 2); closure.invalidate(); closure.invoke::<()>(&[&"test", &42]); assert_eq!(call_count.load(Ordering::Relaxed), 2); let closure = RustClosure::new(closure_fn); let result = closure.invoke::(&[&"test", &42]); assert_eq!(result, 24); closure.invalidate(); let result = closure.invoke::(&[&"test", &42]); assert_eq!(result, 0); } } glib-0.20.9/src/collections/list.rs000064400000000000000000000713321046102023000152650ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{iter::FusedIterator, marker::PhantomData, mem, ptr}; use crate::{ffi, translate::*}; // rustdoc-stripper-ignore-next /// A list of items of type `T`. /// /// Behaves like an `Iterator` but allows modifications. #[repr(transparent)] pub struct List { ptr: Option>, phantom: PhantomData, } #[doc(hidden)] unsafe impl TransparentPtrType for List {} #[doc(hidden)] impl GlibPtrDefault for List { type GlibType = *mut ffi::GList; } unsafe impl Send for List {} unsafe impl Sync for List {} impl List { // rustdoc-stripper-ignore-next /// Create a new `List` around a list. #[inline] pub unsafe fn from_glib_none(list: *const ffi::GList) -> List { // Need to copy the whole list let list = if mem::needs_drop::() { unsafe extern "C" fn copy_item( ptr: ffi::gconstpointer, _user_data: ffi::gpointer, ) -> ffi::gpointer { let mut item = mem::ManuallyDrop::new( (*(&ptr as *const ffi::gconstpointer as *const T)).clone(), ); *(&mut *item as *mut T as *mut *mut T::GlibType) as ffi::gpointer } ffi::g_list_copy_deep(mut_override(list), Some(copy_item::), ptr::null_mut()) } else { ffi::g_list_copy(mut_override(list)) }; List { ptr: ptr::NonNull::new(list), phantom: PhantomData, } } // rustdoc-stripper-ignore-next /// Create a new `List` around a list. #[inline] pub unsafe fn from_glib_container(list: *mut ffi::GList) -> List { // Need to copy all items as we only own the container if mem::needs_drop::() { unsafe extern "C" fn copy_item( ptr: ffi::gpointer, _user_data: ffi::gpointer, ) { let item = (*(&ptr as *const ffi::gpointer as *const T)).clone(); ptr::write(ptr as *mut T, item); } ffi::g_list_foreach(list, Some(copy_item::), ptr::null_mut()); } List { ptr: ptr::NonNull::new(list), phantom: PhantomData, } } // rustdoc-stripper-ignore-next /// Create a new `List` around a list. #[inline] pub unsafe fn from_glib_full(list: *mut ffi::GList) -> List { List { ptr: ptr::NonNull::new(list), phantom: PhantomData, } } // rustdoc-stripper-ignore-next /// Creates a new empty list. #[inline] pub fn new() -> Self { List { ptr: None, phantom: PhantomData, } } // rustdoc-stripper-ignore-next /// Create a non-destructive iterator over the `List`. #[inline] pub fn iter(&self) -> Iter { Iter::new(self) } // rustdoc-stripper-ignore-next /// Create a non-destructive mutable iterator over the `List`. #[inline] pub fn iter_mut(&mut self) -> IterMut { IterMut::new(self) } // rustdoc-stripper-ignore-next /// Check if the list is empty. /// /// This operation is `O(1)`. #[inline] pub fn is_empty(&self) -> bool { self.ptr.is_none() } // rustdoc-stripper-ignore-next /// Returns the length of the list. /// /// This operation is `O(n)`. #[inline] #[doc(alias = "g_list_length")] pub fn len(&self) -> usize { self.iter().count() } // rustdoc-stripper-ignore-next /// Returns a reference to the first item of the list, if any. /// /// This operation is `O(1)`. #[inline] #[doc(alias = "g_list_first")] pub fn front(&self) -> Option<&T> { match self.ptr { None => None, Some(cur) => unsafe { let item = &*(&cur.as_ref().data as *const ffi::gpointer as *const T); Some(item) }, } } // rustdoc-stripper-ignore-next /// Returns a mutable reference to the first item of the list, if any. /// /// This operation is `O(1)`. #[inline] #[doc(alias = "g_list_first")] pub fn front_mut(&mut self) -> Option<&mut T> { match self.ptr { None => None, Some(mut cur) => unsafe { let item = &mut *(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T); Some(item) }, } } // rustdoc-stripper-ignore-next /// Removes the front item from the list, if any. /// /// This operation is `O(1)`. #[inline] pub fn pop_front(&mut self) -> Option { match self.ptr { None => None, Some(mut cur) => unsafe { self.ptr = ptr::NonNull::new(cur.as_ref().next); if let Some(mut next) = self.ptr { next.as_mut().prev = ptr::null_mut(); } let item = ptr::read(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T); ffi::g_list_free_1(cur.as_ptr()); Some(item) }, } } // rustdoc-stripper-ignore-next /// Prepends the new item to the front of the list. /// /// This operation is `O(1)`. #[inline] #[doc(alias = "g_list_prepend")] pub fn push_front(&mut self, item: T) { unsafe { let ptr = self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut()); self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_list_prepend( ptr, *(&mut *mem::ManuallyDrop::new(item) as *mut T as *mut *mut T::GlibType) as ffi::gpointer, ))); } } // rustdoc-stripper-ignore-next /// Returns a reference to the last item of the list, if any. /// /// This operation is `O(n)`. #[inline] #[doc(alias = "g_list_last")] pub fn back(&self) -> Option<&T> { unsafe { let ptr = match self.ptr { None => return None, Some(ptr) => ptr.as_ptr(), }; let last_ptr = ffi::g_list_last(ptr); let item = &*(&(*last_ptr).data as *const ffi::gpointer as *const T); Some(item) } } // rustdoc-stripper-ignore-next /// Returns a mutable reference to the last item of the list, if any. /// /// This operation is `O(n)`. #[inline] #[doc(alias = "g_list_last")] pub fn back_mut(&mut self) -> Option<&mut T> { unsafe { let ptr = match self.ptr { None => return None, Some(ptr) => ptr.as_ptr(), }; let last_ptr = ffi::g_list_last(ptr); let item = &mut *(&mut (*last_ptr).data as *mut ffi::gpointer as *mut T); Some(item) } } // rustdoc-stripper-ignore-next /// Removes the back item from the list, if any. /// /// This operation is `O(n)`. #[inline] pub fn pop_back(&mut self) -> Option { unsafe { let ptr = match self.ptr { None => return None, Some(ptr) => ptr.as_ptr(), }; let last_ptr = ffi::g_list_last(ptr); let item = ptr::read(&mut (*last_ptr).data as *mut ffi::gpointer as *mut T); self.ptr = ptr::NonNull::new(ffi::g_list_delete_link(ptr, last_ptr)); Some(item) } } // rustdoc-stripper-ignore-next /// Appends the new item to the back of the list. /// /// this operation is `O(n)`. #[inline] #[doc(alias = "g_list_append")] pub fn push_back(&mut self, item: T) { unsafe { let ptr = self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut()); self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_list_append( ptr, *(&mut *mem::ManuallyDrop::new(item) as *mut T as *mut *mut T::GlibType) as ffi::gpointer, ))); } } // rustdoc-stripper-ignore-next /// Reverse the list. /// /// This operation is `O(n)`. #[inline] #[doc(alias = "g_list_reverse")] pub fn reverse(&mut self) { unsafe { let ptr = match self.ptr { None => return, Some(ptr) => ptr.as_ptr(), }; self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_list_reverse(ptr))); } } // rustdoc-stripper-ignore-next /// Sorts the list. /// /// This operation is `O(n * log n)`. #[inline] #[doc(alias = "g_list_sort")] pub fn sort(&mut self) where T: Ord, { self.sort_by(|a, b| a.cmp(b)); } // rustdoc-stripper-ignore-next /// Sorts the list. /// /// This operation is `O(n * log n)`. #[inline] #[doc(alias = "g_list_sort")] pub fn sort_by std::cmp::Ordering>(&mut self, mut f: F) { unsafe { let ptr = match self.ptr { None => return, Some(ptr) => ptr.as_ptr(), }; unsafe extern "C" fn func< T: TransparentPtrType, F: FnMut(&T, &T) -> std::cmp::Ordering, >( a: ffi::gconstpointer, b: ffi::gconstpointer, user_data: ffi::gpointer, ) -> i32 { let f = &mut *(user_data as *mut F); let a = &*(&a as *const ffi::gconstpointer as *const T); let b = &*(&b as *const ffi::gconstpointer as *const T); f(a, b).into_glib() } self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_list_sort_with_data( ptr, Some(func::), &mut f as *mut F as ffi::gpointer, ))); } } // rustdoc-stripper-ignore-next /// Removes all items from the list. #[inline] pub fn clear(&mut self) { *self = Self::new(); } // rustdoc-stripper-ignore-next /// Only keeps the item in the list for which `f` returns `true`. #[inline] pub fn retain(&mut self, mut f: impl FnMut(&T) -> bool) { if let Some(head) = self.ptr { unsafe { let mut ptr = head.as_ptr(); while !ptr.is_null() { let item = &*((*ptr).data as *const ffi::gpointer as *const T); let next = (*ptr).next; if !f(item) { ptr::drop_in_place(&mut (*ptr).data as *mut ffi::gpointer as *mut T); self.ptr = ptr::NonNull::new(ffi::g_list_delete_link(head.as_ptr(), ptr)); } ptr = next; } } } } // rustdoc-stripper-ignore-next /// Returns the underlying pointer. #[inline] pub fn as_ptr(&self) -> *const ffi::GList { self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut()) } // rustdoc-stripper-ignore-next /// Returns the underlying pointer. #[inline] pub fn as_mut_ptr(&mut self) -> *mut ffi::GList { self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut()) } // rustdoc-stripper-ignore-next /// Consumes the list and returns the underlying pointer. #[inline] pub fn into_raw(mut self) -> *mut ffi::GList { self.ptr .take() .map(|p| p.as_ptr()) .unwrap_or(ptr::null_mut()) } } impl Default for List { fn default() -> Self { Self::new() } } impl Clone for List { fn clone(&self) -> Self { unsafe { Self::from_glib_none(self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut())) } } } impl Drop for List { #[inline] fn drop(&mut self) { if let Some(ptr) = self.ptr { unsafe { if mem::needs_drop::() { unsafe extern "C" fn drop_item(mut ptr: ffi::gpointer) { ptr::drop_in_place(&mut ptr as *mut ffi::gpointer as *mut T); } ffi::g_list_free_full(ptr.as_ptr(), Some(drop_item::)); } else { ffi::g_list_free(ptr.as_ptr()); } } } } } impl std::iter::FromIterator for List { #[inline] fn from_iter>(iter: I) -> Self { unsafe { let mut iter = iter.into_iter(); let first = match iter.next() { None => return Self::new(), Some(first) => first, }; let list = ffi::g_list_prepend( ptr::null_mut(), *(&mut *mem::ManuallyDrop::new(first) as *mut T as *mut *mut T::GlibType) as ffi::gpointer, ); let mut tail = list; for item in iter { let new_tail = ffi::g_list_alloc(); (*new_tail).data = *(&mut *mem::ManuallyDrop::new(item) as *mut T as *mut *mut T::GlibType) as ffi::gpointer; (*new_tail).prev = tail; (*new_tail).next = ptr::null_mut(); (*tail).next = new_tail; tail = new_tail; } Self::from_glib_full(list) } } } impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a List { type Item = &'a T; type IntoIter = Iter<'a, T>; #[inline] fn into_iter(self) -> Self::IntoIter { self.iter() } } impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a mut List { type Item = &'a mut T; type IntoIter = IterMut<'a, T>; #[inline] fn into_iter(self) -> Self::IntoIter { self.iter_mut() } } impl std::iter::IntoIterator for List { type Item = T; type IntoIter = IntoIter; #[inline] fn into_iter(self) -> Self::IntoIter { IntoIter::new(self) } } impl std::iter::Extend for List { #[inline] fn extend>(&mut self, iter: I) { let list = iter.into_iter().collect::(); if list.is_empty() { return; } match self.ptr.map(|p| p.as_ptr()) { Some(ptr1) => { let ptr2 = list.into_raw(); let _ = unsafe { ffi::g_list_concat(ptr1, ptr2) }; } None => { self.ptr = ptr::NonNull::new(list.into_raw()); } } } } impl FromGlibContainer<::GlibType, *mut ffi::GList> for List { #[inline] unsafe fn from_glib_none_num(ptr: *mut ffi::GList, _num: usize) -> Self { Self::from_glib_none(ptr) } #[inline] unsafe fn from_glib_container_num(ptr: *mut ffi::GList, _num: usize) -> Self { Self::from_glib_container(ptr) } #[inline] unsafe fn from_glib_full_num(ptr: *mut ffi::GList, _num: usize) -> Self { Self::from_glib_full(ptr) } } impl FromGlibContainer<::GlibType, *const ffi::GList> for List { #[inline] unsafe fn from_glib_none_num(ptr: *const ffi::GList, _num: usize) -> Self { Self::from_glib_none(ptr) } unsafe fn from_glib_container_num(_ptr: *const ffi::GList, _num: usize) -> Self { unimplemented!(); } unsafe fn from_glib_full_num(_ptr: *const ffi::GList, _num: usize) -> Self { unimplemented!(); } } impl FromGlibPtrContainer<::GlibType, *mut ffi::GList> for List { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::GList) -> Self { Self::from_glib_none(ptr) } #[inline] unsafe fn from_glib_container(ptr: *mut ffi::GList) -> Self { Self::from_glib_container(ptr) } #[inline] unsafe fn from_glib_full(ptr: *mut ffi::GList) -> Self { Self::from_glib_full(ptr) } } impl FromGlibPtrContainer<::GlibType, *const ffi::GList> for List { #[inline] unsafe fn from_glib_none(ptr: *const ffi::GList) -> Self { Self::from_glib_none(ptr) } unsafe fn from_glib_container(_ptr: *const ffi::GList) -> Self { unimplemented!(); } unsafe fn from_glib_full(_ptr: *const ffi::GList) -> Self { unimplemented!(); } } impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *mut ffi::GList> for List { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GList, Self> { Stash(self.as_ptr() as *mut _, PhantomData) } #[inline] fn to_glib_container(&'a self) -> Stash<'a, *mut ffi::GList, Self> { unsafe { let ptr = ffi::g_malloc(mem::size_of::().checked_mul(self.len() + 1).unwrap()) as *mut ffi::GList; ptr::copy_nonoverlapping(self.as_ptr(), ptr, self.len() + 1); Stash(ptr, PhantomData) } } #[inline] fn to_glib_full(&self) -> *mut ffi::GList { self.clone().into_raw() } } impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *const ffi::GList> for List { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GList, Self> { Stash(self.as_ptr(), PhantomData) } } impl<'a, T: TransparentPtrType + 'a> ToGlibPtrMut<'a, *mut ffi::GList> for List { type Storage = PhantomData<&'a mut Self>; #[inline] fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GList, Self> { StashMut(self.as_mut_ptr(), PhantomData) } } impl IntoGlibPtr<*mut ffi::GList> for List { #[inline] unsafe fn into_glib_ptr(self) -> *mut ffi::GList { self.into_raw() } } // rustdoc-stripper-ignore-next /// A non-destructive iterator over a [`List`]. pub struct Iter<'a, T: TransparentPtrType> { ptr: Option>, phantom: PhantomData<&'a T>, } impl<'a, T: TransparentPtrType> Iter<'a, T> { #[inline] fn new(list: &'a List) -> Iter<'a, T> { debug_assert_eq!( mem::size_of::(), mem::size_of::<::GlibType>() ); Iter { ptr: list.ptr, phantom: PhantomData, } } } impl<'a, T: TransparentPtrType> Iterator for Iter<'a, T> { type Item = &'a T; #[inline] fn next(&mut self) -> Option<&'a T> { match self.ptr { None => None, Some(cur) => unsafe { self.ptr = ptr::NonNull::new(cur.as_ref().next); let item = &*(&cur.as_ref().data as *const ffi::gpointer as *const T); Some(item) }, } } } impl FusedIterator for Iter<'_, T> {} // rustdoc-stripper-ignore-next /// A non-destructive iterator over a [`List`]. pub struct IterMut<'a, T: TransparentPtrType> { ptr: Option>, phantom: PhantomData<&'a mut T>, } impl<'a, T: TransparentPtrType> IterMut<'a, T> { #[inline] fn new(list: &'a mut List) -> IterMut<'a, T> { debug_assert_eq!( mem::size_of::(), mem::size_of::<::GlibType>() ); IterMut { ptr: list.ptr, phantom: PhantomData, } } } impl<'a, T: TransparentPtrType> Iterator for IterMut<'a, T> { type Item = &'a mut T; #[inline] fn next(&mut self) -> Option<&'a mut T> { match self.ptr { None => None, Some(mut cur) => unsafe { self.ptr = ptr::NonNull::new(cur.as_ref().next); let item = &mut *(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T); Some(item) }, } } } impl FusedIterator for IterMut<'_, T> {} // rustdoc-stripper-ignore-next /// A destructive iterator over a [`List`]. pub struct IntoIter { list: List, } impl IntoIter { #[inline] fn new(list: List) -> IntoIter { debug_assert_eq!( mem::size_of::(), mem::size_of::<::GlibType>() ); IntoIter { list } } } impl Iterator for IntoIter { type Item = T; #[inline] fn next(&mut self) -> Option { self.list.pop_front() } } impl FusedIterator for IntoIter {} #[cfg(test)] mod test { use super::*; #[test] // checker-ignore-item fn from_glib_full() { let items = [ crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(), ]; let mut list = unsafe { let mut list = ffi::g_list_append( ptr::null_mut(), ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[0]) as ffi::gpointer, ); list = ffi::g_list_append( list, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[1]) as ffi::gpointer, ); list = ffi::g_list_append( list, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[2]) as ffi::gpointer, ); list = ffi::g_list_append( list, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[3]) as ffi::gpointer, ); List::::from_glib_full(list) }; assert!(!list.is_empty()); let list_items = list.iter().cloned().collect::>(); assert_eq!(&items[..], &list_items); let list_items = list.iter_mut().map(|d| d.clone()).collect::>(); assert_eq!(&items[..], &list_items); let list_items = list.into_iter().collect::>(); assert_eq!(&items[..], &list_items); let list = unsafe { List::::from_glib_full(ptr::null_mut()) }; assert!(list.is_empty()); } #[test] // checker-ignore-item fn from_glib_container() { let items = [ crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(), ]; let mut list = unsafe { let mut list = ffi::g_list_append( ptr::null_mut(), ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer, ); list = ffi::g_list_append( list, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer, ); list = ffi::g_list_append( list, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer, ); list = ffi::g_list_append( list, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer, ); List::::from_glib_container(list) }; assert!(!list.is_empty()); let list_items = list.iter().cloned().collect::>(); assert_eq!(&items[..], &list_items); let list_items = list.iter_mut().map(|d| d.clone()).collect::>(); assert_eq!(&items[..], &list_items); let list_items = list.into_iter().collect::>(); assert_eq!(&items[..], &list_items); let list = unsafe { List::::from_glib_full(ptr::null_mut()) }; assert!(list.is_empty()); } #[test] // checker-ignore-item fn from_glib_none() { let items = [ crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(), ]; let mut list = unsafe { let mut list = ffi::g_list_append( ptr::null_mut(), ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer, ); list = ffi::g_list_append( list, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer, ); list = ffi::g_list_append( list, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer, ); list = ffi::g_list_append( list, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer, ); let res = List::::from_glib_none(list); ffi::g_list_free(list); res }; assert!(!list.is_empty()); let list_items = list.iter().cloned().collect::>(); assert_eq!(&items[..], &list_items); let list_items = list.iter_mut().map(|d| d.clone()).collect::>(); assert_eq!(&items[..], &list_items); let list_items = list.into_iter().collect::>(); assert_eq!(&items[..], &list_items); let list = unsafe { List::::from_glib_full(ptr::null_mut()) }; assert!(list.is_empty()); } #[test] // checker-ignore-item fn safe_api() { let items = [ crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(), ]; let mut list = items[1..3].iter().cloned().collect::>(); assert_eq!(list.len(), 2); list.push_front(items[0].clone()); assert_eq!(list.len(), 3); list.push_back(items[3].clone()); assert_eq!(list.len(), 4); let list_items = list.iter().cloned().collect::>(); assert_eq!(&items[..], &list_items); assert_eq!(list.front(), Some(&items[0])); assert_eq!(list.back(), Some(&items[3])); assert_eq!(list.pop_front().as_ref(), Some(&items[0])); assert_eq!(list.len(), 3); list.reverse(); let mut list_items = list.iter().cloned().collect::>(); list_items.reverse(); assert_eq!(&items[1..], &list_items); let list2 = list.clone(); let mut list_items = list2.iter().cloned().collect::>(); list_items.reverse(); assert_eq!(&items[1..], &list_items); } #[test] fn extend() { let mut list = List::::new(); list.push_back(crate::DateTime::from_unix_utc(11).unwrap()); list.push_back(crate::DateTime::from_unix_utc(12).unwrap()); list.push_back(crate::DateTime::from_unix_utc(13).unwrap()); list.extend(vec![ crate::DateTime::from_unix_utc(21).unwrap(), crate::DateTime::from_unix_utc(22).unwrap(), ]); assert_eq!( list.iter().map(|dt| dt.to_unix()).collect::>(), vec![11, 12, 13, 21, 22] ); } #[test] fn extend_empty_with_empty() { let mut list1 = List::::new(); list1.extend(vec![]); assert!(list1.is_empty()); } #[test] fn extend_with_empty() { let mut list = List::::new(); list.push_back(crate::DateTime::from_unix_utc(11).unwrap()); list.push_back(crate::DateTime::from_unix_utc(12).unwrap()); list.push_back(crate::DateTime::from_unix_utc(13).unwrap()); list.extend(vec![]); assert_eq!( list.iter().map(|dt| dt.to_unix()).collect::>(), vec![11, 12, 13] ); } #[test] fn extend_empty() { let mut list = List::::new(); list.extend(vec![ crate::DateTime::from_unix_utc(21).unwrap(), crate::DateTime::from_unix_utc(22).unwrap(), ]); assert_eq!( list.iter().map(|dt| dt.to_unix()).collect::>(), vec![21, 22] ); } } glib-0.20.9/src/collections/mod.rs000064400000000000000000000004231046102023000150620ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. pub mod ptr_slice; pub use ptr_slice::PtrSlice; pub mod slice; pub use slice::Slice; pub mod list; pub use list::List; pub mod slist; pub use slist::SList; pub mod strv; pub use strv::StrV; glib-0.20.9/src/collections/ptr_slice.rs000064400000000000000000001212521046102023000162730ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{fmt, marker::PhantomData, mem, ptr}; use crate::{ffi, translate::*}; // rustdoc-stripper-ignore-next /// Minimum size of the `PtrSlice` allocation. const MIN_SIZE: usize = 16; // rustdoc-stripper-ignore-next /// Slice of elements of type `T` allocated by the GLib allocator. /// /// The underlying memory is always `NULL`-terminated. [`Slice`](crate::collections::slice::Slice) /// can be used for a non-`NULL`-terminated slice. /// /// This can be used like a `&[T]`, `&mut [T]` and `Vec`. pub struct PtrSlice { ptr: ptr::NonNull<::GlibType>, // rustdoc-stripper-ignore-next /// Length without the `NULL`-terminator. len: usize, // rustdoc-stripper-ignore-next /// Capacity **with** the `NULL`-terminator, i.e. the actual allocation size. capacity: usize, } impl fmt::Debug for PtrSlice { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.as_slice().fmt(f) } } unsafe impl Send for PtrSlice {} unsafe impl Sync for PtrSlice {} impl PartialEq for PtrSlice { #[inline] fn eq(&self, other: &Self) -> bool { self.as_slice() == other.as_slice() } } impl Eq for PtrSlice {} impl PartialOrd for PtrSlice { #[inline] fn partial_cmp(&self, other: &Self) -> Option { self.as_slice().partial_cmp(other.as_slice()) } } impl Ord for PtrSlice { #[inline] fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.as_slice().cmp(other.as_slice()) } } impl std::hash::Hash for PtrSlice { #[inline] fn hash(&self, state: &mut H) { self.as_slice().hash(state) } } impl PartialEq<[T]> for PtrSlice { #[inline] fn eq(&self, other: &[T]) -> bool { self.as_slice() == other } } impl PartialEq> for [T] { #[inline] fn eq(&self, other: &PtrSlice) -> bool { self == other.as_slice() } } impl Drop for PtrSlice { #[inline] fn drop(&mut self) { unsafe { if mem::needs_drop::() { for i in 0..self.len { ptr::drop_in_place::(self.ptr.as_ptr().add(i) as *mut T); } } if self.capacity != 0 { ffi::g_free(self.ptr.as_ptr() as ffi::gpointer); } } } } impl AsRef<[T]> for PtrSlice { #[inline] fn as_ref(&self) -> &[T] { self.as_slice() } } impl AsMut<[T]> for PtrSlice { #[inline] fn as_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } impl std::borrow::Borrow<[T]> for PtrSlice { #[inline] fn borrow(&self) -> &[T] { self.as_slice() } } impl std::borrow::BorrowMut<[T]> for PtrSlice { #[inline] fn borrow_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } impl std::ops::Deref for PtrSlice { type Target = [T]; #[inline] fn deref(&self) -> &[T] { self.as_slice() } } impl std::ops::DerefMut for PtrSlice { #[inline] fn deref_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } impl Default for PtrSlice { #[inline] fn default() -> Self { Self::new() } } impl std::iter::Extend for PtrSlice { #[inline] fn extend>(&mut self, iter: I) { let iter = iter.into_iter(); self.reserve(iter.size_hint().0); for item in iter { self.push(item); } } } impl<'a, T: TransparentPtrType + 'a> std::iter::Extend<&'a T> for PtrSlice { #[inline] fn extend>(&mut self, iter: I) { let iter = iter.into_iter(); self.reserve(iter.size_hint().0); for item in iter { self.push(item.clone()); } } } impl std::iter::FromIterator for PtrSlice { #[inline] fn from_iter>(iter: I) -> Self { let iter = iter.into_iter(); let mut s = Self::with_capacity(iter.size_hint().0); for item in iter { s.push(item); } s } } impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a PtrSlice { type Item = &'a T; type IntoIter = std::slice::Iter<'a, T>; #[inline] fn into_iter(self) -> Self::IntoIter { self.as_slice().iter() } } impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a mut PtrSlice { type Item = &'a mut T; type IntoIter = std::slice::IterMut<'a, T>; #[inline] fn into_iter(self) -> Self::IntoIter { self.as_mut_slice().iter_mut() } } impl std::iter::IntoIterator for PtrSlice { type Item = T; type IntoIter = IntoIter; #[inline] fn into_iter(self) -> Self::IntoIter { IntoIter::new(self) } } pub struct IntoIter { ptr: ptr::NonNull<::GlibType>, idx: ptr::NonNull<::GlibType>, len: usize, empty: bool, } impl IntoIter { #[inline] fn new(slice: PtrSlice) -> Self { let slice = mem::ManuallyDrop::new(slice); IntoIter { ptr: slice.ptr, idx: slice.ptr, len: slice.len, empty: slice.capacity == 0, } } // rustdoc-stripper-ignore-next /// Returns the remaining items as slice. #[inline] pub fn as_slice(&self) -> &[T] { unsafe { if self.len == 0 { &[] } else { std::slice::from_raw_parts(self.idx.as_ptr() as *mut T, self.len) } } } // rustdoc-stripper-ignore-next /// Returns the remaining items as mutable slice. #[inline] pub fn as_mut_slice(&mut self) -> &mut [T] { unsafe { if self.len == 0 { &mut [] } else { std::slice::from_raw_parts_mut(self.idx.as_ptr() as *mut T, self.len) } } } } impl Drop for IntoIter { #[inline] fn drop(&mut self) { unsafe { if mem::needs_drop::() { for i in 0..self.len { ptr::drop_in_place::(self.idx.as_ptr().add(i) as *mut T); } } if !self.empty { ffi::g_free(self.ptr.as_ptr() as ffi::gpointer); } } } } impl Iterator for IntoIter { type Item = T; #[inline] fn next(&mut self) -> Option { if self.len == 0 { return None; } unsafe { let p = self.idx.as_ptr(); self.len -= 1; self.idx = ptr::NonNull::new_unchecked(p.add(1)); Some(ptr::read(p as *mut T)) } } #[inline] fn size_hint(&self) -> (usize, Option) { (self.len, Some(self.len)) } #[inline] fn count(self) -> usize { self.len } #[inline] fn last(mut self) -> Option { if self.len == 0 { None } else { self.len -= 1; Some(unsafe { ptr::read(self.idx.as_ptr().add(self.len) as *mut T) }) } } } impl DoubleEndedIterator for IntoIter { #[inline] fn next_back(&mut self) -> Option { if self.len == 0 { None } else { self.len -= 1; Some(unsafe { ptr::read(self.idx.as_ptr().add(self.len) as *mut T) }) } } } impl ExactSizeIterator for IntoIter {} impl std::iter::FusedIterator for IntoIter {} impl From> for Vec { #[inline] fn from(mut value: PtrSlice) -> Self { unsafe { let mut s = Vec::with_capacity(value.len); ptr::copy_nonoverlapping(value.ptr.as_ptr() as *const T, s.as_mut_ptr(), value.len); s.set_len(value.len); value.len = 0; s } } } impl From> for PtrSlice { #[inline] fn from(mut value: Vec) -> Self { unsafe { let mut s = Self::with_capacity(value.len()); ptr::copy_nonoverlapping(value.as_ptr(), s.ptr.as_ptr() as *mut T, value.len()); s.len = value.len(); value.set_len(0); ptr::write( s.ptr.as_ptr().add(s.len), Ptr::from(ptr::null_mut::<::GlibType>()), ); s } } } impl From<[T; N]> for PtrSlice { #[inline] fn from(value: [T; N]) -> Self { unsafe { let value = mem::ManuallyDrop::new(value); let len = value.len(); let mut s = Self::with_capacity(len); ptr::copy_nonoverlapping(value.as_ptr(), s.ptr.as_ptr() as *mut T, len); s.len = len; ptr::write( s.ptr.as_ptr().add(len), Ptr::from(ptr::null_mut::<::GlibType>()), ); s } } } impl<'a, T: TransparentPtrType> From<&'a [T]> for PtrSlice { #[inline] fn from(value: &'a [T]) -> Self { unsafe { let mut s = Self::with_capacity(value.len()); for (i, item) in value.iter().enumerate() { ptr::write(s.ptr.as_ptr().add(i) as *mut T, item.clone()); } s.len = value.len(); ptr::write( s.ptr.as_ptr().add(s.len), Ptr::from(ptr::null_mut::<::GlibType>()), ); s } } } impl<'a, T: TransparentPtrType> From<&'a [&'a T]> for PtrSlice { #[inline] fn from(value: &'a [&'a T]) -> Self { unsafe { let mut s = Self::with_capacity(value.len()); for (i, item) in value.iter().enumerate() { ptr::write(s.ptr.as_ptr().add(i) as *mut T, (*item).clone()); } s.len = value.len(); ptr::write( s.ptr.as_ptr().add(s.len), Ptr::from(ptr::null_mut::<::GlibType>()), ); s } } } impl Clone for PtrSlice { #[inline] fn clone(&self) -> Self { Self::from(self.as_slice()) } } impl PtrSlice { // rustdoc-stripper-ignore-next /// Borrows a C array. #[inline] pub unsafe fn from_glib_borrow<'a>(ptr: *const ::GlibType) -> &'a [T] { let mut len = 0; if !ptr.is_null() { while !(*ptr.add(len)).is_null() { len += 1; } } Self::from_glib_borrow_num(ptr, len) } // rustdoc-stripper-ignore-next /// Borrows a C array. #[inline] pub unsafe fn from_glib_borrow_num<'a>( ptr: *const ::GlibType, len: usize, ) -> &'a [T] { debug_assert_eq!( mem::size_of::(), mem::size_of::<::GlibType>() ); debug_assert!(!ptr.is_null() || len == 0); if len == 0 { &[] } else { std::slice::from_raw_parts(ptr as *const T, len) } } // rustdoc-stripper-ignore-next /// Create a new `PtrSlice` around a C array. #[inline] pub unsafe fn from_glib_none_num( ptr: *const ::GlibType, len: usize, _null_terminated: bool, ) -> Self { debug_assert_eq!( mem::size_of::(), mem::size_of::<::GlibType>() ); debug_assert!(!ptr.is_null() || len == 0); if len == 0 { PtrSlice::default() } else { // Need to fully copy the array here. let s = Self::from_glib_borrow_num(ptr, len); Self::from(s) } } // rustdoc-stripper-ignore-next /// Create a new `PtrSlice` around a C array. #[inline] pub unsafe fn from_glib_container_num( ptr: *mut ::GlibType, len: usize, null_terminated: bool, ) -> Self { debug_assert_eq!( mem::size_of::(), mem::size_of::<::GlibType>() ); debug_assert!(!ptr.is_null() || len == 0); if len == 0 { ffi::g_free(ptr as ffi::gpointer); PtrSlice::default() } else { // Need to clone every item because we don't own it here for i in 0..len { let p = ptr.add(i) as *mut T; let clone: T = (*p).clone(); ptr::write(p, clone); } // And now it can be handled exactly the same as `from_glib_full_num()`. Self::from_glib_full_num(ptr, len, null_terminated) } } // rustdoc-stripper-ignore-next /// Create a new `PtrSlice` around a C array. #[inline] pub unsafe fn from_glib_full_num( ptr: *mut ::GlibType, len: usize, null_terminated: bool, ) -> Self { debug_assert_eq!( mem::size_of::(), mem::size_of::<::GlibType>() ); debug_assert!(!ptr.is_null() || len == 0); if len == 0 { ffi::g_free(ptr as ffi::gpointer); PtrSlice::default() } else { if null_terminated { return PtrSlice { ptr: ptr::NonNull::new_unchecked(ptr), len, capacity: len + 1, }; } // Need to re-allocate here for adding the NULL-terminator let capacity = len + 1; assert_ne!(capacity, 0); let ptr = ffi::g_realloc( ptr as *mut _, mem::size_of::().checked_mul(capacity).unwrap(), ) as *mut ::GlibType; ptr::write( ptr.add(len), Ptr::from(ptr::null_mut::<::GlibType>()), ); PtrSlice { ptr: ptr::NonNull::new_unchecked(ptr), len, capacity, } } } // rustdoc-stripper-ignore-next /// Create a new `PtrSlice` around a `NULL`-terminated C array. #[inline] pub unsafe fn from_glib_none(ptr: *const ::GlibType) -> Self { let mut len = 0; if !ptr.is_null() { while !(*ptr.add(len)).is_null() { len += 1; } } PtrSlice::from_glib_none_num(ptr, len, true) } // rustdoc-stripper-ignore-next /// Create a new `PtrSlice` around a `NULL`-terminated C array. #[inline] pub unsafe fn from_glib_container(ptr: *mut ::GlibType) -> Self { let mut len = 0; if !ptr.is_null() { while !(*ptr.add(len)).is_null() { len += 1; } } PtrSlice::from_glib_container_num(ptr, len, true) } // rustdoc-stripper-ignore-next /// Create a new `PtrSlice` around a `NULL`-terminated C array. #[inline] pub unsafe fn from_glib_full(ptr: *mut ::GlibType) -> Self { let mut len = 0; if !ptr.is_null() { while !(*ptr.add(len)).is_null() { len += 1; } } PtrSlice::from_glib_full_num(ptr, len, true) } // rustdoc-stripper-ignore-next /// Creates a new empty slice. #[inline] pub fn new() -> Self { debug_assert_eq!( mem::size_of::(), mem::size_of::<::GlibType>() ); PtrSlice { ptr: ptr::NonNull::dangling(), len: 0, capacity: 0, } } // rustdoc-stripper-ignore-next /// Creates a new empty slice with the given capacity. #[inline] pub fn with_capacity(capacity: usize) -> Self { let mut s = Self::new(); s.reserve(capacity); s } // rustdoc-stripper-ignore-next /// Returns the underlying pointer. /// /// This is guaranteed to be `NULL`-terminated. #[inline] pub fn as_ptr(&self) -> *const ::GlibType { if self.len == 0 { static EMPTY: [usize; 1] = [0]; EMPTY.as_ptr() as *const _ } else { self.ptr.as_ptr() } } // rustdoc-stripper-ignore-next /// Returns the underlying pointer. /// /// This is guaranteed to be `NULL`-terminated. #[inline] pub fn as_mut_ptr(&mut self) -> *mut ::GlibType { if self.len == 0 { static EMPTY: [usize; 1] = [0]; EMPTY.as_ptr() as *mut _ } else { self.ptr.as_ptr() } } // rustdoc-stripper-ignore-next /// Consumes the slice and returns the underlying pointer. /// /// This is guaranteed to be `NULL`-terminated. #[inline] pub fn into_raw(mut self) -> *mut ::GlibType { if self.len == 0 { ptr::null_mut() } else { self.len = 0; self.capacity = 0; self.ptr.as_ptr() } } // rustdoc-stripper-ignore-next /// Gets the length of the slice. #[inline] pub fn len(&self) -> usize { self.len } // rustdoc-stripper-ignore-next /// Returns `true` if the slice is empty. #[inline] pub fn is_empty(&self) -> bool { self.len == 0 } // rustdoc-stripper-ignore-next /// Returns the capacity of the slice. /// /// This includes the space that is reserved for the `NULL`-terminator. #[inline] pub fn capacity(&self) -> usize { self.capacity } // rustdoc-stripper-ignore-next /// Sets the length of the slice to `len`. /// /// # SAFETY /// /// There must be at least `len` valid items and a `NULL`-terminator after the last item. pub unsafe fn set_len(&mut self, len: usize) { self.len = len; } // rustdoc-stripper-ignore-next /// Reserves at least this much additional capacity. #[allow(clippy::int_plus_one)] pub fn reserve(&mut self, additional: usize) { // Nothing new to reserve as there's still enough space if self.len + additional + 1 <= self.capacity { return; } let new_capacity = usize::next_power_of_two(std::cmp::max(self.len + additional, MIN_SIZE) + 1); assert_ne!(new_capacity, 0); assert!(new_capacity > self.capacity); unsafe { let ptr = if self.capacity == 0 { ptr::null_mut() } else { self.ptr.as_ptr() as *mut _ }; let new_ptr = ffi::g_realloc(ptr, mem::size_of::().checked_mul(new_capacity).unwrap()) as *mut ::GlibType; if self.capacity == 0 { ptr::write( new_ptr, Ptr::from(ptr::null_mut::<::GlibType>()), ); } self.ptr = ptr::NonNull::new_unchecked(new_ptr); self.capacity = new_capacity; } } // rustdoc-stripper-ignore-next /// Borrows this slice as a `&[T]`. #[inline] pub fn as_slice(&self) -> &[T] { unsafe { if self.len == 0 { &[] } else { std::slice::from_raw_parts(self.ptr.as_ptr() as *const T, self.len) } } } // rustdoc-stripper-ignore-next /// Borrows this slice as a `&mut [T]`. #[inline] pub fn as_mut_slice(&mut self) -> &mut [T] { unsafe { if self.len == 0 { &mut [] } else { std::slice::from_raw_parts_mut(self.ptr.as_ptr() as *mut T, self.len) } } } // rustdoc-stripper-ignore-next /// Removes all items from the slice. #[inline] pub fn clear(&mut self) { unsafe { if mem::needs_drop::() { for i in 0..self.len { ptr::drop_in_place::(self.ptr.as_ptr().add(i) as *mut T); } } self.len = 0; } } // rustdoc-stripper-ignore-next /// Clones and appends all elements in `slice` to the slice. #[inline] pub fn extend_from_slice(&mut self, other: &[T]) { // Nothing new to reserve as there's still enough space if self.len + other.len() + 1 > self.capacity { self.reserve(other.len()); } unsafe { for item in other { ptr::write(self.ptr.as_ptr().add(self.len) as *mut T, item.clone()); self.len += 1; } ptr::write( self.ptr.as_ptr().add(self.len), Ptr::from(ptr::null_mut::<::GlibType>()), ); } } // rustdoc-stripper-ignore-next /// Inserts `item` at position `index` of the slice, shifting all elements after it to the /// right. #[inline] pub fn insert(&mut self, index: usize, item: T) { assert!(index <= self.len); // Nothing new to reserve as there's still enough space if self.len + 1 + 1 > self.capacity { self.reserve(1); } unsafe { if index == self.len { ptr::write(self.ptr.as_ptr().add(self.len) as *mut T, item); } else { let p = self.ptr.as_ptr().add(index); ptr::copy(p, p.add(1), self.len - index); ptr::write(self.ptr.as_ptr().add(index) as *mut T, item); } self.len += 1; ptr::write( self.ptr.as_ptr().add(self.len), Ptr::from(ptr::null_mut::<::GlibType>()), ); } } // rustdoc-stripper-ignore-next /// Pushes `item` to the end of the slice. #[inline] pub fn push(&mut self, item: T) { // Nothing new to reserve as there's still enough space if self.len + 1 + 1 > self.capacity { self.reserve(1); } unsafe { ptr::write(self.ptr.as_ptr().add(self.len) as *mut T, item); self.len += 1; ptr::write( self.ptr.as_ptr().add(self.len), Ptr::from(ptr::null_mut::<::GlibType>()), ); } } // rustdoc-stripper-ignore-next /// Removes item from position `index` of the slice, shifting all elements after it to the /// left. #[inline] pub fn remove(&mut self, index: usize) -> T { assert!(index < self.len); unsafe { let p = self.ptr.as_ptr().add(index); let item = ptr::read(p as *mut T); ptr::copy(p.add(1), p, self.len - index - 1); self.len -= 1; ptr::write( self.ptr.as_ptr().add(self.len), Ptr::from(ptr::null_mut::<::GlibType>()), ); item } } // rustdoc-stripper-ignore-next /// Removes the last item of the slice and returns it. #[inline] pub fn pop(&mut self) -> Option { if self.len == 0 { return None; } unsafe { self.len -= 1; let p = self.ptr.as_ptr().add(self.len); let item = ptr::read(p as *mut T); ptr::write( self.ptr.as_ptr().add(self.len), Ptr::from(ptr::null_mut::<::GlibType>()), ); Some(item) } } // rustdoc-stripper-ignore-next /// Shortens the slice by keeping the last `len` items. /// /// If there are fewer than `len` items then this has no effect. #[inline] pub fn truncate(&mut self, len: usize) { if self.len <= len { return; } unsafe { while self.len > len { self.len -= 1; let p = self.ptr.as_ptr().add(self.len); ptr::drop_in_place::(p as *mut T); ptr::write( p, Ptr::from(ptr::null_mut::<::GlibType>()), ); } } } } impl FromGlibContainer<::GlibType, *mut ::GlibType> for PtrSlice { #[inline] unsafe fn from_glib_none_num(ptr: *mut ::GlibType, num: usize) -> Self { Self::from_glib_none_num(ptr, num, false) } #[inline] unsafe fn from_glib_container_num( ptr: *mut ::GlibType, num: usize, ) -> Self { Self::from_glib_container_num(ptr, num, false) } #[inline] unsafe fn from_glib_full_num(ptr: *mut ::GlibType, num: usize) -> Self { Self::from_glib_full_num(ptr, num, false) } } impl FromGlibContainer<::GlibType, *const ::GlibType> for PtrSlice { unsafe fn from_glib_none_num(ptr: *const ::GlibType, num: usize) -> Self { Self::from_glib_none_num(ptr, num, false) } unsafe fn from_glib_container_num( _ptr: *const ::GlibType, _num: usize, ) -> Self { unimplemented!(); } unsafe fn from_glib_full_num( _ptr: *const ::GlibType, _num: usize, ) -> Self { unimplemented!(); } } impl FromGlibPtrContainer<::GlibType, *mut ::GlibType> for PtrSlice { #[inline] unsafe fn from_glib_none(ptr: *mut ::GlibType) -> Self { Self::from_glib_none(ptr) } #[inline] unsafe fn from_glib_container(ptr: *mut ::GlibType) -> Self { Self::from_glib_container(ptr) } #[inline] unsafe fn from_glib_full(ptr: *mut ::GlibType) -> Self { Self::from_glib_full(ptr) } } impl FromGlibPtrContainer<::GlibType, *const ::GlibType> for PtrSlice { #[inline] unsafe fn from_glib_none(ptr: *const ::GlibType) -> Self { Self::from_glib_none(ptr) } unsafe fn from_glib_container(_ptr: *const ::GlibType) -> Self { unimplemented!(); } unsafe fn from_glib_full(_ptr: *const ::GlibType) -> Self { unimplemented!(); } } impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *mut ::GlibType> for PtrSlice { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut ::GlibType, Self> { Stash(self.as_ptr() as *mut _, PhantomData) } #[inline] fn to_glib_container(&'a self) -> Stash<'a, *mut ::GlibType, Self> { unsafe { let ptr = ffi::g_malloc(mem::size_of::().checked_mul(self.len() + 1).unwrap()) as *mut ::GlibType; ptr::copy_nonoverlapping(self.as_ptr(), ptr, self.len() + 1); Stash(ptr, PhantomData) } } #[inline] fn to_glib_full(&self) -> *mut ::GlibType { self.clone().into_raw() } } impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *const ::GlibType> for PtrSlice { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const ::GlibType, Self> { Stash(self.as_ptr(), PhantomData) } } impl<'a, T: TransparentPtrType + 'a> ToGlibPtrMut<'a, *mut ::GlibType> for PtrSlice { type Storage = PhantomData<&'a mut Self>; #[inline] fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ::GlibType, Self> { StashMut(self.as_mut_ptr(), PhantomData) } } impl IntoGlibPtr<*mut ::GlibType> for PtrSlice { #[inline] unsafe fn into_glib_ptr(self) -> *mut ::GlibType { self.into_raw() } } impl From> for PtrSlice { fn from(value: super::Slice) -> Self { let len = value.len(); let capacity = value.capacity(); unsafe { let ptr = value.into_raw(); let mut s = PtrSlice:: { ptr: ptr::NonNull::new_unchecked(ptr), len, capacity, }; // Reserve space for the `NULL`-terminator if needed if len == capacity { s.reserve(0); } ptr::write( s.ptr.as_ptr().add(s.len()), Ptr::from(ptr::null_mut::<::GlibType>()), ); s } } } // rustdoc-stripper-ignore-next /// A trait to accept both `&[T]` or `PtrSlice` as an argument. pub trait IntoPtrSlice { // rustdoc-stripper-ignore-next /// Runs the given closure with a `NULL`-terminated array. fn run_with_ptr_slice::GlibType]) -> R>(self, f: F) -> R; } impl IntoPtrSlice for PtrSlice { #[inline] fn run_with_ptr_slice::GlibType]) -> R>(self, f: F) -> R { <&Self>::run_with_ptr_slice(&self, f) } } impl IntoPtrSlice for &'_ PtrSlice { #[inline] fn run_with_ptr_slice::GlibType]) -> R>(self, f: F) -> R { f(unsafe { std::slice::from_raw_parts(self.as_ptr() as *mut _, self.len() + 1) }) } } // rustdoc-stripper-ignore-next /// Maximum number of pointers to stack-allocate before falling back to a heap allocation. const MAX_STACK_ALLOCATION: usize = 16; impl IntoPtrSlice for Vec { #[inline] fn run_with_ptr_slice::GlibType]) -> R>(self, f: F) -> R { if self.len() < MAX_STACK_ALLOCATION { unsafe { let mut s = mem::MaybeUninit::< [::GlibType; MAX_STACK_ALLOCATION], >::uninit(); let ptr = s.as_mut_ptr() as *mut ::GlibType; ptr::copy_nonoverlapping( self.as_ptr() as *mut ::GlibType, ptr, self.len(), ); ptr::write( ptr.add(self.len()), Ptr::from(ptr::null_mut::<::GlibType>()), ); f(std::slice::from_raw_parts(ptr, self.len() + 1)) } } else { PtrSlice::::from(self).run_with_ptr_slice(f) } } } impl IntoPtrSlice for [T; N] { #[inline] fn run_with_ptr_slice::GlibType]) -> R>(self, f: F) -> R { if self.len() < MAX_STACK_ALLOCATION { unsafe { let mut s = mem::MaybeUninit::< [::GlibType; MAX_STACK_ALLOCATION], >::uninit(); let ptr = s.as_mut_ptr() as *mut ::GlibType; ptr::copy_nonoverlapping( self.as_ptr() as *mut ::GlibType, ptr, self.len(), ); ptr::write( ptr.add(self.len()), Ptr::from(ptr::null_mut::<::GlibType>()), ); f(std::slice::from_raw_parts(ptr, self.len() + 1)) } } else { PtrSlice::::from(self).run_with_ptr_slice(f) } } } impl IntoPtrSlice for &'_ [T] { #[inline] fn run_with_ptr_slice::GlibType]) -> R>(self, f: F) -> R { if self.len() < MAX_STACK_ALLOCATION { unsafe { let mut s = mem::MaybeUninit::< [::GlibType; MAX_STACK_ALLOCATION], >::uninit(); let ptr = s.as_mut_ptr() as *mut ::GlibType; ptr::copy_nonoverlapping( self.as_ptr() as *mut ::GlibType, ptr, self.len(), ); ptr::write( ptr.add(self.len()), Ptr::from(ptr::null_mut::<::GlibType>()), ); f(std::slice::from_raw_parts(ptr, self.len() + 1)) } } else { PtrSlice::::from(self).run_with_ptr_slice(f) } } } #[cfg(test)] mod test { use super::*; #[test] fn test_from_glib_full() { let items = [ crate::Error::new(crate::FileError::Failed, "Failed 1"), crate::Error::new(crate::FileError::Noent, "Failed 2"), crate::Error::new(crate::FileError::Io, "Failed 3"), crate::Error::new(crate::FileError::Perm, "Failed 4"), ]; let slice = unsafe { let ptr = ffi::g_malloc(mem::size_of::() * 4) as *mut *mut ffi::GError; ptr::write(ptr.add(0), items[0].to_glib_full()); ptr::write(ptr.add(1), items[1].to_glib_full()); ptr::write(ptr.add(2), items[2].to_glib_full()); ptr::write(ptr.add(3), items[3].to_glib_full()); PtrSlice::::from_glib_full_num(ptr, 4, false) }; for (a, b) in Iterator::zip(items.iter(), slice.iter()) { assert_eq!(a.message(), b.message()); assert_eq!( a.kind::().unwrap(), b.kind::().unwrap() ); } } #[test] fn test_from_glib_none() { let items = [ crate::Error::new(crate::FileError::Failed, "Failed 1"), crate::Error::new(crate::FileError::Noent, "Failed 2"), crate::Error::new(crate::FileError::Io, "Failed 3"), crate::Error::new(crate::FileError::Perm, "Failed 4"), ]; let slice = unsafe { PtrSlice::::from_glib_none_num( items.as_ptr() as *const *mut ffi::GError, 4, false, ) }; for (a, b) in Iterator::zip(items.iter(), slice.iter()) { assert_eq!(a.message(), b.message()); assert_eq!( a.kind::().unwrap(), b.kind::().unwrap() ); } } #[test] fn test_safe_api() { let items = [ crate::Error::new(crate::FileError::Failed, "Failed 1"), crate::Error::new(crate::FileError::Noent, "Failed 2"), crate::Error::new(crate::FileError::Io, "Failed 3"), ]; let mut slice = PtrSlice::from(&items[..]); assert_eq!(slice.len(), 3); slice.push(crate::Error::new(crate::FileError::Perm, "Failed 4")); assert_eq!(slice.len(), 4); for (a, b) in Iterator::zip(items.iter(), slice.iter()) { assert_eq!(a.message(), b.message()); assert_eq!( a.kind::().unwrap(), b.kind::().unwrap() ); } assert_eq!(slice[3].message(), "Failed 4"); let vec = Vec::from(slice); assert_eq!(vec.len(), 4); for (a, b) in Iterator::zip(items.iter(), vec.iter()) { assert_eq!(a.message(), b.message()); assert_eq!( a.kind::().unwrap(), b.kind::().unwrap() ); } assert_eq!(vec[3].message(), "Failed 4"); let mut slice = PtrSlice::from(vec); assert_eq!(slice.len(), 4); let e = slice.pop().unwrap(); assert_eq!(e.message(), "Failed 4"); assert_eq!(slice.len(), 3); slice.insert(2, e); assert_eq!(slice.len(), 4); assert_eq!(slice[0].message(), "Failed 1"); assert_eq!(slice[1].message(), "Failed 2"); assert_eq!(slice[2].message(), "Failed 4"); assert_eq!(slice[3].message(), "Failed 3"); let e = slice.remove(2); assert_eq!(e.message(), "Failed 4"); assert_eq!(slice.len(), 3); slice.push(e); assert_eq!(slice.len(), 4); let slice2 = crate::Slice::from(slice.clone()); for (a, b) in Iterator::zip(items.iter(), slice.into_iter()) { assert_eq!(a.message(), b.message()); assert_eq!( a.kind::().unwrap(), b.kind::().unwrap() ); } let slice3 = crate::PtrSlice::from(slice2.clone()); for (a, b) in Iterator::zip(items.iter(), slice2.into_iter()) { assert_eq!(a.message(), b.message()); assert_eq!( a.kind::().unwrap(), b.kind::().unwrap() ); } for (a, b) in Iterator::zip(items.iter(), slice3.into_iter()) { assert_eq!(a.message(), b.message()); assert_eq!( a.kind::().unwrap(), b.kind::().unwrap() ); } } #[test] fn test_into_ptrslice() { let items = [ crate::Error::new(crate::FileError::Failed, "Failed 1"), crate::Error::new(crate::FileError::Noent, "Failed 2"), crate::Error::new(crate::FileError::Io, "Failed 3"), crate::Error::new(crate::FileError::Perm, "Failed 4"), ]; items[..].run_with_ptr_slice(|s| unsafe { assert!(s[4].is_null()); assert_eq!(s.len(), items.len() + 1); let s = std::slice::from_raw_parts(s.as_ptr() as *const crate::Error, items.len()); assert_eq!(s, items); }); Vec::from(&items[..]).run_with_ptr_slice(|s| unsafe { assert!(s[4].is_null()); assert_eq!(s.len(), items.len() + 1); let s = std::slice::from_raw_parts(s.as_ptr() as *const crate::Error, items.len()); for (a, b) in Iterator::zip(items.iter(), s.iter()) { assert_eq!(a.message(), b.message()); assert_eq!( a.kind::().unwrap(), b.kind::().unwrap() ); } }); PtrSlice::::from(&items[..]).run_with_ptr_slice(|s| unsafe { assert!(s[4].is_null()); assert_eq!(s.len(), items.len() + 1); let s = std::slice::from_raw_parts(s.as_ptr() as *const crate::Error, items.len()); for (a, b) in Iterator::zip(items.iter(), s.iter()) { assert_eq!(a.message(), b.message()); assert_eq!( a.kind::().unwrap(), b.kind::().unwrap() ); } }); let v = Vec::from(&items[..]); items.run_with_ptr_slice(|s| unsafe { assert!(s[4].is_null()); assert_eq!(s.len(), v.len() + 1); let s = std::slice::from_raw_parts(s.as_ptr() as *const crate::Error, v.len()); for (a, b) in Iterator::zip(v.iter(), s.iter()) { assert_eq!(a.message(), b.message()); assert_eq!( a.kind::().unwrap(), b.kind::().unwrap() ); } }); } } glib-0.20.9/src/collections/slice.rs000064400000000000000000000663411046102023000154150ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{fmt, marker::PhantomData, mem, ptr}; use crate::{ffi, translate::*}; // rustdoc-stripper-ignore-next /// Minimum size of the `Slice` allocation in bytes. const MIN_SIZE: usize = 256; // rustdoc-stripper-ignore-next /// Slice of elements of type `T` allocated by the GLib allocator. /// /// This can be used like a `&[T]`, `&mut [T]` and `Vec`. pub struct Slice { ptr: ptr::NonNull, len: usize, capacity: usize, } unsafe impl Send for Slice {} unsafe impl Sync for Slice {} impl fmt::Debug for Slice { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.as_slice().fmt(f) } } impl PartialEq for Slice { #[inline] fn eq(&self, other: &Self) -> bool { self.as_slice() == other.as_slice() } } impl Eq for Slice {} impl PartialOrd for Slice { #[inline] fn partial_cmp(&self, other: &Self) -> Option { self.as_slice().partial_cmp(other.as_slice()) } } impl Ord for Slice { #[inline] fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.as_slice().cmp(other.as_slice()) } } impl std::hash::Hash for Slice { #[inline] fn hash(&self, state: &mut H) { self.as_slice().hash(state) } } impl PartialEq<[T]> for Slice { #[inline] fn eq(&self, other: &[T]) -> bool { self.as_slice() == other } } impl PartialEq> for [T] { #[inline] fn eq(&self, other: &Slice) -> bool { self == other.as_slice() } } impl Drop for Slice { #[inline] fn drop(&mut self) { unsafe { if mem::needs_drop::() { for i in 0..self.len { ptr::drop_in_place::(self.ptr.as_ptr().add(i) as *mut T); } } if self.capacity != 0 { ffi::g_free(self.ptr.as_ptr() as ffi::gpointer); } } } } impl AsRef<[T]> for Slice { #[inline] fn as_ref(&self) -> &[T] { self.as_slice() } } impl AsMut<[T]> for Slice { #[inline] fn as_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } impl std::borrow::Borrow<[T]> for Slice { #[inline] fn borrow(&self) -> &[T] { self.as_slice() } } impl std::borrow::BorrowMut<[T]> for Slice { #[inline] fn borrow_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } impl std::ops::Deref for Slice { type Target = [T]; #[inline] fn deref(&self) -> &[T] { self.as_slice() } } impl std::ops::DerefMut for Slice { #[inline] fn deref_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } impl Default for Slice { #[inline] fn default() -> Self { Self::new() } } impl std::iter::Extend for Slice { #[inline] fn extend>(&mut self, iter: I) { let iter = iter.into_iter(); self.reserve(iter.size_hint().0); for item in iter { self.push(item); } } } impl<'a, T: TransparentType + 'a> std::iter::Extend<&'a T> for Slice { #[inline] fn extend>(&mut self, iter: I) { let iter = iter.into_iter(); self.reserve(iter.size_hint().0); for item in iter { self.push(item.clone()); } } } impl std::iter::FromIterator for Slice { #[inline] fn from_iter>(iter: I) -> Self { let iter = iter.into_iter(); let mut s = Self::with_capacity(iter.size_hint().0); for item in iter { s.push(item); } s } } impl<'a, T: TransparentType> std::iter::IntoIterator for &'a Slice { type Item = &'a T; type IntoIter = std::slice::Iter<'a, T>; #[inline] fn into_iter(self) -> Self::IntoIter { self.as_slice().iter() } } impl<'a, T: TransparentType> std::iter::IntoIterator for &'a mut Slice { type Item = &'a mut T; type IntoIter = std::slice::IterMut<'a, T>; #[inline] fn into_iter(self) -> Self::IntoIter { self.as_mut_slice().iter_mut() } } impl std::iter::IntoIterator for Slice { type Item = T; type IntoIter = IntoIter; #[inline] fn into_iter(self) -> Self::IntoIter { IntoIter::new(self) } } pub struct IntoIter { ptr: ptr::NonNull, idx: ptr::NonNull, len: usize, empty: bool, } impl IntoIter { #[inline] fn new(slice: Slice) -> Self { let slice = mem::ManuallyDrop::new(slice); IntoIter { ptr: slice.ptr, idx: slice.ptr, len: slice.len, empty: slice.capacity == 0, } } // rustdoc-stripper-ignore-next /// Returns the remaining items as slice. #[inline] pub fn as_slice(&self) -> &[T] { unsafe { if self.len == 0 { &[] } else { std::slice::from_raw_parts(self.idx.as_ptr() as *mut T, self.len) } } } // rustdoc-stripper-ignore-next /// Returns the remaining items as mutable slice. #[inline] pub fn as_mut_slice(&mut self) -> &mut [T] { unsafe { if self.len == 0 { &mut [] } else { std::slice::from_raw_parts_mut(self.idx.as_ptr() as *mut T, self.len) } } } } impl Drop for IntoIter { #[inline] fn drop(&mut self) { unsafe { if mem::needs_drop::() { for i in 0..self.len { ptr::drop_in_place::(self.idx.as_ptr().add(i) as *mut T); } } if !self.empty { ffi::g_free(self.ptr.as_ptr() as ffi::gpointer); } } } } impl Iterator for IntoIter { type Item = T; #[inline] fn next(&mut self) -> Option { if self.len == 0 { return None; } unsafe { let p = self.idx.as_ptr(); self.len -= 1; self.idx = ptr::NonNull::new_unchecked(p.add(1)); Some(ptr::read(p as *mut T)) } } #[inline] fn size_hint(&self) -> (usize, Option) { (self.len, Some(self.len)) } #[inline] fn count(self) -> usize { self.len } #[inline] fn last(mut self) -> Option { if self.len == 0 { None } else { self.len -= 1; Some(unsafe { ptr::read(self.idx.as_ptr().add(self.len) as *mut T) }) } } } impl DoubleEndedIterator for IntoIter { #[inline] fn next_back(&mut self) -> Option { if self.len == 0 { None } else { self.len -= 1; Some(unsafe { ptr::read(self.idx.as_ptr().add(self.len) as *mut T) }) } } } impl ExactSizeIterator for IntoIter {} impl std::iter::FusedIterator for IntoIter {} impl From> for Vec { #[inline] fn from(mut value: Slice) -> Self { unsafe { let mut s = Vec::with_capacity(value.len); ptr::copy_nonoverlapping(value.ptr.as_ptr() as *const T, s.as_mut_ptr(), value.len); s.set_len(value.len); value.len = 0; s } } } impl From> for Slice { #[inline] fn from(mut value: Vec) -> Self { unsafe { let mut s = Self::with_capacity(value.len()); ptr::copy_nonoverlapping(value.as_ptr(), s.ptr.as_ptr() as *mut T, value.len()); s.len = value.len(); value.set_len(0); s } } } impl From<[T; N]> for Slice { #[inline] fn from(value: [T; N]) -> Self { unsafe { let value = mem::ManuallyDrop::new(value); let len = value.len(); let mut s = Self::with_capacity(len); ptr::copy_nonoverlapping(value.as_ptr(), s.ptr.as_ptr() as *mut T, len); s.len = len; s } } } impl<'a, T: TransparentType> From<&'a [T]> for Slice { #[inline] fn from(value: &'a [T]) -> Self { unsafe { let mut s = Self::with_capacity(value.len()); for (i, item) in value.iter().enumerate() { ptr::write(s.ptr.as_ptr().add(i) as *mut T, item.clone()); } s.len = value.len(); s } } } impl<'a, T: TransparentType> From<&'a [&'a T]> for Slice { #[inline] fn from(value: &'a [&'a T]) -> Self { unsafe { let mut s = Self::with_capacity(value.len()); for (i, item) in value.iter().enumerate() { ptr::write(s.ptr.as_ptr().add(i) as *mut T, (*item).clone()); } s.len = value.len(); s } } } impl Clone for Slice { #[inline] fn clone(&self) -> Self { Self::from(self.as_slice()) } } impl Slice { // rustdoc-stripper-ignore-next /// Borrows a C array. #[inline] pub unsafe fn from_glib_borrow_num<'a>(ptr: *const T::GlibType, len: usize) -> &'a [T] { debug_assert_eq!(mem::size_of::(), mem::size_of::()); debug_assert!(!ptr.is_null() || len == 0); if len == 0 { &[] } else { std::slice::from_raw_parts(ptr as *const T, len) } } // rustdoc-stripper-ignore-next /// Borrows a mutable C array. #[inline] pub unsafe fn from_glib_borrow_num_mut<'a>(ptr: *mut T::GlibType, len: usize) -> &'a mut [T] { debug_assert_eq!(mem::size_of::(), mem::size_of::()); debug_assert!(!ptr.is_null() || len == 0); if len == 0 { &mut [] } else { std::slice::from_raw_parts_mut(ptr as *mut T, len) } } // rustdoc-stripper-ignore-next /// Borrows a C array of references. #[inline] pub unsafe fn from_glib_ptr_borrow_num<'a>( ptr: *const *const T::GlibType, len: usize, ) -> &'a [&'a T] { debug_assert_eq!(mem::size_of::(), mem::size_of::()); debug_assert!(!ptr.is_null() || len == 0); if len == 0 { &[] } else { std::slice::from_raw_parts(ptr as *const &T, len) } } // rustdoc-stripper-ignore-next /// Borrows a mutable C array. #[inline] pub unsafe fn from_glib_ptr_borrow_num_mut<'a>( ptr: *mut *mut T::GlibType, len: usize, ) -> &'a mut [&'a mut T] { debug_assert_eq!(mem::size_of::(), mem::size_of::()); debug_assert!(!ptr.is_null() || len == 0); if len == 0 { &mut [] } else { std::slice::from_raw_parts_mut(ptr as *mut &mut T, len) } } // rustdoc-stripper-ignore-next /// Create a new `Slice` around a C array. #[inline] pub unsafe fn from_glib_none_num(ptr: *const T::GlibType, len: usize) -> Self { debug_assert_eq!(mem::size_of::(), mem::size_of::()); debug_assert!(!ptr.is_null() || len == 0); if len == 0 { Slice::default() } else { // Need to fully copy the array here. let s = Self::from_glib_borrow_num(ptr, len); Self::from(s) } } // rustdoc-stripper-ignore-next /// Create a new `Slice` around a C array. #[inline] pub unsafe fn from_glib_container_num(ptr: *mut T::GlibType, len: usize) -> Self { debug_assert_eq!(mem::size_of::(), mem::size_of::()); debug_assert!(!ptr.is_null() || len == 0); if len == 0 { ffi::g_free(ptr as ffi::gpointer); Slice::default() } else { // Need to clone every item because we don't own it here but only // if this type requires explicit drop. if mem::needs_drop::() { for i in 0..len { let p = ptr.add(i) as *mut T; let clone: T = (*p).clone(); ptr::write(p, clone); } } // And now it can be handled exactly the same as `from_glib_full_num()`. Self::from_glib_full_num(ptr, len) } } // rustdoc-stripper-ignore-next /// Create a new `Slice` around a C array. #[inline] pub unsafe fn from_glib_full_num(ptr: *mut T::GlibType, len: usize) -> Self { debug_assert_eq!(mem::size_of::(), mem::size_of::()); debug_assert!(!ptr.is_null() || len == 0); if len == 0 { ffi::g_free(ptr as ffi::gpointer); Slice::default() } else { Slice { ptr: ptr::NonNull::new_unchecked(ptr), len, capacity: len, } } } // rustdoc-stripper-ignore-next /// Creates a new empty slice. #[inline] pub fn new() -> Self { debug_assert_eq!(mem::size_of::(), mem::size_of::()); Slice { ptr: ptr::NonNull::dangling(), len: 0, capacity: 0, } } // rustdoc-stripper-ignore-next /// Creates a new empty slice with the given capacity. #[inline] pub fn with_capacity(capacity: usize) -> Self { let mut s = Self::new(); s.reserve(capacity); s } // rustdoc-stripper-ignore-next /// Returns the underlying pointer. /// /// This is guaranteed to be `NULL`-terminated. #[inline] pub fn as_ptr(&self) -> *const T::GlibType { if self.len == 0 { ptr::null() } else { self.ptr.as_ptr() } } // rustdoc-stripper-ignore-next /// Returns the underlying pointer. /// /// This is guaranteed to be `NULL`-terminated. #[inline] pub fn as_mut_ptr(&mut self) -> *mut T::GlibType { if self.len == 0 { ptr::null_mut() } else { self.ptr.as_ptr() } } // rustdoc-stripper-ignore-next /// Consumes the slice and returns the underlying pointer. /// /// This is guaranteed to be `NULL`-terminated. #[inline] pub fn into_raw(mut self) -> *mut T::GlibType { if self.len == 0 { ptr::null_mut() } else { self.len = 0; self.capacity = 0; self.ptr.as_ptr() } } // rustdoc-stripper-ignore-next /// Gets the length of the slice. #[inline] pub fn len(&self) -> usize { self.len } // rustdoc-stripper-ignore-next /// Returns `true` if the slice is empty. #[inline] pub fn is_empty(&self) -> bool { self.len == 0 } // rustdoc-stripper-ignore-next /// Returns the capacity of the slice. #[inline] pub fn capacity(&self) -> usize { self.capacity } // rustdoc-stripper-ignore-next /// Sets the length of the slice to `len`. /// /// # SAFETY /// /// There must be at least `len` valid items. pub unsafe fn set_len(&mut self, len: usize) { self.len = len; } // rustdoc-stripper-ignore-next /// Reserves at least this much additional capacity. pub fn reserve(&mut self, additional: usize) { // Nothing new to reserve as there's still enough space if self.len + additional <= self.capacity { return; } let new_capacity = usize::next_power_of_two(std::cmp::max( self.len + additional, MIN_SIZE / mem::size_of::(), )); assert_ne!(new_capacity, 0); assert!(new_capacity > self.capacity); unsafe { let ptr = if self.capacity == 0 { ptr::null_mut() } else { self.ptr.as_ptr() as *mut _ }; let new_ptr = ffi::g_realloc(ptr, mem::size_of::().checked_mul(new_capacity).unwrap()) as *mut T::GlibType; self.ptr = ptr::NonNull::new_unchecked(new_ptr); self.capacity = new_capacity; } } // rustdoc-stripper-ignore-next /// Borrows this slice as a `&[T]`. #[inline] pub fn as_slice(&self) -> &[T] { unsafe { if self.len == 0 { &[] } else { std::slice::from_raw_parts(self.ptr.as_ptr() as *const T, self.len) } } } // rustdoc-stripper-ignore-next /// Borrows this slice as a `&mut [T]`. #[inline] pub fn as_mut_slice(&mut self) -> &mut [T] { unsafe { if self.len == 0 { &mut [] } else { std::slice::from_raw_parts_mut(self.ptr.as_ptr() as *mut T, self.len) } } } // rustdoc-stripper-ignore-next /// Removes all items from the slice. #[inline] pub fn clear(&mut self) { unsafe { if mem::needs_drop::() { for i in 0..self.len { ptr::drop_in_place::(self.ptr.as_ptr().add(i) as *mut T); } } self.len = 0; } } // rustdoc-stripper-ignore-next /// Clones and appends all elements in `slice` to the slice. #[inline] pub fn extend_from_slice(&mut self, other: &[T]) { // Nothing new to reserve as there's still enough space if self.len + other.len() > self.capacity { self.reserve(other.len()); } unsafe { for item in other { ptr::write(self.ptr.as_ptr().add(self.len) as *mut T, item.clone()); self.len += 1; } } } // rustdoc-stripper-ignore-next /// Inserts `item` at position `index` of the slice, shifting all elements after it to the /// right. #[inline] #[allow(clippy::int_plus_one)] pub fn insert(&mut self, index: usize, item: T) { assert!(index <= self.len); // Nothing new to reserve as there's still enough space if self.len + 1 > self.capacity { self.reserve(1); } unsafe { if index == self.len { ptr::write(self.ptr.as_ptr().add(self.len) as *mut T, item); } else { let p = self.ptr.as_ptr().add(index); ptr::copy(p, p.add(1), self.len - index); ptr::write(self.ptr.as_ptr().add(index) as *mut T, item); } self.len += 1; } } // rustdoc-stripper-ignore-next /// Pushes `item` to the end of the slice. #[inline] #[allow(clippy::int_plus_one)] pub fn push(&mut self, item: T) { // Nothing new to reserve as there's still enough space if self.len + 1 > self.capacity { self.reserve(1); } unsafe { ptr::write(self.ptr.as_ptr().add(self.len) as *mut T, item); self.len += 1; } } // rustdoc-stripper-ignore-next /// Removes item from position `index` of the slice, shifting all elements after it to the /// left. #[inline] pub fn remove(&mut self, index: usize) -> T { assert!(index < self.len); unsafe { let p = self.ptr.as_ptr().add(index); let item = ptr::read(p as *mut T); ptr::copy(p.add(1), p, self.len - index - 1); self.len -= 1; item } } // rustdoc-stripper-ignore-next /// Removes the last item of the slice and returns it. #[inline] pub fn pop(&mut self) -> Option { if self.len == 0 { return None; } unsafe { self.len -= 1; let p = self.ptr.as_ptr().add(self.len); let item = ptr::read(p as *mut T); Some(item) } } // rustdoc-stripper-ignore-next /// Shortens the slice by keeping the last `len` items. /// /// If there are fewer than `len` items then this has no effect. #[inline] pub fn truncate(&mut self, len: usize) { if self.len <= len { return; } unsafe { while self.len > len { self.len -= 1; let p = self.ptr.as_ptr().add(self.len); ptr::drop_in_place::(p as *mut T); } } } } impl FromGlibContainer for Slice { unsafe fn from_glib_none_num(ptr: *mut T::GlibType, num: usize) -> Self { Self::from_glib_none_num(ptr, num) } #[inline] unsafe fn from_glib_container_num(ptr: *mut T::GlibType, num: usize) -> Self { Self::from_glib_container_num(ptr, num) } #[inline] unsafe fn from_glib_full_num(ptr: *mut T::GlibType, num: usize) -> Self { Self::from_glib_full_num(ptr, num) } } impl FromGlibContainer for Slice { unsafe fn from_glib_none_num(ptr: *const T::GlibType, num: usize) -> Self { Self::from_glib_none_num(ptr, num) } unsafe fn from_glib_container_num(_ptr: *const T::GlibType, _num: usize) -> Self { unimplemented!(); } unsafe fn from_glib_full_num(_ptr: *const T::GlibType, _num: usize) -> Self { unimplemented!(); } } impl<'a, T: TransparentType + 'a> ToGlibPtr<'a, *mut T::GlibType> for Slice { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut T::GlibType, Self> { Stash(self.as_ptr() as *mut _, PhantomData) } #[inline] fn to_glib_container(&'a self) -> Stash<'a, *mut T::GlibType, Self> { unsafe { let ptr = ffi::g_malloc(mem::size_of::().checked_mul(self.len()).unwrap()) as *mut T::GlibType; ptr::copy_nonoverlapping(self.as_ptr(), ptr, self.len()); Stash(ptr, PhantomData) } } #[inline] fn to_glib_full(&self) -> *mut T::GlibType { self.clone().into_raw() } } impl<'a, T: TransparentType + 'a> ToGlibPtr<'a, *const T::GlibType> for Slice { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const T::GlibType, Self> { Stash(self.as_ptr(), PhantomData) } } impl<'a, T: TransparentType + 'a> ToGlibPtrMut<'a, *mut T::GlibType> for Slice { type Storage = PhantomData<&'a mut Self>; #[inline] fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut T::GlibType, Self> { StashMut(self.as_mut_ptr(), PhantomData) } } impl IntoGlibPtr<*mut T::GlibType> for Slice { #[inline] unsafe fn into_glib_ptr(self) -> *mut T::GlibType { self.into_raw() } } impl From> for Slice { fn from(value: super::PtrSlice) -> Self { let len = value.len(); let capacity = value.capacity(); unsafe { let ptr = value.into_raw(); Slice:: { ptr: ptr::NonNull::new_unchecked(ptr), len, capacity, } } } } #[cfg(test)] mod test { use super::*; #[test] fn test_from_glib_full() { let items = [ crate::Date::from_dmy(20, crate::DateMonth::November, 2021).unwrap(), crate::Date::from_dmy(21, crate::DateMonth::November, 2021).unwrap(), crate::Date::from_dmy(22, crate::DateMonth::November, 2021).unwrap(), crate::Date::from_dmy(23, crate::DateMonth::November, 2021).unwrap(), ]; let slice = unsafe { let ptr = ffi::g_malloc(mem::size_of::() * 4) as *mut ffi::GDate; ptr::write(ptr.add(0), *items[0].to_glib_none().0); ptr::write(ptr.add(1), *items[1].to_glib_none().0); ptr::write(ptr.add(2), *items[2].to_glib_none().0); ptr::write(ptr.add(3), *items[3].to_glib_none().0); Slice::::from_glib_full_num(ptr, 4) }; assert_eq!(&items[..], &*slice); } #[test] fn test_from_glib_none() { let items = [ crate::Date::from_dmy(20, crate::DateMonth::November, 2021).unwrap(), crate::Date::from_dmy(21, crate::DateMonth::November, 2021).unwrap(), crate::Date::from_dmy(22, crate::DateMonth::November, 2021).unwrap(), crate::Date::from_dmy(23, crate::DateMonth::November, 2021).unwrap(), ]; let slice = unsafe { Slice::::from_glib_none_num(items.as_ptr() as *const ffi::GDate, 4) }; assert_eq!(&items[..], &*slice); } #[test] fn test_safe_api() { let items = [ crate::Date::from_dmy(20, crate::DateMonth::November, 2021).unwrap(), crate::Date::from_dmy(21, crate::DateMonth::November, 2021).unwrap(), crate::Date::from_dmy(22, crate::DateMonth::November, 2021).unwrap(), ]; let mut slice = Slice::from(&items[..]); assert_eq!(slice.len(), 3); slice.push(crate::Date::from_dmy(23, crate::DateMonth::November, 2021).unwrap()); assert_eq!(slice.len(), 4); for (a, b) in Iterator::zip(items.iter(), slice.iter()) { assert_eq!(a, b); } assert_eq!( (slice[3].day(), slice[3].month(), slice[3].year()), (23, crate::DateMonth::November, 2021) ); let vec = Vec::from(slice); assert_eq!(vec.len(), 4); for (a, b) in Iterator::zip(items.iter(), vec.iter()) { assert_eq!(a, b); } assert_eq!( (vec[3].day(), vec[3].month(), vec[3].year()), (23, crate::DateMonth::November, 2021) ); let mut slice = Slice::from(vec); assert_eq!(slice.len(), 4); let e = slice.pop().unwrap(); assert_eq!( (e.day(), e.month(), e.year()), (23, crate::DateMonth::November, 2021) ); assert_eq!(slice.len(), 3); slice.insert(2, e); assert_eq!(slice.len(), 4); assert_eq!(slice[0].day(), 20); assert_eq!(slice[1].day(), 21); assert_eq!(slice[2].day(), 23); assert_eq!(slice[3].day(), 22); let e = slice.remove(2); assert_eq!( (e.day(), e.month(), e.year()), (23, crate::DateMonth::November, 2021) ); assert_eq!(slice.len(), 3); slice.push(e); assert_eq!(slice.len(), 4); for (a, b) in Iterator::zip(items.iter(), slice.into_iter()) { assert_eq!(a, &b); } } } glib-0.20.9/src/collections/slist.rs000064400000000000000000000712611046102023000154510ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{iter::FusedIterator, marker::PhantomData, mem, ptr}; use crate::{ffi, translate::*}; // rustdoc-stripper-ignore-next /// A list of items of type `T`. /// /// Behaves like an `Iterator` but allows modifications. #[repr(transparent)] pub struct SList { ptr: Option>, phantom: PhantomData, } #[doc(hidden)] unsafe impl TransparentPtrType for SList {} #[doc(hidden)] impl GlibPtrDefault for SList { type GlibType = *mut ffi::GSList; } unsafe impl Send for SList {} unsafe impl Sync for SList {} impl SList { // rustdoc-stripper-ignore-next /// Create a new `SList` around a list. #[inline] pub unsafe fn from_glib_none(list: *const ffi::GSList) -> SList { // Need to copy the whole list let list = if mem::needs_drop::() { unsafe extern "C" fn copy_item( ptr: ffi::gconstpointer, _user_data: ffi::gpointer, ) -> ffi::gpointer { let mut item = mem::ManuallyDrop::new( (*(&ptr as *const ffi::gconstpointer as *const T)).clone(), ); *(&mut *item as *mut T as *mut *mut T::GlibType) as ffi::gpointer } ffi::g_slist_copy_deep(mut_override(list), Some(copy_item::), ptr::null_mut()) } else { ffi::g_slist_copy(mut_override(list)) }; SList { ptr: ptr::NonNull::new(list), phantom: PhantomData, } } // rustdoc-stripper-ignore-next /// Create a new `SList` around a list. #[inline] pub unsafe fn from_glib_container(list: *mut ffi::GSList) -> SList { // Need to copy all items as we only own the container if mem::needs_drop::() { unsafe extern "C" fn copy_item( ptr: ffi::gpointer, _user_data: ffi::gpointer, ) { let item = (*(&ptr as *const ffi::gpointer as *const T)).clone(); ptr::write(ptr as *mut T, item); } ffi::g_slist_foreach(list, Some(copy_item::), ptr::null_mut()); } SList { ptr: ptr::NonNull::new(list), phantom: PhantomData, } } // rustdoc-stripper-ignore-next /// Create a new `SList` around a list. #[inline] pub unsafe fn from_glib_full(list: *mut ffi::GSList) -> SList { SList { ptr: ptr::NonNull::new(list), phantom: PhantomData, } } // rustdoc-stripper-ignore-next /// Creates a new empty list. #[inline] pub fn new() -> Self { SList { ptr: None, phantom: PhantomData, } } // rustdoc-stripper-ignore-next /// Create a non-destructive iterator over the `SList`. #[inline] pub fn iter(&self) -> Iter { Iter::new(self) } // rustdoc-stripper-ignore-next /// Create a non-destructive mutable iterator over the `SList`. #[inline] pub fn iter_mut(&mut self) -> IterMut { IterMut::new(self) } // rustdoc-stripper-ignore-next /// Check if the list is empty. /// /// This operation is `O(1)`. #[inline] pub fn is_empty(&self) -> bool { self.ptr.is_none() } // rustdoc-stripper-ignore-next /// Returns the length of the list. /// /// This operation is `O(n)`. #[inline] #[doc(alias = "g_slist_length")] pub fn len(&self) -> usize { self.iter().count() } // rustdoc-stripper-ignore-next /// Returns a reference to the first item of the list, if any. /// /// This operation is `O(1)`. #[inline] #[doc(alias = "g_slist_first")] pub fn front(&self) -> Option<&T> { match self.ptr { None => None, Some(cur) => unsafe { let item = &*(&cur.as_ref().data as *const ffi::gpointer as *const T); Some(item) }, } } // rustdoc-stripper-ignore-next /// Returns a mutable reference to the first item of the list, if any. /// /// This operation is `O(1)`. #[inline] #[doc(alias = "g_slist_first")] pub fn front_mut(&mut self) -> Option<&mut T> { match self.ptr { None => None, Some(mut cur) => unsafe { let item = &mut *(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T); Some(item) }, } } // rustdoc-stripper-ignore-next /// Removes the front item from the list, if any. /// /// This operation is `O(1)`. #[inline] pub fn pop_front(&mut self) -> Option { match self.ptr { None => None, Some(mut cur) => unsafe { self.ptr = ptr::NonNull::new(cur.as_ref().next); let item = ptr::read(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T); ffi::g_slist_free_1(cur.as_ptr()); Some(item) }, } } // rustdoc-stripper-ignore-next /// Prepends the new item to the front of the list. /// /// This operation is `O(1)`. #[inline] #[doc(alias = "g_slist_prepend")] pub fn push_front(&mut self, item: T) { unsafe { let ptr = self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut()); self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_slist_prepend( ptr, *(&mut *mem::ManuallyDrop::new(item) as *mut T as *mut *mut T::GlibType) as ffi::gpointer, ))); } } // rustdoc-stripper-ignore-next /// Returns a reference to the last item of the list, if any. /// /// This operation is `O(n)`. #[inline] #[doc(alias = "g_slist_last")] pub fn back(&self) -> Option<&T> { unsafe { let ptr = match self.ptr { None => return None, Some(ptr) => ptr.as_ptr(), }; let last_ptr = ffi::g_slist_last(ptr); let item = &*(&(*last_ptr).data as *const ffi::gpointer as *const T); Some(item) } } // rustdoc-stripper-ignore-next /// Returns a mutable reference to the last item of the list, if any. /// /// This operation is `O(n)`. #[inline] #[doc(alias = "g_slist_last")] pub fn back_mut(&mut self) -> Option<&mut T> { unsafe { let ptr = match self.ptr { None => return None, Some(ptr) => ptr.as_ptr(), }; let last_ptr = ffi::g_slist_last(ptr); let item = &mut *(&mut (*last_ptr).data as *mut ffi::gpointer as *mut T); Some(item) } } // rustdoc-stripper-ignore-next /// Removes the back item from the list, if any. /// /// This operation is `O(n)`. #[inline] pub fn pop_back(&mut self) -> Option { unsafe { let ptr = match self.ptr { None => return None, Some(ptr) => ptr.as_ptr(), }; let last_ptr = ffi::g_slist_last(ptr); let item = ptr::read(&mut (*last_ptr).data as *mut ffi::gpointer as *mut T); self.ptr = ptr::NonNull::new(ffi::g_slist_delete_link(ptr, last_ptr)); Some(item) } } // rustdoc-stripper-ignore-next /// Appends the new item to the back of the list. /// /// this operation is `O(n)`. #[inline] #[doc(alias = "g_slist_append")] pub fn push_back(&mut self, item: T) { unsafe { let ptr = self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut()); self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_slist_append( ptr, *(&mut *mem::ManuallyDrop::new(item) as *mut T as *mut *mut T::GlibType) as ffi::gpointer, ))); } } // rustdoc-stripper-ignore-next /// Reverse the list. /// /// This operation is `O(n)`. #[inline] #[doc(alias = "g_slist_reverse")] pub fn reverse(&mut self) { unsafe { let ptr = match self.ptr { None => return, Some(ptr) => ptr.as_ptr(), }; self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_slist_reverse(ptr))); } } // rustdoc-stripper-ignore-next /// Sorts the list. /// /// This operation is `O(n * log n)`. #[inline] #[doc(alias = "g_slist_sort")] pub fn sort(&mut self) where T: Ord, { self.sort_by(|a, b| a.cmp(b)); } // rustdoc-stripper-ignore-next /// Sorts the list. /// /// This operation is `O(n * log n)`. #[inline] #[doc(alias = "g_slist_sort")] pub fn sort_by std::cmp::Ordering>(&mut self, mut f: F) { unsafe { let ptr = match self.ptr { None => return, Some(ptr) => ptr.as_ptr(), }; unsafe extern "C" fn func< T: TransparentPtrType, F: FnMut(&T, &T) -> std::cmp::Ordering, >( a: ffi::gconstpointer, b: ffi::gconstpointer, user_data: ffi::gpointer, ) -> i32 { let f = &mut *(user_data as *mut F); let a = &*(&a as *const ffi::gconstpointer as *const T); let b = &*(&b as *const ffi::gconstpointer as *const T); f(a, b).into_glib() } self.ptr = Some(ptr::NonNull::new_unchecked(ffi::g_slist_sort_with_data( ptr, Some(func::), &mut f as *mut F as ffi::gpointer, ))); } } // rustdoc-stripper-ignore-next /// Removes all items from the list. #[inline] pub fn clear(&mut self) { *self = Self::new(); } // rustdoc-stripper-ignore-next /// Only keeps the item in the list for which `f` returns `true`. #[inline] pub fn retain(&mut self, mut f: impl FnMut(&T) -> bool) { if let Some(head) = self.ptr { unsafe { let mut ptr = head.as_ptr(); while !ptr.is_null() { let item = &*((*ptr).data as *const ffi::gpointer as *const T); let next = (*ptr).next; if !f(item) { ptr::drop_in_place(&mut (*ptr).data as *mut ffi::gpointer as *mut T); self.ptr = ptr::NonNull::new(ffi::g_slist_delete_link(head.as_ptr(), ptr)); } ptr = next; } } } } // rustdoc-stripper-ignore-next /// Returns the underlying pointer. #[inline] pub fn as_ptr(&self) -> *const ffi::GSList { self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut()) } // rustdoc-stripper-ignore-next /// Returns the underlying pointer. #[inline] pub fn as_mut_ptr(&mut self) -> *mut ffi::GSList { self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut()) } // rustdoc-stripper-ignore-next /// Consumes the list and returns the underlying pointer. #[inline] pub fn into_raw(mut self) -> *mut ffi::GSList { self.ptr .take() .map(|p| p.as_ptr()) .unwrap_or(ptr::null_mut()) } } impl Default for SList { fn default() -> Self { Self::new() } } impl Clone for SList { fn clone(&self) -> Self { unsafe { Self::from_glib_none(self.ptr.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut())) } } } impl Drop for SList { #[inline] fn drop(&mut self) { if let Some(ptr) = self.ptr { unsafe { if mem::needs_drop::() { unsafe extern "C" fn drop_item(mut ptr: ffi::gpointer) { ptr::drop_in_place(&mut ptr as *mut ffi::gpointer as *mut T); } ffi::g_slist_free_full(ptr.as_ptr(), Some(drop_item::)); } else { ffi::g_slist_free(ptr.as_ptr()); } } } } } impl std::iter::FromIterator for SList { #[inline] fn from_iter>(iter: I) -> Self { unsafe { let mut iter = iter.into_iter(); let first = match iter.next() { None => return Self::new(), Some(first) => first, }; let list = ffi::g_slist_prepend( ptr::null_mut(), *(&mut *mem::ManuallyDrop::new(first) as *mut T as *mut *mut T::GlibType) as ffi::gpointer, ); let mut tail = list; for item in iter { let new_tail = ffi::g_slist_alloc(); (*new_tail).data = *(&mut *mem::ManuallyDrop::new(item) as *mut T as *mut *mut T::GlibType) as ffi::gpointer; (*new_tail).next = ptr::null_mut(); (*tail).next = new_tail; tail = new_tail; } Self::from_glib_full(list) } } } impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a SList { type Item = &'a T; type IntoIter = Iter<'a, T>; #[inline] fn into_iter(self) -> Self::IntoIter { self.iter() } } impl<'a, T: TransparentPtrType> std::iter::IntoIterator for &'a mut SList { type Item = &'a mut T; type IntoIter = IterMut<'a, T>; #[inline] fn into_iter(self) -> Self::IntoIter { self.iter_mut() } } impl std::iter::IntoIterator for SList { type Item = T; type IntoIter = IntoIter; #[inline] fn into_iter(self) -> Self::IntoIter { IntoIter::new(self) } } impl std::iter::Extend for SList { #[inline] fn extend>(&mut self, iter: I) { let list = iter.into_iter().collect::(); if list.is_empty() { return; } match self.ptr.map(|p| p.as_ptr()) { Some(ptr1) => { let ptr2 = list.into_raw(); let _ = unsafe { ffi::g_slist_concat(ptr1, ptr2) }; } None => { self.ptr = ptr::NonNull::new(list.into_raw()); } } } } impl FromGlibContainer<::GlibType, *mut ffi::GSList> for SList { #[inline] unsafe fn from_glib_none_num(ptr: *mut ffi::GSList, _num: usize) -> Self { Self::from_glib_none(ptr) } #[inline] unsafe fn from_glib_container_num(ptr: *mut ffi::GSList, _num: usize) -> Self { Self::from_glib_container(ptr) } #[inline] unsafe fn from_glib_full_num(ptr: *mut ffi::GSList, _num: usize) -> Self { Self::from_glib_full(ptr) } } impl FromGlibContainer<::GlibType, *const ffi::GSList> for SList { #[inline] unsafe fn from_glib_none_num(ptr: *const ffi::GSList, _num: usize) -> Self { Self::from_glib_none(ptr) } unsafe fn from_glib_container_num(_ptr: *const ffi::GSList, _num: usize) -> Self { unimplemented!(); } unsafe fn from_glib_full_num(_ptr: *const ffi::GSList, _num: usize) -> Self { unimplemented!(); } } impl FromGlibPtrContainer<::GlibType, *mut ffi::GSList> for SList { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::GSList) -> Self { Self::from_glib_none(ptr) } #[inline] unsafe fn from_glib_container(ptr: *mut ffi::GSList) -> Self { Self::from_glib_container(ptr) } #[inline] unsafe fn from_glib_full(ptr: *mut ffi::GSList) -> Self { Self::from_glib_full(ptr) } } impl FromGlibPtrContainer<::GlibType, *const ffi::GSList> for SList { #[inline] unsafe fn from_glib_none(ptr: *const ffi::GSList) -> Self { Self::from_glib_none(ptr) } unsafe fn from_glib_container(_ptr: *const ffi::GSList) -> Self { unimplemented!(); } unsafe fn from_glib_full(_ptr: *const ffi::GSList) -> Self { unimplemented!(); } } impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *mut ffi::GSList> for SList { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GSList, Self> { Stash(self.as_ptr() as *mut _, PhantomData) } #[inline] fn to_glib_container(&'a self) -> Stash<'a, *mut ffi::GSList, Self> { unsafe { let ptr = ffi::g_malloc(mem::size_of::().checked_mul(self.len() + 1).unwrap()) as *mut ffi::GSList; ptr::copy_nonoverlapping(self.as_ptr(), ptr, self.len() + 1); Stash(ptr, PhantomData) } } #[inline] fn to_glib_full(&self) -> *mut ffi::GSList { self.clone().into_raw() } } impl<'a, T: TransparentPtrType + 'a> ToGlibPtr<'a, *const ffi::GSList> for SList { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GSList, Self> { Stash(self.as_ptr(), PhantomData) } } impl<'a, T: TransparentPtrType + 'a> ToGlibPtrMut<'a, *mut ffi::GSList> for SList { type Storage = PhantomData<&'a mut Self>; #[inline] fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GSList, Self> { StashMut(self.as_mut_ptr(), PhantomData) } } impl IntoGlibPtr<*mut ffi::GSList> for SList { #[inline] unsafe fn into_glib_ptr(self) -> *mut ffi::GSList { self.into_raw() } } // rustdoc-stripper-ignore-next /// A non-destructive iterator over a [`SList`]. pub struct Iter<'a, T: TransparentPtrType> { ptr: Option>, phantom: PhantomData<&'a T>, } impl<'a, T: TransparentPtrType> Iter<'a, T> { #[inline] fn new(list: &'a SList) -> Iter<'a, T> { debug_assert_eq!( mem::size_of::(), mem::size_of::<::GlibType>() ); Iter { ptr: list.ptr, phantom: PhantomData, } } } impl<'a, T: TransparentPtrType> Iterator for Iter<'a, T> { type Item = &'a T; #[inline] fn next(&mut self) -> Option<&'a T> { match self.ptr { None => None, Some(cur) => unsafe { self.ptr = ptr::NonNull::new(cur.as_ref().next); let item = &*(&cur.as_ref().data as *const ffi::gpointer as *const T); Some(item) }, } } } impl FusedIterator for Iter<'_, T> {} // rustdoc-stripper-ignore-next /// A non-destructive iterator over a [`SList`]. pub struct IterMut<'a, T: TransparentPtrType> { ptr: Option>, phantom: PhantomData<&'a mut T>, } impl<'a, T: TransparentPtrType> IterMut<'a, T> { #[inline] fn new(list: &'a mut SList) -> IterMut<'a, T> { debug_assert_eq!( mem::size_of::(), mem::size_of::<::GlibType>() ); IterMut { ptr: list.ptr, phantom: PhantomData, } } } impl<'a, T: TransparentPtrType> Iterator for IterMut<'a, T> { type Item = &'a mut T; #[inline] fn next(&mut self) -> Option<&'a mut T> { match self.ptr { None => None, Some(mut cur) => unsafe { self.ptr = ptr::NonNull::new(cur.as_ref().next); let item = &mut *(&mut cur.as_mut().data as *mut ffi::gpointer as *mut T); Some(item) }, } } } impl FusedIterator for IterMut<'_, T> {} // rustdoc-stripper-ignore-next /// A destructive iterator over a [`SList`]. pub struct IntoIter { list: SList, } impl IntoIter { #[inline] fn new(list: SList) -> IntoIter { debug_assert_eq!( mem::size_of::(), mem::size_of::<::GlibType>() ); IntoIter { list } } } impl Iterator for IntoIter { type Item = T; #[inline] fn next(&mut self) -> Option { self.list.pop_front() } } impl FusedIterator for IntoIter {} #[cfg(test)] mod test { use super::*; #[test] // checker-ignore-item fn from_glib_full() { let items = [ crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(), ]; let mut list = unsafe { let mut list = ffi::g_slist_append( ptr::null_mut(), ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[0]) as ffi::gpointer, ); list = ffi::g_slist_append( list, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[1]) as ffi::gpointer, ); list = ffi::g_slist_append( list, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[2]) as ffi::gpointer, ); list = ffi::g_slist_append( list, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_full(&items[3]) as ffi::gpointer, ); SList::::from_glib_full(list) }; assert!(!list.is_empty()); let list_items = list.iter().cloned().collect::>(); assert_eq!(&items[..], &list_items); let list_items = list.iter_mut().map(|d| d.clone()).collect::>(); assert_eq!(&items[..], &list_items); let list_items = list.into_iter().collect::>(); assert_eq!(&items[..], &list_items); let list = unsafe { SList::::from_glib_full(ptr::null_mut()) }; assert!(list.is_empty()); } #[test] // checker-ignore-item fn from_glib_container() { let items = [ crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(), ]; let mut list = unsafe { let mut list = ffi::g_slist_append( ptr::null_mut(), ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer, ); list = ffi::g_slist_append( list, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer, ); list = ffi::g_slist_append( list, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer, ); list = ffi::g_slist_append( list, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer, ); SList::::from_glib_container(list) }; assert!(!list.is_empty()); let list_items = list.iter().cloned().collect::>(); assert_eq!(&items[..], &list_items); let list_items = list.iter_mut().map(|d| d.clone()).collect::>(); assert_eq!(&items[..], &list_items); let list_items = list.into_iter().collect::>(); assert_eq!(&items[..], &list_items); let list = unsafe { SList::::from_glib_full(ptr::null_mut()) }; assert!(list.is_empty()); } #[test] // checker-ignore-item fn from_glib_none() { let items = [ crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(), ]; let mut list = unsafe { let mut list = ffi::g_slist_append( ptr::null_mut(), ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[0]).0 as ffi::gpointer, ); list = ffi::g_slist_append( list, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[1]).0 as ffi::gpointer, ); list = ffi::g_slist_append( list, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[2]).0 as ffi::gpointer, ); list = ffi::g_slist_append( list, ToGlibPtr::<*mut ffi::GDateTime>::to_glib_none(&items[3]).0 as ffi::gpointer, ); let res = SList::::from_glib_none(list); ffi::g_slist_free(list); res }; assert!(!list.is_empty()); let list_items = list.iter().cloned().collect::>(); assert_eq!(&items[..], &list_items); let list_items = list.iter_mut().map(|d| d.clone()).collect::>(); assert_eq!(&items[..], &list_items); let list_items = list.into_iter().collect::>(); assert_eq!(&items[..], &list_items); let list = unsafe { SList::::from_glib_full(ptr::null_mut()) }; assert!(list.is_empty()); } #[test] // checker-ignore-item fn safe_api() { let items = [ crate::DateTime::from_utc(2021, 11, 20, 23, 41, 12.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 13.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 14.0).unwrap(), crate::DateTime::from_utc(2021, 11, 20, 23, 41, 15.0).unwrap(), ]; let mut list = items[1..3].iter().cloned().collect::>(); assert_eq!(list.len(), 2); list.push_front(items[0].clone()); assert_eq!(list.len(), 3); list.push_back(items[3].clone()); assert_eq!(list.len(), 4); let list_items = list.iter().cloned().collect::>(); assert_eq!(&items[..], &list_items); assert_eq!(list.front(), Some(&items[0])); assert_eq!(list.back(), Some(&items[3])); assert_eq!(list.pop_front().as_ref(), Some(&items[0])); assert_eq!(list.len(), 3); list.reverse(); let mut list_items = list.iter().cloned().collect::>(); list_items.reverse(); assert_eq!(&items[1..], &list_items); let list2 = list.clone(); let mut list_items = list2.iter().cloned().collect::>(); list_items.reverse(); assert_eq!(&items[1..], &list_items); } #[test] fn extend() { let mut list = SList::::new(); list.push_back(crate::DateTime::from_unix_utc(11).unwrap()); list.push_back(crate::DateTime::from_unix_utc(12).unwrap()); list.push_back(crate::DateTime::from_unix_utc(13).unwrap()); list.extend(vec![ crate::DateTime::from_unix_utc(21).unwrap(), crate::DateTime::from_unix_utc(22).unwrap(), ]); assert_eq!( list.iter().map(|dt| dt.to_unix()).collect::>(), vec![11, 12, 13, 21, 22] ); } #[test] fn extend_empty_with_empty() { let mut list1 = SList::::new(); list1.extend(vec![]); assert!(list1.is_empty()); } #[test] fn extend_with_empty() { let mut list = SList::::new(); list.push_back(crate::DateTime::from_unix_utc(11).unwrap()); list.push_back(crate::DateTime::from_unix_utc(12).unwrap()); list.push_back(crate::DateTime::from_unix_utc(13).unwrap()); list.extend(vec![]); assert_eq!( list.iter().map(|dt| dt.to_unix()).collect::>(), vec![11, 12, 13] ); } #[test] fn extend_empty() { let mut list = SList::::new(); list.extend(vec![ crate::DateTime::from_unix_utc(21).unwrap(), crate::DateTime::from_unix_utc(22).unwrap(), ]); assert_eq!( list.iter().map(|dt| dt.to_unix()).collect::>(), vec![21, 22] ); } } glib-0.20.9/src/collections/strv.rs000064400000000000000000001271211046102023000153060ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ffi::c_char, fmt, marker::PhantomData, mem, ptr}; use crate::{ffi, gobject_ffi, prelude::*, translate::*, GStr, GString, GStringPtr}; // rustdoc-stripper-ignore-next /// Minimum size of the `StrV` allocation. const MIN_SIZE: usize = 16; // rustdoc-stripper-ignore-next /// `NULL`-terminated array of `NULL`-terminated strings. /// /// The underlying memory is always `NULL`-terminated. /// /// This can be used like a `&[&str]`, `&mut [&str]` and `Vec<&str>`. pub struct StrV { ptr: ptr::NonNull<*mut c_char>, // rustdoc-stripper-ignore-next /// Length without the `NULL`-terminator. len: usize, // rustdoc-stripper-ignore-next /// Capacity **with** the `NULL`-terminator, i.e. the actual allocation size. capacity: usize, } impl fmt::Debug for StrV { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.as_slice().fmt(f) } } unsafe impl Send for StrV {} unsafe impl Sync for StrV {} impl PartialEq for StrV { #[inline] fn eq(&self, other: &Self) -> bool { self.as_slice() == other.as_slice() } } impl Eq for StrV {} impl PartialOrd for StrV { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for StrV { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.as_slice().cmp(other.as_slice()) } } impl std::hash::Hash for StrV { #[inline] fn hash(&self, state: &mut H) { self.as_slice().hash(state) } } impl PartialEq<[&'_ str]> for StrV { fn eq(&self, other: &[&'_ str]) -> bool { for (a, b) in Iterator::zip(self.iter(), other.iter()) { if a != b { return false; } } true } } impl PartialEq for [&'_ str] { #[inline] fn eq(&self, other: &StrV) -> bool { other.eq(self) } } impl Drop for StrV { #[inline] fn drop(&mut self) { unsafe { if self.capacity != 0 { ffi::g_strfreev(self.ptr.as_ptr()); } } } } impl Default for StrV { #[inline] fn default() -> Self { Self::new() } } impl AsRef<[GStringPtr]> for StrV { #[inline] fn as_ref(&self) -> &[GStringPtr] { self.as_slice() } } impl std::borrow::Borrow<[GStringPtr]> for StrV { #[inline] fn borrow(&self) -> &[GStringPtr] { self.as_slice() } } impl std::ops::Deref for StrV { type Target = [GStringPtr]; #[inline] fn deref(&self) -> &[GStringPtr] { self.as_slice() } } impl std::iter::Extend for StrV { #[inline] fn extend>(&mut self, iter: I) { let iter = iter.into_iter(); self.reserve(iter.size_hint().0); for item in iter { self.push(item); } } } impl<'a> std::iter::Extend<&'a str> for StrV { #[inline] fn extend>(&mut self, iter: I) { let iter = iter.into_iter(); self.reserve(iter.size_hint().0); for item in iter { self.push(GString::from(item)); } } } impl std::iter::FromIterator for StrV { #[inline] fn from_iter>(iter: I) -> Self { let iter = iter.into_iter(); let mut s = Self::with_capacity(iter.size_hint().0); for item in iter { s.push(item); } s } } impl<'a> std::iter::IntoIterator for &'a StrV { type Item = &'a GStringPtr; type IntoIter = std::slice::Iter<'a, GStringPtr>; #[inline] fn into_iter(self) -> Self::IntoIter { self.as_slice().iter() } } impl std::iter::IntoIterator for StrV { type Item = GString; type IntoIter = IntoIter; #[inline] fn into_iter(self) -> Self::IntoIter { IntoIter::new(self) } } pub struct IntoIter { ptr: ptr::NonNull<*mut c_char>, idx: ptr::NonNull<*mut c_char>, len: usize, empty: bool, } impl IntoIter { #[inline] fn new(slice: StrV) -> Self { let slice = mem::ManuallyDrop::new(slice); IntoIter { ptr: slice.ptr, idx: slice.ptr, len: slice.len, empty: slice.capacity == 0, } } // rustdoc-stripper-ignore-next /// Returns the remaining items as slice. #[inline] pub const fn as_slice(&self) -> &[GStringPtr] { unsafe { if self.len == 0 { &[] } else { std::slice::from_raw_parts(self.idx.as_ptr() as *const GStringPtr, self.len) } } } } impl Drop for IntoIter { #[inline] fn drop(&mut self) { unsafe { for i in 0..self.len { ffi::g_free(*self.idx.as_ptr().add(i) as ffi::gpointer); } if !self.empty { ffi::g_free(self.ptr.as_ptr() as ffi::gpointer); } } } } impl Iterator for IntoIter { type Item = GString; #[inline] fn next(&mut self) -> Option { if self.len == 0 { return None; } unsafe { let p = self.idx.as_ptr(); self.len -= 1; self.idx = ptr::NonNull::new_unchecked(p.add(1)); Some(GString::from_glib_full(*p)) } } #[inline] fn size_hint(&self) -> (usize, Option) { (self.len, Some(self.len)) } #[inline] fn count(self) -> usize { self.len } #[inline] fn last(mut self) -> Option { if self.len == 0 { None } else { self.len -= 1; Some(unsafe { GString::from_glib_full(*self.idx.as_ptr().add(self.len)) }) } } } impl DoubleEndedIterator for IntoIter { #[inline] fn next_back(&mut self) -> Option { if self.len == 0 { None } else { self.len -= 1; Some(unsafe { GString::from_glib_full(*self.idx.as_ptr().add(self.len)) }) } } } impl ExactSizeIterator for IntoIter {} impl std::iter::FusedIterator for IntoIter {} impl From for Vec { #[inline] fn from(value: StrV) -> Self { value.into_iter().collect() } } impl From> for StrV { #[inline] fn from(value: Vec) -> Self { unsafe { let len = value.len(); let mut s = Self::with_capacity(len); for (i, item) in value.into_iter().enumerate() { *s.ptr.as_ptr().add(i) = GString::from(item).into_glib_ptr(); } s.len = len; *s.ptr.as_ptr().add(s.len) = ptr::null_mut(); s } } } impl From> for StrV { #[inline] fn from(value: Vec<&'_ str>) -> Self { value.as_slice().into() } } impl From> for StrV { #[inline] fn from(value: Vec) -> Self { unsafe { let len = value.len(); let mut s = Self::with_capacity(len); for (i, v) in value.into_iter().enumerate() { *s.ptr.as_ptr().add(i) = v.into_glib_ptr(); } s.len = len; *s.ptr.as_ptr().add(s.len) = ptr::null_mut(); s } } } impl From<[GString; N]> for StrV { #[inline] fn from(value: [GString; N]) -> Self { unsafe { let len = value.len(); let mut s = Self::with_capacity(len); for (i, v) in value.into_iter().enumerate() { *s.ptr.as_ptr().add(i) = v.into_glib_ptr(); } s.len = len; *s.ptr.as_ptr().add(s.len) = ptr::null_mut(); s } } } impl From<[String; N]> for StrV { #[inline] fn from(value: [String; N]) -> Self { unsafe { let len = value.len(); let mut s = Self::with_capacity(len); for (i, v) in value.into_iter().enumerate() { *s.ptr.as_ptr().add(i) = GString::from(v).into_glib_ptr(); } s.len = len; *s.ptr.as_ptr().add(s.len) = ptr::null_mut(); s } } } impl From<[&'_ str; N]> for StrV { #[inline] fn from(value: [&'_ str; N]) -> Self { unsafe { let mut s = Self::with_capacity(value.len()); for (i, item) in value.iter().enumerate() { *s.ptr.as_ptr().add(i) = GString::from(*item).into_glib_ptr(); } s.len = value.len(); *s.ptr.as_ptr().add(s.len) = ptr::null_mut(); s } } } impl From<[&'_ GStr; N]> for StrV { #[inline] fn from(value: [&'_ GStr; N]) -> Self { unsafe { let mut s = Self::with_capacity(value.len()); for (i, item) in value.iter().enumerate() { *s.ptr.as_ptr().add(i) = GString::from(*item).into_glib_ptr(); } s.len = value.len(); *s.ptr.as_ptr().add(s.len) = ptr::null_mut(); s } } } impl From<&'_ [&'_ str]> for StrV { #[inline] fn from(value: &'_ [&'_ str]) -> Self { unsafe { let mut s = Self::with_capacity(value.len()); for (i, item) in value.iter().enumerate() { *s.ptr.as_ptr().add(i) = GString::from(*item).into_glib_ptr(); } s.len = value.len(); *s.ptr.as_ptr().add(s.len) = ptr::null_mut(); s } } } impl From<&'_ [&'_ GStr]> for StrV { #[inline] fn from(value: &'_ [&'_ GStr]) -> Self { unsafe { let mut s = Self::with_capacity(value.len()); for (i, item) in value.iter().enumerate() { *s.ptr.as_ptr().add(i) = GString::from(*item).into_glib_ptr(); } s.len = value.len(); *s.ptr.as_ptr().add(s.len) = ptr::null_mut(); s } } } impl Clone for StrV { #[inline] fn clone(&self) -> Self { unsafe { let mut s = Self::with_capacity(self.len()); for (i, item) in self.iter().enumerate() { *s.ptr.as_ptr().add(i) = GString::from(item.as_str()).into_glib_ptr(); } s.len = self.len(); *s.ptr.as_ptr().add(s.len) = ptr::null_mut(); s } } } impl StrV { // rustdoc-stripper-ignore-next /// Borrows a C array. #[inline] pub unsafe fn from_glib_borrow<'a>(ptr: *const *const c_char) -> &'a [GStringPtr] { let mut len = 0; if !ptr.is_null() { while !(*ptr.add(len)).is_null() { len += 1; } } Self::from_glib_borrow_num(ptr, len) } // rustdoc-stripper-ignore-next /// Borrows a C array. #[inline] pub unsafe fn from_glib_borrow_num<'a>( ptr: *const *const c_char, len: usize, ) -> &'a [GStringPtr] { debug_assert!(!ptr.is_null() || len == 0); if len == 0 { &[] } else { std::slice::from_raw_parts(ptr as *const GStringPtr, len) } } // rustdoc-stripper-ignore-next /// Create a new `StrV` around a C array. #[inline] pub unsafe fn from_glib_none_num( ptr: *const *const c_char, len: usize, _null_terminated: bool, ) -> Self { debug_assert!(!ptr.is_null() || len == 0); if len == 0 { StrV::default() } else { // Allocate space for len + 1 pointers, one pointer for each string and a trailing // null pointer. let new_ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * (len + 1)) as *mut *mut c_char; // Need to clone every item because we don't own it here for i in 0..len { let p = ptr.add(i) as *mut *const c_char; let q = new_ptr.add(i) as *mut *const c_char; *q = ffi::g_strdup(*p); } *new_ptr.add(len) = ptr::null_mut(); StrV { ptr: ptr::NonNull::new_unchecked(new_ptr), len, capacity: len + 1, } } } // rustdoc-stripper-ignore-next /// Create a new `StrV` around a C array. #[inline] pub unsafe fn from_glib_container_num( ptr: *mut *const c_char, len: usize, null_terminated: bool, ) -> Self { debug_assert!(!ptr.is_null() || len == 0); if len == 0 { ffi::g_free(ptr as ffi::gpointer); StrV::default() } else { // Need to clone every item because we don't own it here for i in 0..len { let p = ptr.add(i); *p = ffi::g_strdup(*p); } // And now it can be handled exactly the same as `from_glib_full_num()`. Self::from_glib_full_num(ptr as *mut *mut c_char, len, null_terminated) } } // rustdoc-stripper-ignore-next /// Create a new `StrV` around a C array. #[inline] pub unsafe fn from_glib_full_num( ptr: *mut *mut c_char, len: usize, null_terminated: bool, ) -> Self { debug_assert!(!ptr.is_null() || len == 0); if len == 0 { ffi::g_free(ptr as ffi::gpointer); StrV::default() } else { if null_terminated { return StrV { ptr: ptr::NonNull::new_unchecked(ptr), len, capacity: len + 1, }; } // Need to re-allocate here for adding the NULL-terminator let capacity = len + 1; assert_ne!(capacity, 0); let ptr = ffi::g_realloc( ptr as *mut _, mem::size_of::<*mut c_char>().checked_mul(capacity).unwrap(), ) as *mut *mut c_char; *ptr.add(len) = ptr::null_mut(); StrV { ptr: ptr::NonNull::new_unchecked(ptr), len, capacity, } } } // rustdoc-stripper-ignore-next /// Create a new `StrV` around a `NULL`-terminated C array. #[inline] pub unsafe fn from_glib_none(ptr: *const *const c_char) -> Self { let mut len = 0; if !ptr.is_null() { while !(*ptr.add(len)).is_null() { len += 1; } } StrV::from_glib_none_num(ptr, len, true) } // rustdoc-stripper-ignore-next /// Create a new `StrV` around a `NULL`-terminated C array. #[inline] pub unsafe fn from_glib_container(ptr: *mut *const c_char) -> Self { let mut len = 0; if !ptr.is_null() { while !(*ptr.add(len)).is_null() { len += 1; } } StrV::from_glib_container_num(ptr, len, true) } // rustdoc-stripper-ignore-next /// Create a new `StrV` around a `NULL`-terminated C array. #[inline] pub unsafe fn from_glib_full(ptr: *mut *mut c_char) -> Self { let mut len = 0; if !ptr.is_null() { while !(*ptr.add(len)).is_null() { len += 1; } } StrV::from_glib_full_num(ptr, len, true) } // rustdoc-stripper-ignore-next /// Creates a new empty slice. #[inline] pub fn new() -> Self { StrV { ptr: ptr::NonNull::dangling(), len: 0, capacity: 0, } } // rustdoc-stripper-ignore-next /// Creates a new empty slice with the given capacity. #[inline] pub fn with_capacity(capacity: usize) -> Self { let mut s = Self::new(); s.reserve(capacity); s } // rustdoc-stripper-ignore-next /// Returns the underlying pointer. /// /// This is guaranteed to be `NULL`-terminated. #[inline] pub fn as_ptr(&self) -> *const *mut c_char { if self.len == 0 { static EMPTY: [usize; 1] = [0]; EMPTY.as_ptr() as *const _ } else { self.ptr.as_ptr() } } // rustdoc-stripper-ignore-next /// Consumes the slice and returns the underlying pointer. /// /// This is guaranteed to be `NULL`-terminated. #[inline] pub fn into_raw(mut self) -> *mut *mut c_char { if self.len == 0 { ptr::null_mut() } else { self.len = 0; self.capacity = 0; self.ptr.as_ptr() } } // rustdoc-stripper-ignore-next /// Gets the length of the slice. #[inline] pub fn len(&self) -> usize { self.len } // rustdoc-stripper-ignore-next /// Returns `true` if the slice is empty. #[inline] pub fn is_empty(&self) -> bool { self.len == 0 } // rustdoc-stripper-ignore-next /// Returns the capacity of the slice. /// /// This includes the space that is reserved for the `NULL`-terminator. #[inline] pub fn capacity(&self) -> usize { self.capacity } // rustdoc-stripper-ignore-next /// Sets the length of the slice to `len`. /// /// # SAFETY /// /// There must be at least `len` valid items and a `NULL`-terminator after the last item. pub unsafe fn set_len(&mut self, len: usize) { self.len = len; } // rustdoc-stripper-ignore-next /// Reserves at least this much additional capacity. #[allow(clippy::int_plus_one)] pub fn reserve(&mut self, additional: usize) { // Nothing new to reserve as there's still enough space if self.len + additional + 1 <= self.capacity { return; } let new_capacity = usize::next_power_of_two(std::cmp::max(self.len + additional, MIN_SIZE) + 1); assert_ne!(new_capacity, 0); assert!(new_capacity > self.capacity); unsafe { let ptr = if self.capacity == 0 { ptr::null_mut() } else { self.ptr.as_ptr() as *mut _ }; let new_ptr = ffi::g_realloc( ptr, mem::size_of::<*mut c_char>() .checked_mul(new_capacity) .unwrap(), ) as *mut *mut c_char; if self.capacity == 0 { *new_ptr = ptr::null_mut(); } self.ptr = ptr::NonNull::new_unchecked(new_ptr); self.capacity = new_capacity; } } // rustdoc-stripper-ignore-next /// Borrows this slice as a `&[GStringPtr]`. #[inline] pub const fn as_slice(&self) -> &[GStringPtr] { unsafe { if self.len == 0 { &[] } else { std::slice::from_raw_parts(self.ptr.as_ptr() as *const GStringPtr, self.len) } } } // rustdoc-stripper-ignore-next /// Removes all items from the slice. #[inline] pub fn clear(&mut self) { unsafe { for i in 0..self.len { ffi::g_free(*self.ptr.as_ptr().add(i) as ffi::gpointer); } self.len = 0; } } // rustdoc-stripper-ignore-next /// Clones and appends all elements in `slice` to the slice. #[inline] pub fn extend_from_slice>(&mut self, other: &[S]) { // Nothing new to reserve as there's still enough space if self.len + other.len() + 1 > self.capacity { self.reserve(other.len()); } unsafe { for item in other { *self.ptr.as_ptr().add(self.len) = GString::from(item.as_ref()).into_glib_ptr(); self.len += 1; } *self.ptr.as_ptr().add(self.len) = ptr::null_mut(); } } // rustdoc-stripper-ignore-next /// Inserts `item` at position `index` of the slice, shifting all elements after it to the /// right. #[inline] pub fn insert(&mut self, index: usize, item: GString) { assert!(index <= self.len); // Nothing new to reserve as there's still enough space if self.len + 1 + 1 > self.capacity { self.reserve(1); } unsafe { if index == self.len { *self.ptr.as_ptr().add(self.len) = item.into_glib_ptr(); } else { let p = self.ptr.as_ptr().add(index); ptr::copy(p, p.add(1), self.len - index); *self.ptr.as_ptr().add(index) = item.into_glib_ptr(); } self.len += 1; *self.ptr.as_ptr().add(self.len) = ptr::null_mut(); } } // rustdoc-stripper-ignore-next /// Pushes `item` to the end of the slice. #[inline] pub fn push(&mut self, item: GString) { // Nothing new to reserve as there's still enough space if self.len + 1 + 1 > self.capacity { self.reserve(1); } unsafe { *self.ptr.as_ptr().add(self.len) = item.into_glib_ptr(); self.len += 1; *self.ptr.as_ptr().add(self.len) = ptr::null_mut(); } } // rustdoc-stripper-ignore-next /// Removes item from position `index` of the slice, shifting all elements after it to the /// left. #[inline] pub fn remove(&mut self, index: usize) -> GString { assert!(index < self.len); unsafe { let p = self.ptr.as_ptr().add(index); let item = *p; ptr::copy(p.add(1), p, self.len - index - 1); self.len -= 1; *self.ptr.as_ptr().add(self.len) = ptr::null_mut(); GString::from_glib_full(item) } } // rustdoc-stripper-ignore-next /// Swaps item from position `index` of the slice and returns it. #[inline] pub fn swap(&mut self, index: usize, new_item: GString) -> GString { assert!(index < self.len); unsafe { let p = self.ptr.as_ptr().add(index); let item = *p; *p = new_item.into_glib_ptr(); GString::from_glib_full(item) } } // rustdoc-stripper-ignore-next /// Removes the last item of the slice and returns it. #[inline] pub fn pop(&mut self) -> Option { if self.len == 0 { return None; } unsafe { self.len -= 1; let p = self.ptr.as_ptr().add(self.len); let item = *p; *self.ptr.as_ptr().add(self.len) = ptr::null_mut(); Some(GString::from_glib_full(item)) } } // rustdoc-stripper-ignore-next /// Shortens the slice by keeping the last `len` items. /// /// If there are fewer than `len` items then this has no effect. #[inline] pub fn truncate(&mut self, len: usize) { if self.len <= len { return; } unsafe { while self.len > len { self.len -= 1; let p = self.ptr.as_ptr().add(self.len); ffi::g_free(*p as ffi::gpointer); *p = ptr::null_mut(); } } } // rustdoc-stripper-ignore-next /// Joins the strings into a longer string, with an optional separator #[inline] #[doc(alias = "g_strjoinv")] pub fn join(&self, separator: Option) -> GString { separator.run_with_gstr(|separator| unsafe { from_glib_full(ffi::g_strjoinv( separator.to_glib_none().0, self.as_ptr() as *mut _, )) }) } // rustdoc-stripper-ignore-next /// Checks whether the `StrV` contains the specified string #[inline] #[doc(alias = "g_strv_contains")] pub fn contains(&self, s: impl IntoGStr) -> bool { s.run_with_gstr(|s| unsafe { from_glib(ffi::g_strv_contains( self.as_ptr() as *const _, s.to_glib_none().0, )) }) } } impl FromGlibContainer<*mut c_char, *mut *mut c_char> for StrV { #[inline] unsafe fn from_glib_none_num(ptr: *mut *mut c_char, num: usize) -> Self { Self::from_glib_none_num(ptr as *const *const c_char, num, false) } #[inline] unsafe fn from_glib_container_num(ptr: *mut *mut c_char, num: usize) -> Self { Self::from_glib_container_num(ptr as *mut *const c_char, num, false) } #[inline] unsafe fn from_glib_full_num(ptr: *mut *mut c_char, num: usize) -> Self { Self::from_glib_full_num(ptr, num, false) } } impl FromGlibContainer<*mut c_char, *const *mut c_char> for StrV { unsafe fn from_glib_none_num(ptr: *const *mut c_char, num: usize) -> Self { Self::from_glib_none_num(ptr as *const *const c_char, num, false) } unsafe fn from_glib_container_num(_ptr: *const *mut c_char, _num: usize) -> Self { unimplemented!(); } unsafe fn from_glib_full_num(_ptr: *const *mut c_char, _num: usize) -> Self { unimplemented!(); } } impl FromGlibPtrContainer<*mut c_char, *mut *mut c_char> for StrV { #[inline] unsafe fn from_glib_none(ptr: *mut *mut c_char) -> Self { Self::from_glib_none(ptr as *const *const c_char) } #[inline] unsafe fn from_glib_container(ptr: *mut *mut c_char) -> Self { Self::from_glib_container(ptr as *mut *const c_char) } #[inline] unsafe fn from_glib_full(ptr: *mut *mut c_char) -> Self { Self::from_glib_full(ptr) } } impl FromGlibPtrContainer<*mut c_char, *const *mut c_char> for StrV { #[inline] unsafe fn from_glib_none(ptr: *const *mut c_char) -> Self { Self::from_glib_none(ptr as *const *const c_char) } unsafe fn from_glib_container(_ptr: *const *mut c_char) -> Self { unimplemented!(); } unsafe fn from_glib_full(_ptr: *const *mut c_char) -> Self { unimplemented!(); } } impl<'a> ToGlibPtr<'a, *mut *mut c_char> for StrV { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut *mut c_char, Self> { Stash(self.as_ptr() as *mut _, PhantomData) } #[inline] fn to_glib_container(&'a self) -> Stash<'a, *mut *mut c_char, Self> { unsafe { let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * (self.len() + 1)) as *mut *mut c_char; ptr::copy_nonoverlapping(self.as_ptr(), ptr, self.len() + 1); Stash(ptr, PhantomData) } } #[inline] fn to_glib_full(&self) -> *mut *mut c_char { self.clone().into_raw() } } impl<'a> ToGlibPtr<'a, *const *mut c_char> for StrV { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const *mut c_char, Self> { Stash(self.as_ptr(), PhantomData) } } impl IntoGlibPtr<*mut *mut c_char> for StrV { #[inline] unsafe fn into_glib_ptr(self) -> *mut *mut c_char { self.into_raw() } } impl StaticType for StrV { #[inline] fn static_type() -> crate::Type { >::static_type() } } impl StaticType for &'_ [GStringPtr] { #[inline] fn static_type() -> crate::Type { >::static_type() } } impl crate::value::ValueType for StrV { type Type = Vec; } unsafe impl<'a> crate::value::FromValue<'a> for StrV { type Checker = crate::value::GenericValueTypeChecker; unsafe fn from_value(value: &'a crate::value::Value) -> Self { let ptr = gobject_ffi::g_value_dup_boxed(value.to_glib_none().0) as *mut *mut c_char; FromGlibPtrContainer::from_glib_full(ptr) } } unsafe impl<'a> crate::value::FromValue<'a> for &'a [GStringPtr] { type Checker = crate::value::GenericValueTypeChecker; unsafe fn from_value(value: &'a crate::value::Value) -> Self { let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char; StrV::from_glib_borrow(ptr) } } impl crate::value::ToValue for StrV { fn to_value(&self) -> crate::value::Value { unsafe { let mut value = crate::value::Value::for_value_type::(); gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, self.as_ptr() as ffi::gpointer, ); value } } fn value_type(&self) -> crate::Type { ::static_type() } } impl From for crate::Value { #[inline] fn from(s: StrV) -> Self { unsafe { let mut value = crate::value::Value::for_value_type::(); gobject_ffi::g_value_take_boxed( value.to_glib_none_mut().0, s.into_raw() as ffi::gpointer, ); value } } } // rustdoc-stripper-ignore-next /// A trait to accept both `&[T]` or `StrV` as an argument. pub trait IntoStrV { // rustdoc-stripper-ignore-next /// Runs the given closure with a `NULL`-terminated array. fn run_with_strv R>(self, f: F) -> R; } impl IntoStrV for StrV { #[inline] fn run_with_strv R>(self, f: F) -> R { <&Self>::run_with_strv(&self, f) } } impl IntoStrV for &'_ StrV { #[inline] fn run_with_strv R>(self, f: F) -> R { f(unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len()) }) } } // rustdoc-stripper-ignore-next /// Maximum number of pointers to stack-allocate before falling back to a heap allocation. /// /// The beginning will be used for the pointers, the remainder for the actual string content. const MAX_STACK_ALLOCATION: usize = 16; impl IntoStrV for Vec { #[inline] fn run_with_strv R>(self, f: F) -> R { self.as_slice().run_with_strv(f) } } impl IntoStrV for Vec<&'_ GString> { #[inline] fn run_with_strv R>(self, f: F) -> R { self.as_slice().run_with_strv(f) } } impl IntoStrV for Vec<&'_ GStr> { #[inline] fn run_with_strv R>(self, f: F) -> R { self.as_slice().run_with_strv(f) } } impl IntoStrV for Vec<&'_ str> { #[inline] fn run_with_strv R>(self, f: F) -> R { self.as_slice().run_with_strv(f) } } impl IntoStrV for Vec { #[inline] fn run_with_strv R>(self, f: F) -> R { self.as_slice().run_with_strv(f) } } impl IntoStrV for Vec<&'_ String> { #[inline] fn run_with_strv R>(self, f: F) -> R { self.as_slice().run_with_strv(f) } } impl IntoStrV for &[GString] { #[inline] fn run_with_strv R>(self, f: F) -> R { let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>(); if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() { unsafe { let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit(); let ptrs = s.as_mut_ptr() as *mut *mut c_char; for (i, item) in self.iter().enumerate() { *ptrs.add(i) = item.as_ptr() as *mut _; } *ptrs.add(self.len()) = ptr::null_mut(); f(std::slice::from_raw_parts(ptrs, self.len())) } } else { let mut s = StrV::with_capacity(self.len()); s.extend_from_slice(self); s.run_with_strv(f) } } } impl IntoStrV for &[&GString] { #[inline] fn run_with_strv R>(self, f: F) -> R { let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>(); if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() { unsafe { let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit(); let ptrs = s.as_mut_ptr() as *mut *mut c_char; for (i, item) in self.iter().enumerate() { *ptrs.add(i) = item.as_ptr() as *mut _; } *ptrs.add(self.len()) = ptr::null_mut(); f(std::slice::from_raw_parts(ptrs, self.len())) } } else { let mut s = StrV::with_capacity(self.len()); s.extend_from_slice(self); s.run_with_strv(f) } } } impl IntoStrV for &[&GStr] { #[inline] fn run_with_strv R>(self, f: F) -> R { let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>(); if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() { unsafe { let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit(); let ptrs = s.as_mut_ptr() as *mut *mut c_char; for (i, item) in self.iter().enumerate() { *ptrs.add(i) = item.as_ptr() as *mut _; } *ptrs.add(self.len()) = ptr::null_mut(); f(std::slice::from_raw_parts(ptrs, self.len())) } } else { let mut s = StrV::with_capacity(self.len()); s.extend_from_slice(self); s.run_with_strv(f) } } } impl IntoStrV for &[&str] { #[inline] fn run_with_strv R>(self, f: F) -> R { let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>() + self.iter().map(|s| s.len() + 1).sum::(); if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() { unsafe { let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit(); let ptrs = s.as_mut_ptr() as *mut *mut c_char; let mut strs = ptrs.add(self.len() + 1) as *mut c_char; for (i, item) in self.iter().enumerate() { ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len()); *strs.add(item.len()) = 0; *ptrs.add(i) = strs; strs = strs.add(item.len() + 1); } *ptrs.add(self.len()) = ptr::null_mut(); f(std::slice::from_raw_parts(ptrs, self.len())) } } else { let mut s = StrV::with_capacity(self.len()); s.extend_from_slice(self); s.run_with_strv(f) } } } impl IntoStrV for &[String] { #[inline] fn run_with_strv R>(self, f: F) -> R { let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>() + self.iter().map(|s| s.len() + 1).sum::(); if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() { unsafe { let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit(); let ptrs = s.as_mut_ptr() as *mut *mut c_char; let mut strs = ptrs.add(self.len() + 1) as *mut c_char; for (i, item) in self.iter().enumerate() { ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len()); *strs.add(item.len()) = 0; *ptrs.add(i) = strs; strs = strs.add(item.len() + 1); } *ptrs.add(self.len()) = ptr::null_mut(); f(std::slice::from_raw_parts(ptrs, self.len())) } } else { let mut s = StrV::with_capacity(self.len()); s.extend_from_slice(self); s.run_with_strv(f) } } } impl IntoStrV for &[&String] { #[inline] fn run_with_strv R>(self, f: F) -> R { let required_len = (self.len() + 1) * mem::size_of::<*mut c_char>() + self.iter().map(|s| s.len() + 1).sum::(); if required_len < MAX_STACK_ALLOCATION * mem::size_of::<*mut c_char>() { unsafe { let mut s = mem::MaybeUninit::<[*mut c_char; MAX_STACK_ALLOCATION]>::uninit(); let ptrs = s.as_mut_ptr() as *mut *mut c_char; let mut strs = ptrs.add(self.len() + 1) as *mut c_char; for (i, item) in self.iter().enumerate() { ptr::copy_nonoverlapping(item.as_ptr() as *const _, strs, item.len()); *strs.add(item.len()) = 0; *ptrs.add(i) = strs; strs = strs.add(item.len() + 1); } *ptrs.add(self.len()) = ptr::null_mut(); f(std::slice::from_raw_parts(ptrs, self.len())) } } else { let mut s = StrV::with_capacity(self.len()); s.extend_from_slice(self); s.run_with_strv(f) } } } impl IntoStrV for [GString; N] { #[inline] fn run_with_strv R>(self, f: F) -> R { self.as_slice().run_with_strv(f) } } impl IntoStrV for [&'_ GString; N] { #[inline] fn run_with_strv R>(self, f: F) -> R { self.as_slice().run_with_strv(f) } } impl IntoStrV for [&'_ GStr; N] { #[inline] fn run_with_strv R>(self, f: F) -> R { self.as_slice().run_with_strv(f) } } impl IntoStrV for [&'_ str; N] { #[inline] fn run_with_strv R>(self, f: F) -> R { self.as_slice().run_with_strv(f) } } impl IntoStrV for [String; N] { #[inline] fn run_with_strv R>(self, f: F) -> R { self.as_slice().run_with_strv(f) } } impl IntoStrV for [&'_ String; N] { #[inline] fn run_with_strv R>(self, f: F) -> R { self.as_slice().run_with_strv(f) } } #[cfg(test)] mod test { use super::*; #[test] fn test_from_glib_full() { let items = ["str1", "str2", "str3", "str4"]; let slice = unsafe { let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * 4) as *mut *mut c_char; *ptr.add(0) = items[0].to_glib_full(); *ptr.add(1) = items[1].to_glib_full(); *ptr.add(2) = items[2].to_glib_full(); *ptr.add(3) = items[3].to_glib_full(); StrV::from_glib_full_num(ptr, 4, false) }; for (a, b) in Iterator::zip(items.iter(), slice.iter()) { assert_eq!(a, b); } } #[test] fn test_from_glib_container() { let items = [ crate::gstr!("str1"), crate::gstr!("str2"), crate::gstr!("str3"), crate::gstr!("str4"), ]; let slice = unsafe { let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * 4) as *mut *const c_char; *ptr.add(0) = items[0].as_ptr(); *ptr.add(1) = items[1].as_ptr(); *ptr.add(2) = items[2].as_ptr(); *ptr.add(3) = items[3].as_ptr(); StrV::from_glib_container_num(ptr, 4, false) }; for (a, b) in Iterator::zip(items.iter(), slice.iter()) { assert_eq!(a, b); } } #[test] fn test_from_glib_none() { let items = [ crate::gstr!("str1"), crate::gstr!("str2"), crate::gstr!("str3"), crate::gstr!("str4"), ]; let slice = unsafe { let ptr = ffi::g_malloc(mem::size_of::<*mut c_char>() * 4) as *mut *const c_char; *ptr.add(0) = items[0].as_ptr(); *ptr.add(1) = items[1].as_ptr(); *ptr.add(2) = items[2].as_ptr(); *ptr.add(3) = items[3].as_ptr(); let res = StrV::from_glib_none_num(ptr, 4, false); ffi::g_free(ptr as ffi::gpointer); res }; for (a, b) in Iterator::zip(items.iter(), slice.iter()) { assert_eq!(a, b); } } #[test] fn test_from_slice() { let items = [ crate::gstr!("str1"), crate::gstr!("str2"), crate::gstr!("str3"), ]; let slice1 = StrV::from(&items[..]); let slice2 = StrV::from(items); assert_eq!(slice1.len(), 3); assert_eq!(slice1, slice2); } #[test] fn test_safe_api() { let items = [ crate::gstr!("str1"), crate::gstr!("str2"), crate::gstr!("str3"), ]; let mut slice = StrV::from(&items[..]); assert_eq!(slice.len(), 3); slice.push(GString::from("str4")); assert_eq!(slice.len(), 4); for (a, b) in Iterator::zip(items.iter(), slice.iter()) { assert_eq!(a, b); } assert_eq!(slice[3], "str4"); let vec = Vec::from(slice); assert_eq!(vec.len(), 4); for (a, b) in Iterator::zip(items.iter(), vec.iter()) { assert_eq!(a, b); } assert_eq!(vec[3], "str4"); let mut slice = StrV::from(vec); assert_eq!(slice.len(), 4); let e = slice.pop().unwrap(); assert_eq!(e, "str4"); assert_eq!(slice.len(), 3); slice.insert(2, e); assert_eq!(slice.len(), 4); assert_eq!(slice[0], "str1"); assert_eq!(slice[1], "str2"); assert_eq!(slice[2], "str4"); assert_eq!(slice[3], "str3"); let e = slice.remove(2); assert_eq!(e, "str4"); assert_eq!(slice.len(), 3); slice.push(e); assert_eq!(slice.len(), 4); for (a, b) in Iterator::zip(items.iter(), slice.into_iter()) { assert_eq!(*a, b); } } #[test] fn test_into_strv() { let items = ["str1", "str2", "str3", "str4"]; items[..].run_with_strv(|s| unsafe { assert!((*s.as_ptr().add(4)).is_null()); assert_eq!(s.len(), items.len()); let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char); assert_eq!(s, items); }); Vec::from(&items[..]).run_with_strv(|s| unsafe { assert!((*s.as_ptr().add(4)).is_null()); assert_eq!(s.len(), items.len()); let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char); assert_eq!(s, items); }); StrV::from(&items[..]).run_with_strv(|s| unsafe { assert!((*s.as_ptr().add(4)).is_null()); assert_eq!(s.len(), items.len()); let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char); assert_eq!(s, items); }); let v = items.iter().copied().map(String::from).collect::>(); items.run_with_strv(|s| unsafe { assert!((*s.as_ptr().add(4)).is_null()); assert_eq!(s.len(), v.len()); let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char); assert_eq!(s, items); }); let v = items.iter().copied().map(GString::from).collect::>(); items.run_with_strv(|s| unsafe { assert!((*s.as_ptr().add(4)).is_null()); assert_eq!(s.len(), v.len()); let s = StrV::from_glib_borrow(s.as_ptr() as *const *const c_char); assert_eq!(s, items); }); } #[test] fn test_join() { let items = [ crate::gstr!("str1"), crate::gstr!("str2"), crate::gstr!("str3"), ]; let strv = StrV::from(&items[..]); assert_eq!(strv.join(None::<&str>), "str1str2str3"); assert_eq!(strv.join(Some(",")), "str1,str2,str3"); } #[test] fn test_contains() { let items = [ crate::gstr!("str1"), crate::gstr!("str2"), crate::gstr!("str3"), ]; let strv = StrV::from(&items[..]); assert!(strv.contains("str2")); assert!(!strv.contains("str4")); } } glib-0.20.9/src/control_flow.rs000064400000000000000000000052071046102023000145010ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::{ffi, prelude::*, translate::*}; // rustdoc-stripper-ignore-next /// Continue calling the closure in the future iterations or drop it. /// /// This is the return type of `idle_add` and `timeout_add` closures. /// /// `ControlFlow::Continue` keeps the closure assigned, to be rerun when appropriate. /// /// `ControlFlow::Break` disconnects and drops it. /// /// `Continue` and `Break` map to `G_SOURCE_CONTINUE` (`true`) and /// `G_SOURCE_REMOVE` (`false`), respectively. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum ControlFlow { #[doc(alias = "G_SOURCE_CONTINUE")] Continue, #[doc(alias = "G_SOURCE_REMOVE")] Break, } impl ControlFlow { // rustdoc-stripper-ignore-next /// Returns `true` if this is a `Continue` variant. pub fn is_continue(&self) -> bool { matches!(self, Self::Continue) } // rustdoc-stripper-ignore-next /// Returns `true` if this is a `Break` variant. pub fn is_break(&self) -> bool { matches!(self, Self::Break) } } impl From> for ControlFlow { fn from(c: std::ops::ControlFlow<()>) -> Self { match c { std::ops::ControlFlow::Break(_) => Self::Break, std::ops::ControlFlow::Continue(_) => Self::Continue, } } } impl From for std::ops::ControlFlow<()> { fn from(c: ControlFlow) -> Self { match c { ControlFlow::Break => Self::Break(()), ControlFlow::Continue => Self::Continue(()), } } } impl From for ControlFlow { fn from(c: bool) -> Self { if c { Self::Continue } else { Self::Break } } } impl From for bool { fn from(c: ControlFlow) -> Self { match c { ControlFlow::Break => false, ControlFlow::Continue => true, } } } #[doc(hidden)] impl IntoGlib for ControlFlow { type GlibType = ffi::gboolean; #[inline] fn into_glib(self) -> ffi::gboolean { bool::from(self).into_glib() } } #[doc(hidden)] impl FromGlib for ControlFlow { #[inline] unsafe fn from_glib(value: ffi::gboolean) -> Self { bool::from_glib(value).into() } } impl crate::value::ToValue for ControlFlow { fn to_value(&self) -> crate::Value { bool::from(*self).to_value() } fn value_type(&self) -> crate::Type { ::static_type() } } impl From for crate::Value { #[inline] fn from(v: ControlFlow) -> Self { bool::from(v).into() } } glib-0.20.9/src/convert.rs000064400000000000000000000351431046102023000134540ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{fmt, io, os::raw::c_char, path::PathBuf, ptr}; use crate::{ffi, translate::*, ConvertError, Error, GString, NormalizeMode, Slice}; // rustdoc-stripper-ignore-next /// A wrapper for [`ConvertError`](crate::ConvertError) that can hold an offset into the input /// string. #[derive(Debug)] pub enum CvtError { Convert(Error), IllegalSequence { source: Error, offset: usize }, } impl std::error::Error for CvtError { fn source(&self) -> ::core::option::Option<&(dyn std::error::Error + 'static)> { match self { CvtError::Convert(err) => std::error::Error::source(err), CvtError::IllegalSequence { source, .. } => Some(source), } } } impl fmt::Display for CvtError { fn fmt(&self, fmt: &mut fmt::Formatter) -> ::core::fmt::Result { match self { CvtError::Convert(err) => fmt::Display::fmt(err, fmt), CvtError::IllegalSequence { source, offset } => { write!(fmt, "{source} at offset {offset}") } } } } impl std::convert::From for CvtError { fn from(err: Error) -> Self { CvtError::Convert(err) } } impl CvtError { #[inline] fn new(err: Error, bytes_read: usize) -> Self { if err.kind::() == Some(ConvertError::IllegalSequence) { Self::IllegalSequence { source: err, offset: bytes_read, } } else { err.into() } } } #[doc(alias = "g_convert")] pub fn convert( str_: &[u8], to_codeset: impl IntoGStr, from_codeset: impl IntoGStr, ) -> Result<(Slice, usize), CvtError> { assert!(str_.len() <= isize::MAX as usize); let mut bytes_read = 0; let mut bytes_written = 0; let mut error = ptr::null_mut(); let result = to_codeset.run_with_gstr(|to_codeset| { from_codeset.run_with_gstr(|from_codeset| unsafe { ffi::g_convert( str_.as_ptr(), str_.len() as isize, to_codeset.to_glib_none().0, from_codeset.to_glib_none().0, &mut bytes_read, &mut bytes_written, &mut error, ) }) }); if result.is_null() { Err(CvtError::new(unsafe { from_glib_full(error) }, bytes_read)) } else { let slice = unsafe { Slice::from_glib_full_num(result, bytes_written as _) }; Ok((slice, bytes_read)) } } #[doc(alias = "g_convert_with_fallback")] pub fn convert_with_fallback( str_: &[u8], to_codeset: impl IntoGStr, from_codeset: impl IntoGStr, fallback: Option, ) -> Result<(Slice, usize), CvtError> { assert!(str_.len() <= isize::MAX as usize); let mut bytes_read = 0; let mut bytes_written = 0; let mut error = ptr::null_mut(); let result = to_codeset.run_with_gstr(|to_codeset| { from_codeset.run_with_gstr(|from_codeset| { fallback.run_with_gstr(|fallback| unsafe { ffi::g_convert_with_fallback( str_.as_ptr(), str_.len() as isize, to_codeset.to_glib_none().0, from_codeset.to_glib_none().0, fallback.to_glib_none().0, &mut bytes_read, &mut bytes_written, &mut error, ) }) }) }); if result.is_null() { Err(CvtError::new(unsafe { from_glib_full(error) }, bytes_read)) } else { let slice = unsafe { Slice::from_glib_full_num(result, bytes_written as _) }; Ok((slice, bytes_read)) } } // rustdoc-stripper-ignore-next /// A wrapper for [`std::io::Error`] that can hold an offset into an input string. #[derive(Debug)] pub enum IConvError { Error(io::Error), WithOffset { source: io::Error, offset: usize }, } impl std::error::Error for IConvError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { IConvError::Error(err) => std::error::Error::source(err), IConvError::WithOffset { source, .. } => Some(source), } } } impl fmt::Display for IConvError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { IConvError::Error(err) => fmt::Display::fmt(err, fmt), IConvError::WithOffset { source, offset } => write!(fmt, "{source} at offset {offset}"), } } } impl std::convert::From for IConvError { fn from(err: io::Error) -> Self { IConvError::Error(err) } } #[derive(Debug)] #[repr(transparent)] #[doc(alias = "GIConv")] pub struct IConv(ffi::GIConv); unsafe impl Send for IConv {} impl IConv { #[doc(alias = "g_iconv_open")] #[allow(clippy::unnecessary_lazy_evaluations)] pub fn new(to_codeset: impl IntoGStr, from_codeset: impl IntoGStr) -> Option { let iconv = to_codeset.run_with_gstr(|to_codeset| { from_codeset.run_with_gstr(|from_codeset| unsafe { ffi::g_iconv_open(to_codeset.to_glib_none().0, from_codeset.to_glib_none().0) }) }); (iconv as isize != -1).then(|| Self(iconv)) } #[doc(alias = "g_convert_with_iconv")] pub fn convert(&mut self, str_: &[u8]) -> Result<(Slice, usize), CvtError> { assert!(str_.len() <= isize::MAX as usize); let mut bytes_read = 0; let mut bytes_written = 0; let mut error = ptr::null_mut(); let result = unsafe { ffi::g_convert_with_iconv( str_.as_ptr(), str_.len() as isize, self.0, &mut bytes_read, &mut bytes_written, &mut error, ) }; if result.is_null() { Err(CvtError::new(unsafe { from_glib_full(error) }, bytes_read)) } else { let slice = unsafe { Slice::from_glib_full_num(result, bytes_written as _) }; Ok((slice, bytes_read)) } } #[doc(alias = "g_iconv")] pub fn iconv( &mut self, inbuf: Option<&[u8]>, outbuf: Option<&mut [std::mem::MaybeUninit]>, ) -> Result<(usize, usize, usize), IConvError> { let input_len = inbuf.as_ref().map(|b| b.len()).unwrap_or_default(); let mut inbytes_left = input_len; let mut outbytes_left = outbuf.as_ref().map(|b| b.len()).unwrap_or_default(); let mut inbuf = inbuf .map(|b| mut_override(b.as_ptr()) as *mut c_char) .unwrap_or_else(ptr::null_mut); let mut outbuf = outbuf .map(|b| b.as_mut_ptr() as *mut c_char) .unwrap_or_else(ptr::null_mut); let conversions = unsafe { ffi::g_iconv( self.0, &mut inbuf, &mut inbytes_left, &mut outbuf, &mut outbytes_left, ) }; if conversions as isize == -1 { let err = io::Error::last_os_error(); let code = err.raw_os_error().unwrap(); if code == libc::EILSEQ || code == libc::EINVAL { Err(IConvError::WithOffset { source: err, offset: input_len - inbytes_left, }) } else { Err(err.into()) } } else { Ok((conversions, inbytes_left, outbytes_left)) } } } impl Drop for IConv { #[inline] fn drop(&mut self) { unsafe { ffi::g_iconv_close(self.0); } } } #[doc(alias = "g_get_filename_charsets")] #[doc(alias = "get_filename_charsets")] pub fn filename_charsets() -> (bool, Vec) { let mut filename_charsets = ptr::null_mut(); unsafe { let is_utf8 = ffi::g_get_filename_charsets(&mut filename_charsets); ( from_glib(is_utf8), FromGlibPtrContainer::from_glib_none(filename_charsets), ) } } #[doc(alias = "g_filename_from_utf8")] pub fn filename_from_utf8(utf8string: impl IntoGStr) -> Result<(PathBuf, usize), CvtError> { let mut bytes_read = 0; let mut bytes_written = std::mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let ret = utf8string.run_with_gstr(|utf8string| { assert!(utf8string.len() <= isize::MAX as usize); let len = utf8string.len() as isize; unsafe { ffi::g_filename_from_utf8( utf8string.to_glib_none().0, len, &mut bytes_read, bytes_written.as_mut_ptr(), &mut error, ) } }); if error.is_null() { Ok(unsafe { ( PathBuf::from_glib_full_num(ret, bytes_written.assume_init()), bytes_read, ) }) } else { Err(unsafe { CvtError::new(from_glib_full(error), bytes_read) }) } } #[doc(alias = "g_filename_to_utf8")] pub fn filename_to_utf8( opsysstring: impl AsRef, ) -> Result<(crate::GString, usize), CvtError> { let path = opsysstring.as_ref().to_glib_none(); let mut bytes_read = 0; let mut bytes_written = std::mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let ret = unsafe { ffi::g_filename_to_utf8( path.0, path.1.as_bytes().len() as isize, &mut bytes_read, bytes_written.as_mut_ptr(), &mut error, ) }; if error.is_null() { Ok(unsafe { ( GString::from_glib_full_num(ret, bytes_written.assume_init()), bytes_read, ) }) } else { Err(unsafe { CvtError::new(from_glib_full(error), bytes_read) }) } } #[doc(alias = "g_locale_from_utf8")] pub fn locale_from_utf8(utf8string: impl IntoGStr) -> Result<(Slice, usize), CvtError> { let mut bytes_read = 0; let mut bytes_written = std::mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let ret = utf8string.run_with_gstr(|utf8string| { assert!(utf8string.len() <= isize::MAX as usize); unsafe { ffi::g_locale_from_utf8( utf8string.as_ptr(), utf8string.len() as isize, &mut bytes_read, bytes_written.as_mut_ptr(), &mut error, ) } }); if error.is_null() { Ok(unsafe { ( Slice::from_glib_full_num(ret, bytes_written.assume_init() + 1), bytes_read, ) }) } else { Err(unsafe { CvtError::new(from_glib_full(error), bytes_read) }) } } #[doc(alias = "g_locale_to_utf8")] pub fn locale_to_utf8(opsysstring: &[u8]) -> Result<(crate::GString, usize), CvtError> { let len = opsysstring.len() as isize; let mut bytes_read = 0; let mut bytes_written = std::mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let ret = unsafe { ffi::g_locale_to_utf8( opsysstring.to_glib_none().0, len, &mut bytes_read, bytes_written.as_mut_ptr(), &mut error, ) }; if error.is_null() { Ok(unsafe { ( GString::from_glib_full_num(ret, bytes_written.assume_init()), bytes_read, ) }) } else { Err(unsafe { CvtError::new(from_glib_full(error), bytes_read) }) } } #[doc(alias = "g_utf8_to_ucs4")] #[doc(alias = "g_utf8_to_ucs4_fast")] #[doc(alias = "utf8_to_ucs4")] pub fn utf8_to_utf32(str: impl AsRef) -> Slice { unsafe { let mut items_written = 0; let str_as_utf32 = ffi::g_utf8_to_ucs4_fast( str.as_ref().as_ptr().cast::(), str.as_ref().len() as _, &mut items_written, ); // NOTE: We assume that u32 and char have the same layout and trust that glib won't give us // invalid UTF-32 codepoints Slice::from_glib_full_num(str_as_utf32, items_written as usize) } } #[doc(alias = "g_ucs4_to_utf8")] #[doc(alias = "ucs4_to_utf8")] pub fn utf32_to_utf8(str: impl AsRef<[char]>) -> GString { let mut items_read = 0; let mut items_written = 0; let mut error = ptr::null_mut(); unsafe { let str_as_utf8 = ffi::g_ucs4_to_utf8( str.as_ref().as_ptr().cast::(), str.as_ref().len() as _, &mut items_read, &mut items_written, &mut error, ); debug_assert!( error.is_null(), "Rust `char` should always be convertible to UTF-8" ); GString::from_glib_full_num(str_as_utf8, items_written as usize) } } #[doc(alias = "g_utf8_casefold")] #[doc(alias = "utf8_casefold")] pub fn casefold(str: impl AsRef) -> GString { unsafe { let str = ffi::g_utf8_casefold(str.as_ref().as_ptr().cast(), str.as_ref().len() as isize); from_glib_full(str) } } #[doc(alias = "g_utf8_normalize")] #[doc(alias = "utf8_normalize")] pub fn normalize(str: impl AsRef, mode: NormalizeMode) -> GString { unsafe { let str = ffi::g_utf8_normalize( str.as_ref().as_ptr().cast(), str.as_ref().len() as isize, mode.into_glib(), ); from_glib_full(str) } } #[cfg(test)] mod tests { #[test] fn convert_ascii() { assert!(super::convert(b"Hello", "utf-8", "ascii").is_ok()); assert!(super::convert(b"He\xaallo", "utf-8", "ascii").is_err()); assert_eq!( super::convert_with_fallback(b"H\xc3\xa9llo", "ascii", "utf-8", crate::NONE_STR) .unwrap() .0 .as_slice(), b"H\\u00e9llo" ); assert_eq!( super::convert_with_fallback(b"H\xc3\xa9llo", "ascii", "utf-8", Some("_")) .unwrap() .0 .as_slice(), b"H_llo" ); } #[test] fn iconv() { let mut conv = super::IConv::new("utf-8", "ascii").unwrap(); assert!(conv.convert(b"Hello").is_ok()); assert!(conv.convert(b"He\xaallo").is_err()); assert!(super::IConv::new("utf-8", "badcharset123456789").is_none()); } #[test] fn filename_charsets() { let _ = super::filename_charsets(); } #[test] fn utf8_and_utf32() { let utf32 = ['A', 'b', '🤔']; let utf8 = super::utf32_to_utf8(utf32); assert_eq!(utf8, "Ab🤔"); let utf8 = "🤔 ț"; let utf32 = super::utf8_to_utf32(utf8); assert_eq!(utf32.as_slice(), &['🤔', ' ', 'ț']); } } glib-0.20.9/src/date.rs000064400000000000000000000327201046102023000127070ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{cmp, fmt, hash}; use crate::{ffi, gobject_ffi, translate::*, BoolError, DateDay, DateMonth, DateWeekday, DateYear}; wrapper! { #[doc(alias = "GDate")] pub struct Date(BoxedInline); match fn { copy => |ptr| gobject_ffi::g_boxed_copy(ffi::g_date_get_type(), ptr as *const _) as *mut _, free => |ptr| ffi::g_date_free(ptr), type_ => || ffi::g_date_get_type(), } } unsafe impl Send for Date {} unsafe impl Sync for Date {} impl Date { #[doc(alias = "g_date_new_dmy")] pub fn from_dmy(day: DateDay, month: DateMonth, year: DateYear) -> Result { let month = month.into_glib(); unsafe { let check: bool = from_glib(ffi::g_date_valid_dmy(day, month, year)); if !check { Err(bool_error!("Invalid date")) } else { Ok(from_glib_full(ffi::g_date_new_dmy(day, month, year))) } } } #[doc(alias = "g_date_new_julian")] pub fn from_julian(julian_day: u32) -> Result { if !Self::valid_julian(julian_day) { Err(bool_error!("Invalid date")) } else { unsafe { Ok(from_glib_full(ffi::g_date_new_julian(julian_day))) } } } #[doc(alias = "g_date_add_days")] pub fn add_days(&mut self, n_days: u32) -> Result<(), BoolError> { let julian_days = self.julian(); if julian_days == 0 || n_days > u32::MAX - julian_days { Err(bool_error!("Invalid date")) } else { unsafe { ffi::g_date_add_days(self.to_glib_none_mut().0, n_days); } Ok(()) } } #[doc(alias = "g_date_add_months")] pub fn add_months(&mut self, n_months: u32) -> Result<(), BoolError> { // The checks for this function are just a mess in the C code, allowing intermediate // unknown state. So for now, nothing can be done... unsafe { ffi::g_date_add_months(self.to_glib_none_mut().0, n_months); } Ok(()) } #[doc(alias = "g_date_add_years")] pub fn add_years(&mut self, n_years: u16) -> Result<(), BoolError> { let year = self.year(); if n_years > u16::MAX - year { Err(bool_error!("Invalid date")) } else { unsafe { ffi::g_date_add_years(self.to_glib_none_mut().0, n_years as _); } Ok(()) } } #[doc(alias = "g_date_clamp")] pub fn clamp(&mut self, min_date: &Date, max_date: &Date) -> Result<(), BoolError> { if min_date >= max_date { Err(bool_error!("`min_date` must be before `max_date`")) } else { unsafe { ffi::g_date_clamp( self.to_glib_none_mut().0, min_date.to_glib_none().0, max_date.to_glib_none().0, ); } Ok(()) } } #[doc(alias = "g_date_compare")] fn compare(&self, rhs: &Date) -> i32 { unsafe { ffi::g_date_compare(self.to_glib_none().0, rhs.to_glib_none().0) } } #[doc(alias = "g_date_days_between")] pub fn days_between(&self, date2: &Date) -> i32 { unsafe { ffi::g_date_days_between(self.to_glib_none().0, date2.to_glib_none().0) } } #[doc(alias = "g_date_get_day")] #[doc(alias = "get_day")] pub fn day(&self) -> DateDay { unsafe { ffi::g_date_get_day(self.to_glib_none().0) } } #[doc(alias = "g_date_get_day_of_year")] #[doc(alias = "get_day_of_year")] pub fn day_of_year(&self) -> u32 { unsafe { ffi::g_date_get_day_of_year(self.to_glib_none().0) } } #[doc(alias = "g_date_get_iso8601_week_of_year")] #[doc(alias = "get_iso8601_week_of_year")] pub fn iso8601_week_of_year(&self) -> u32 { unsafe { ffi::g_date_get_iso8601_week_of_year(self.to_glib_none().0) } } #[doc(alias = "g_date_get_julian")] #[doc(alias = "get_julian")] pub fn julian(&self) -> u32 { unsafe { ffi::g_date_get_julian(self.to_glib_none().0) } } #[doc(alias = "g_date_get_monday_week_of_year")] #[doc(alias = "get_monday_week_of_year")] pub fn monday_week_of_year(&self) -> u32 { unsafe { ffi::g_date_get_monday_week_of_year(self.to_glib_none().0) } } #[doc(alias = "g_date_get_month")] #[doc(alias = "get_month")] pub fn month(&self) -> DateMonth { unsafe { from_glib(ffi::g_date_get_month(self.to_glib_none().0)) } } #[doc(alias = "g_date_get_sunday_week_of_year")] #[doc(alias = "get_sunday_week_of_year")] pub fn sunday_week_of_year(&self) -> u32 { unsafe { ffi::g_date_get_sunday_week_of_year(self.to_glib_none().0) } } #[doc(alias = "g_date_get_weekday")] #[doc(alias = "get_weekday")] pub fn weekday(&self) -> DateWeekday { unsafe { from_glib(ffi::g_date_get_weekday(self.to_glib_none().0)) } } #[doc(alias = "g_date_get_year")] #[doc(alias = "get_year")] pub fn year(&self) -> DateYear { unsafe { ffi::g_date_get_year(self.to_glib_none().0) } } #[doc(alias = "g_date_is_first_of_month")] pub fn is_first_of_month(&self) -> bool { unsafe { from_glib(ffi::g_date_is_first_of_month(self.to_glib_none().0)) } } #[doc(alias = "g_date_is_last_of_month")] pub fn is_last_of_month(&self) -> bool { unsafe { from_glib(ffi::g_date_is_last_of_month(self.to_glib_none().0)) } } #[doc(alias = "g_date_order")] pub fn order(&mut self, date2: &mut Date) { unsafe { ffi::g_date_order(self.to_glib_none_mut().0, date2.to_glib_none_mut().0); } } #[doc(alias = "g_date_set_day")] pub fn set_day(&mut self, day: DateDay) -> Result<(), BoolError> { if !Self::valid_dmy(day, self.month(), self.year()) { Err(bool_error!("invalid day")) } else { unsafe { ffi::g_date_set_day(self.to_glib_none_mut().0, day); } Ok(()) } } #[doc(alias = "g_date_set_dmy")] pub fn set_dmy( &mut self, day: DateDay, month: DateMonth, y: DateYear, ) -> Result<(), BoolError> { if !Self::valid_dmy(day, month, y) { Err(bool_error!("invalid date")) } else { unsafe { ffi::g_date_set_dmy(self.to_glib_none_mut().0, day, month.into_glib(), y); } Ok(()) } } #[doc(alias = "g_date_set_julian")] pub fn set_julian(&mut self, julian_date: u32) -> Result<(), BoolError> { if !Self::valid_julian(julian_date) { Err(bool_error!("invalid date")) } else { unsafe { ffi::g_date_set_julian(self.to_glib_none_mut().0, julian_date); } Ok(()) } } #[doc(alias = "g_date_set_month")] pub fn set_month(&mut self, month: DateMonth) -> Result<(), BoolError> { if !Self::valid_dmy(self.day(), month, self.year()) { Err(bool_error!("invalid month")) } else { unsafe { ffi::g_date_set_month(self.to_glib_none_mut().0, month.into_glib()); } Ok(()) } } #[doc(alias = "g_date_set_parse")] pub fn set_parse(&mut self, str: &str) -> Result<(), BoolError> { let mut c = *self; if !unsafe { ffi::g_date_set_parse(c.to_glib_none_mut().0, str.to_glib_none().0); ffi::g_date_valid(c.to_glib_none().0) == 0 } { Err(bool_error!("invalid parse string")) } else { *self = c; Ok(()) } } #[doc(alias = "g_date_set_time_t")] pub fn set_time(&mut self, time_: libc::time_t) -> Result<(), BoolError> { let mut c = *self; unsafe { ffi::g_date_set_time_t(c.to_glib_none_mut().0, time_ as _); } if !Self::valid_dmy(c.day(), c.month(), c.year()) { Err(bool_error!("invalid time")) } else { *self = c; Ok(()) } } //pub fn set_time_val(&mut self, timeval: /*Ignored*/&mut TimeVal) { // unsafe { TODO: call ffi::g_date_set_time_val() } //} #[doc(alias = "g_date_set_year")] pub fn set_year(&mut self, year: DateYear) -> Result<(), BoolError> { if !Self::valid_dmy(self.day(), self.month(), year) { Err(bool_error!("invalid year")) } else { unsafe { ffi::g_date_set_year(self.to_glib_none_mut().0, year); } Ok(()) } } #[doc(alias = "g_date_subtract_days")] pub fn subtract_days(&mut self, n_days: u32) -> Result<(), BoolError> { let julian = self.julian(); if julian > n_days { Err(bool_error!("invalid number of days")) } else { unsafe { ffi::g_date_subtract_days(self.to_glib_none_mut().0, n_days); } Ok(()) } } #[doc(alias = "g_date_subtract_months")] pub fn subtract_months(&mut self, n_months: u32) -> Result<(), BoolError> { // The checks for this function are just a mess in the C code, allowing intermediate // unknown state. So for now, nothing can be done... unsafe { ffi::g_date_subtract_months(self.to_glib_none_mut().0, n_months); } Ok(()) } #[doc(alias = "g_date_subtract_years")] pub fn subtract_years(&mut self, n_years: u16) -> Result<(), BoolError> { if self.year() < n_years { Err(bool_error!("invalid number of years")) } else { unsafe { ffi::g_date_subtract_years(self.to_glib_none_mut().0, n_years as _); } Ok(()) } } //#[doc(alias="g_date_to_struct_tm")] //pub fn to_struct_tm(&self, tm: /*Unimplemented*/Fundamental: Pointer) { // unsafe { TODO: call ffi::g_date_to_struct_tm() } //} #[doc(alias = "g_date_valid")] pub fn valid(&self) -> bool { unsafe { from_glib(ffi::g_date_valid(self.to_glib_none().0)) } } #[doc(alias = "g_date_get_days_in_month")] #[doc(alias = "get_days_in_month")] pub fn days_in_month(month: DateMonth, year: DateYear) -> u8 { unsafe { ffi::g_date_get_days_in_month(month.into_glib(), year) } } #[doc(alias = "g_date_get_monday_weeks_in_year")] #[doc(alias = "get_monday_weeks_in_year")] pub fn monday_weeks_in_year(year: DateYear) -> u8 { unsafe { ffi::g_date_get_monday_weeks_in_year(year) } } #[doc(alias = "g_date_get_sunday_weeks_in_year")] #[doc(alias = "get_sunday_weeks_in_year")] pub fn sunday_weeks_in_year(year: DateYear) -> u8 { unsafe { ffi::g_date_get_sunday_weeks_in_year(year) } } #[doc(alias = "g_date_is_leap_year")] pub fn is_leap_year(year: DateYear) -> bool { unsafe { from_glib(ffi::g_date_is_leap_year(year)) } } #[doc(alias = "g_date_strftime")] pub fn strftime(s: &str, format: &str, date: &Date) -> usize { let slen = s.len() as _; unsafe { ffi::g_date_strftime( s.to_glib_none().0, slen, format.to_glib_none().0, date.to_glib_none().0, ) } } #[doc(alias = "g_date_valid_day")] pub fn valid_day(day: DateDay) -> bool { unsafe { from_glib(ffi::g_date_valid_day(day)) } } #[doc(alias = "g_date_valid_dmy")] pub fn valid_dmy(day: DateDay, month: DateMonth, year: DateYear) -> bool { unsafe { from_glib(ffi::g_date_valid_dmy(day, month.into_glib(), year)) } } #[doc(alias = "g_date_valid_julian")] pub fn valid_julian(julian_date: u32) -> bool { unsafe { from_glib(ffi::g_date_valid_julian(julian_date)) } } #[doc(alias = "g_date_valid_month")] pub fn valid_month(month: DateMonth) -> bool { unsafe { from_glib(ffi::g_date_valid_month(month.into_glib())) } } #[doc(alias = "g_date_valid_weekday")] pub fn valid_weekday(weekday: DateWeekday) -> bool { unsafe { from_glib(ffi::g_date_valid_weekday(weekday.into_glib())) } } #[doc(alias = "g_date_valid_year")] pub fn valid_year(year: DateYear) -> bool { unsafe { from_glib(ffi::g_date_valid_year(year)) } } } impl PartialEq for Date { #[inline] fn eq(&self, other: &Self) -> bool { self.compare(other) == 0 } } impl Eq for Date {} impl PartialOrd for Date { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for Date { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { self.compare(other).cmp(&0) } } impl fmt::Debug for Date { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Date") .field("year", &self.year()) .field("month", &self.month()) .field("day", &self.day()) .finish() } } impl hash::Hash for Date { fn hash(&self, state: &mut H) where H: hash::Hasher, { self.year().hash(state); self.month().hash(state); self.day().hash(state); } } #[cfg(test)] mod test { use super::*; use crate::value::ToValue; #[test] fn test_value() { let d1 = Date::from_dmy(20, crate::DateMonth::November, 2021).unwrap(); let v = d1.to_value(); let d2 = v.get::<&Date>().unwrap(); assert_eq!(&d1, d2); } } glib-0.20.9/src/date_time.rs000064400000000000000000000005561046102023000137270ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #[cfg(test)] mod tests { use crate::{prelude::*, DateTime}; #[test] fn test_value() { let dt1 = DateTime::now_utc().unwrap(); let v = dt1.to_value(); let dt2 = v.get::<&DateTime>().unwrap(); assert_eq!(dt1.as_ptr(), dt2.as_ptr()); } } glib-0.20.9/src/enums.rs000064400000000000000000001157771046102023000131370ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{cmp, ffi::CStr, fmt, ops::Deref, ptr}; use crate::{ ffi, gobject_ffi, prelude::*, translate::*, ParamSpecEnum, ParamSpecFlags, Type, TypeInfo, Value, }; #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub enum UserDirectory { #[doc(alias = "G_USER_DIRECTORY_DESKTOP")] Desktop, #[doc(alias = "G_USER_DIRECTORY_DOCUMENTS")] Documents, #[doc(alias = "G_USER_DIRECTORY_DOWNLOAD")] Downloads, #[doc(alias = "G_USER_DIRECTORY_MUSIC")] Music, #[doc(alias = "G_USER_DIRECTORY_PICTURES")] Pictures, #[doc(alias = "G_USER_DIRECTORY_PUBLIC_SHARE")] PublicShare, #[doc(alias = "G_USER_DIRECTORY_TEMPLATES")] Templates, #[doc(alias = "G_USER_DIRECTORY_VIDEOS")] Videos, } #[doc(hidden)] impl IntoGlib for UserDirectory { type GlibType = ffi::GUserDirectory; #[inline] fn into_glib(self) -> ffi::GUserDirectory { match self { Self::Desktop => ffi::G_USER_DIRECTORY_DESKTOP, Self::Documents => ffi::G_USER_DIRECTORY_DOCUMENTS, Self::Downloads => ffi::G_USER_DIRECTORY_DOWNLOAD, Self::Music => ffi::G_USER_DIRECTORY_MUSIC, Self::Pictures => ffi::G_USER_DIRECTORY_PICTURES, Self::PublicShare => ffi::G_USER_DIRECTORY_PUBLIC_SHARE, Self::Templates => ffi::G_USER_DIRECTORY_TEMPLATES, Self::Videos => ffi::G_USER_DIRECTORY_VIDEOS, } } } // rustdoc-stripper-ignore-next /// Representation of an `enum` for dynamically, at runtime, querying the values of the enum and /// using them. #[doc(alias = "GEnumClass")] #[repr(transparent)] pub struct EnumClass(ptr::NonNull); unsafe impl Send for EnumClass {} unsafe impl Sync for EnumClass {} impl fmt::Debug for EnumClass { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("EnumClass") .field("type", &self.type_()) .field("values", &self.values()) .finish() } } impl EnumClass { // rustdoc-stripper-ignore-next /// Create a new `EnumClass` from a static type `T`. /// /// Panics if `T` is not representing an enum. pub fn new>() -> Self { Self::with_type(T::static_type()).expect("invalid enum class") } // rustdoc-stripper-ignore-next /// Create a new `EnumClass` from a `Type`. /// /// Returns `None` if `type_` is not representing an enum. pub fn with_type(type_: Type) -> Option { unsafe { let is_enum: bool = from_glib(gobject_ffi::g_type_is_a( type_.into_glib(), gobject_ffi::G_TYPE_ENUM, )); if !is_enum { return None; } Some(EnumClass( ptr::NonNull::new(gobject_ffi::g_type_class_ref(type_.into_glib()) as *mut _) .unwrap(), )) } } // rustdoc-stripper-ignore-next /// `Type` of the enum. pub fn type_(&self) -> Type { unsafe { from_glib(self.0.as_ref().g_type_class.g_type) } } // rustdoc-stripper-ignore-next /// Gets `EnumValue` by integer `value`, if existing. /// /// Returns `None` if the enum does not contain any value /// with `value`. #[doc(alias = "g_enum_get_value")] #[doc(alias = "get_value")] pub fn value(&self, value: i32) -> Option<&EnumValue> { unsafe { let v = gobject_ffi::g_enum_get_value(self.0.as_ptr(), value); if v.is_null() { None } else { Some(&*(v as *const EnumValue)) } } } // rustdoc-stripper-ignore-next /// Gets `EnumValue` by string name `name`, if existing. /// /// Returns `None` if the enum does not contain any value /// with name `name`. #[doc(alias = "g_enum_get_value_by_name")] #[doc(alias = "get_value_by_name")] pub fn value_by_name(&self, name: &str) -> Option<&EnumValue> { unsafe { let v = gobject_ffi::g_enum_get_value_by_name(self.0.as_ptr(), name.to_glib_none().0); if v.is_null() { None } else { Some(&*(v as *const EnumValue)) } } } // rustdoc-stripper-ignore-next /// Gets `EnumValue` by string nick `nick`, if existing. /// /// Returns `None` if the enum does not contain any value /// with nick `nick`. #[doc(alias = "g_enum_get_value_by_nick")] #[doc(alias = "get_value_by_nick")] pub fn value_by_nick(&self, nick: &str) -> Option<&EnumValue> { unsafe { let v = gobject_ffi::g_enum_get_value_by_nick(self.0.as_ptr(), nick.to_glib_none().0); if v.is_null() { None } else { Some(&*(v as *const EnumValue)) } } } // rustdoc-stripper-ignore-next /// Gets all `EnumValue` of this `EnumClass`. #[doc(alias = "get_values")] pub fn values(&self) -> &[EnumValue] { unsafe { if self.0.as_ref().n_values == 0 { return &[]; } std::slice::from_raw_parts( self.0.as_ref().values as *const EnumValue, self.0.as_ref().n_values as usize, ) } } // rustdoc-stripper-ignore-next /// Converts integer `value` to a `Value`, if part of the enum. pub fn to_value(&self, value: i32) -> Option { self.value(value).map(|v| v.to_value(self)) } // rustdoc-stripper-ignore-next /// Converts string name `name` to a `Value`, if part of the enum. pub fn to_value_by_name(&self, name: &str) -> Option { self.value_by_name(name).map(|v| v.to_value(self)) } // rustdoc-stripper-ignore-next /// Converts string nick `nick` to a `Value`, if part of the enum. pub fn to_value_by_nick(&self, nick: &str) -> Option { self.value_by_nick(nick).map(|v| v.to_value(self)) } // rustdoc-stripper-ignore-next /// Complete `TypeInfo` for an enum with values. /// This is an associated function. A method would result in a stack overflow due to a recurvice call: /// callers should first create an `EnumClass` instance by calling `EnumClass::with_type()` which indirectly /// calls `TypePluginRegisterImpl::register_dynamic_enum()` and `TypePluginImpl::complete_type_info()` /// and one of them should call `EnumClass::with_type()` before calling this method. /// `const_static_values` is a reference on a wrapper of a slice of `EnumValue`. /// It must be static to ensure enumeration values are never dropped, and ensures that slice is terminated /// by an `EnumValue` with all members being 0, as expected by GLib. #[doc(alias = "g_enum_complete_type_info")] pub fn complete_type_info( type_: Type, const_static_values: &'static EnumValues, ) -> Option { unsafe { let is_enum: bool = from_glib(gobject_ffi::g_type_is_a( type_.into_glib(), gobject_ffi::G_TYPE_ENUM, )); if !is_enum { return None; } let info = TypeInfo::default(); gobject_ffi::g_enum_complete_type_info( type_.into_glib(), info.as_ptr(), const_static_values.to_glib_none().0, ); Some(info) } } } impl Drop for EnumClass { #[inline] fn drop(&mut self) { unsafe { gobject_ffi::g_type_class_unref(self.0.as_ptr() as *mut _); } } } impl Clone for EnumClass { #[inline] fn clone(&self) -> Self { unsafe { Self(ptr::NonNull::new(gobject_ffi::g_type_class_ref(self.type_().into_glib()) as *mut _).unwrap()) } } } // rustdoc-stripper-ignore-next /// Representation of a single enum value of an `EnumClass`. #[doc(alias = "GEnumValue")] #[derive(Copy, Clone)] #[repr(transparent)] pub struct EnumValue(gobject_ffi::GEnumValue); unsafe impl Send for EnumValue {} unsafe impl Sync for EnumValue {} impl fmt::Debug for EnumValue { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("EnumValue") .field("value", &self.value()) .field("name", &self.name()) .field("nick", &self.nick()) .finish() } } impl EnumValue { // rustdoc-stripper-ignore-next /// # Safety /// /// It is the responsibility of the caller to ensure `GEnumValue` is /// valid. pub const unsafe fn unsafe_from(g_value: gobject_ffi::GEnumValue) -> Self { Self(g_value) } // rustdoc-stripper-ignore-next /// Get integer value corresponding to the value. #[doc(alias = "get_value")] pub fn value(&self) -> i32 { self.0.value } // rustdoc-stripper-ignore-next /// Get name corresponding to the value. #[doc(alias = "get_name")] pub fn name(&self) -> &str { unsafe { CStr::from_ptr(self.0.value_name).to_str().unwrap() } } // rustdoc-stripper-ignore-next /// Get nick corresponding to the value. #[doc(alias = "get_nick")] pub fn nick(&self) -> &str { unsafe { CStr::from_ptr(self.0.value_nick).to_str().unwrap() } } // rustdoc-stripper-ignore-next /// Convert enum value to a `Value`. pub fn to_value(&self, enum_: &EnumClass) -> Value { unsafe { let mut v = Value::from_type_unchecked(enum_.type_()); gobject_ffi::g_value_set_enum(v.to_glib_none_mut().0, self.0.value); v } } // rustdoc-stripper-ignore-next /// Convert enum value from a `Value`. pub fn from_value(value: &Value) -> Option<(EnumClass, &EnumValue)> { unsafe { let enum_class = EnumClass::with_type(value.type_())?; let v = enum_class.value(gobject_ffi::g_value_get_enum(value.to_glib_none().0))?; let v = &*(v as *const EnumValue); Some((enum_class, v)) } } } impl PartialEq for EnumValue { fn eq(&self, other: &Self) -> bool { self.value().eq(&other.value()) } } impl Eq for EnumValue {} impl PartialOrd for EnumValue { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for EnumValue { fn cmp(&self, other: &Self) -> cmp::Ordering { self.value().cmp(&other.value()) } } impl UnsafeFrom for EnumValue { unsafe fn unsafe_from(g_value: gobject_ffi::GEnumValue) -> Self { Self::unsafe_from(g_value) } } unsafe impl<'a> crate::value::FromValue<'a> for &EnumValue { type Checker = EnumTypeChecker; unsafe fn from_value(value: &'a Value) -> Self { let (_, v) = EnumValue::from_value(value).unwrap(); // SAFETY: The enum class and its values live forever std::mem::transmute(v) } } // rustdoc-stripper-ignore-next /// Define the zero value and the associated GLib type. impl EnumerationValue for EnumValue { type GlibType = gobject_ffi::GEnumValue; const ZERO: EnumValue = unsafe { EnumValue::unsafe_from(gobject_ffi::GEnumValue { value: 0, value_name: ptr::null(), value_nick: ptr::null(), }) }; } // rustdoc-stripper-ignore-next /// Storage of enum values. pub type EnumValuesStorage = EnumerationValuesStorage; // rustdoc-stripper-ignore-next /// Representation of enum values wrapped by `EnumValuesStorage` pub type EnumValues = EnumerationValues; pub struct EnumTypeChecker(); unsafe impl crate::value::ValueTypeChecker for EnumTypeChecker { type Error = InvalidEnumError; fn check(value: &Value) -> Result<(), Self::Error> { let t = value.type_(); if t.is_a(Type::ENUM) { Ok(()) } else { Err(InvalidEnumError) } } } // rustdoc-stripper-ignore-next /// An error returned from the [`get`](struct.Value.html#method.get) function /// on a [`Value`](struct.Value.html) for enum types. #[derive(Clone, PartialEq, Eq, Debug)] pub struct InvalidEnumError; impl fmt::Display for InvalidEnumError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Value is not an enum") } } impl std::error::Error for InvalidEnumError {} // rustdoc-stripper-ignore-next /// Representation of a `flags` for dynamically, at runtime, querying the values of the enum and /// using them #[doc(alias = "GFlagsClass")] #[repr(transparent)] pub struct FlagsClass(ptr::NonNull); unsafe impl Send for FlagsClass {} unsafe impl Sync for FlagsClass {} impl fmt::Debug for FlagsClass { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FlagsClass") .field("type", &self.type_()) .field("values", &self.values()) .finish() } } impl FlagsClass { // rustdoc-stripper-ignore-next /// Create a new `FlagsClass` from a static type `T`. /// /// Panics if `T` is not representing an flags type. pub fn new>() -> Self { Self::with_type(T::static_type()).expect("invalid flags class") } // rustdoc-stripper-ignore-next /// Create a new `FlagsClass` from a `Type` /// /// Returns `None` if `type_` is not representing a flags type. pub fn with_type(type_: Type) -> Option { unsafe { let is_flags: bool = from_glib(gobject_ffi::g_type_is_a( type_.into_glib(), gobject_ffi::G_TYPE_FLAGS, )); if !is_flags { return None; } Some(FlagsClass( ptr::NonNull::new(gobject_ffi::g_type_class_ref(type_.into_glib()) as *mut _) .unwrap(), )) } } // rustdoc-stripper-ignore-next /// `Type` of the flags. pub fn type_(&self) -> Type { unsafe { from_glib(self.0.as_ref().g_type_class.g_type) } } // rustdoc-stripper-ignore-next /// Gets `FlagsValue` by integer `value`, if existing. /// /// Returns `None` if the flags do not contain any value /// with `value`. #[doc(alias = "g_flags_get_first_value")] #[doc(alias = "get_value")] pub fn value(&self, value: u32) -> Option<&FlagsValue> { unsafe { let v = gobject_ffi::g_flags_get_first_value(self.0.as_ptr(), value); if v.is_null() { None } else { Some(&*(v as *const FlagsValue)) } } } // rustdoc-stripper-ignore-next /// Gets `FlagsValue` by string name `name`, if existing. /// /// Returns `None` if the flags do not contain any value /// with name `name`. #[doc(alias = "g_flags_get_value_by_name")] #[doc(alias = "get_value_by_name")] pub fn value_by_name(&self, name: &str) -> Option<&FlagsValue> { unsafe { let v = gobject_ffi::g_flags_get_value_by_name(self.0.as_ptr(), name.to_glib_none().0); if v.is_null() { None } else { Some(&*(v as *const FlagsValue)) } } } // rustdoc-stripper-ignore-next /// Gets `FlagsValue` by string nick `nick`, if existing. /// /// Returns `None` if the flags do not contain any value /// with nick `nick`. #[doc(alias = "g_flags_get_value_by_nick")] #[doc(alias = "get_value_by_nick")] pub fn value_by_nick(&self, nick: &str) -> Option<&FlagsValue> { unsafe { let v = gobject_ffi::g_flags_get_value_by_nick(self.0.as_ptr(), nick.to_glib_none().0); if v.is_null() { None } else { Some(&*(v as *const FlagsValue)) } } } // rustdoc-stripper-ignore-next /// Gets all `FlagsValue` of this `FlagsClass`. #[doc(alias = "get_values")] pub fn values(&self) -> &[FlagsValue] { unsafe { if self.0.as_ref().n_values == 0 { return &[]; } std::slice::from_raw_parts( self.0.as_ref().values as *const FlagsValue, self.0.as_ref().n_values as usize, ) } } // rustdoc-stripper-ignore-next /// Converts integer `value` to a `Value`, if part of the flags. pub fn to_value(&self, value: u32) -> Option { self.value(value).map(|v| v.to_value(self)) } // rustdoc-stripper-ignore-next /// Converts string name `name` to a `Value`, if part of the flags. pub fn to_value_by_name(&self, name: &str) -> Option { self.value_by_name(name).map(|v| v.to_value(self)) } // rustdoc-stripper-ignore-next /// Converts string nick `nick` to a `Value`, if part of the flags. pub fn to_value_by_nick(&self, nick: &str) -> Option { self.value_by_nick(nick).map(|v| v.to_value(self)) } // rustdoc-stripper-ignore-next /// Checks if the flags corresponding to integer `f` is set in `value`. pub fn is_set(&self, value: &Value, f: u32) -> bool { unsafe { if self.type_() != value.type_() { return false; } let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0); flags & f != 0 } } // rustdoc-stripper-ignore-next /// Checks if the flags corresponding to string name `name` is set in `value`. pub fn is_set_by_name(&self, value: &Value, name: &str) -> bool { unsafe { if self.type_() != value.type_() { return false; } if let Some(f) = self.value_by_name(name) { let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0); flags & f.value() != 0 } else { false } } } // rustdoc-stripper-ignore-next /// Checks if the flags corresponding to string nick `nick` is set in `value`. pub fn is_set_by_nick(&self, value: &Value, nick: &str) -> bool { unsafe { if self.type_() != value.type_() { return false; } if let Some(f) = self.value_by_nick(nick) { let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0); flags & f.value() != 0 } else { false } } } // rustdoc-stripper-ignore-next /// Set flags value corresponding to integer `f` in `value`, if part of that flags. If the /// flag is already set, it will succeed without doing any changes. /// /// Returns `Ok(value)` with the flag set if successful, or `Err(value)` with the original /// value otherwise. #[doc(alias = "g_value_set_flags")] pub fn set(&self, mut value: Value, f: u32) -> Result { unsafe { if self.type_() != value.type_() { return Err(value); } if let Some(f) = self.value(f) { let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0); gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags | f.value()); Ok(value) } else { Err(value) } } } // rustdoc-stripper-ignore-next /// Set flags value corresponding to string name `name` in `value`, if part of that flags. /// If the flag is already set, it will succeed without doing any changes. /// /// Returns `Ok(value)` with the flag set if successful, or `Err(value)` with the original /// value otherwise. pub fn set_by_name(&self, mut value: Value, name: &str) -> Result { unsafe { if self.type_() != value.type_() { return Err(value); } if let Some(f) = self.value_by_name(name) { let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0); gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags | f.value()); Ok(value) } else { Err(value) } } } // rustdoc-stripper-ignore-next /// Set flags value corresponding to string nick `nick` in `value`, if part of that flags. /// If the flag is already set, it will succeed without doing any changes. /// /// Returns `Ok(value)` with the flag set if successful, or `Err(value)` with the original /// value otherwise. pub fn set_by_nick(&self, mut value: Value, nick: &str) -> Result { unsafe { if self.type_() != value.type_() { return Err(value); } if let Some(f) = self.value_by_nick(nick) { let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0); gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags | f.value()); Ok(value) } else { Err(value) } } } // rustdoc-stripper-ignore-next /// Unset flags value corresponding to integer `f` in `value`, if part of that flags. /// If the flag is already unset, it will succeed without doing any changes. /// /// Returns `Ok(value)` with the flag unset if successful, or `Err(value)` with the original /// value otherwise. pub fn unset(&self, mut value: Value, f: u32) -> Result { unsafe { if self.type_() != value.type_() { return Err(value); } if let Some(f) = self.value(f) { let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0); gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags & !f.value()); Ok(value) } else { Err(value) } } } // rustdoc-stripper-ignore-next /// Unset flags value corresponding to string name `name` in `value`, if part of that flags. /// If the flag is already unset, it will succeed without doing any changes. /// /// Returns `Ok(value)` with the flag unset if successful, or `Err(value)` with the original /// value otherwise. pub fn unset_by_name(&self, mut value: Value, name: &str) -> Result { unsafe { if self.type_() != value.type_() { return Err(value); } if let Some(f) = self.value_by_name(name) { let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0); gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags & !f.value()); Ok(value) } else { Err(value) } } } // rustdoc-stripper-ignore-next /// Unset flags value corresponding to string nick `nick` in `value`, if part of that flags. /// If the flag is already unset, it will succeed without doing any changes. /// /// Returns `Ok(value)` with the flag unset if successful, or `Err(value)` with the original /// value otherwise. pub fn unset_by_nick(&self, mut value: Value, nick: &str) -> Result { unsafe { if self.type_() != value.type_() { return Err(value); } if let Some(f) = self.value_by_nick(nick) { let flags = gobject_ffi::g_value_get_flags(value.to_glib_none().0); gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, flags & !f.value()); Ok(value) } else { Err(value) } } } // rustdoc-stripper-ignore-next /// Converts an integer `value` to a string of nicks separated by `|`. pub fn to_nick_string(&self, mut value: u32) -> String { let mut s = String::new(); for val in self.values() { let v = val.value(); if v != 0 && (value & v) == v { value &= !v; if !s.is_empty() { s.push('|'); } s.push_str(val.nick()); } } s } // rustdoc-stripper-ignore-next /// Converts a string of nicks `s` separated by `|` to an integer value. pub fn from_nick_string(&self, s: &str) -> Result { s.split('|').try_fold(0u32, |acc, flag| { self.value_by_nick(flag.trim()) .map(|v| acc + v.value()) .ok_or_else(|| ParseFlagsError(flag.to_owned())) }) } // rustdoc-stripper-ignore-next /// Returns a new `FlagsBuilder` for conveniently setting/unsetting flags /// and building a `Value`. pub fn builder(&self) -> FlagsBuilder { FlagsBuilder::new(self) } // rustdoc-stripper-ignore-next /// Returns a new `FlagsBuilder` for conveniently setting/unsetting flags /// and building a `Value`. The `Value` is initialized with `value`. pub fn builder_with_value(&self, value: Value) -> Option { if self.type_() != value.type_() { return None; } Some(FlagsBuilder::with_value(self, value)) } // rustdoc-stripper-ignore-next /// Complete `TypeInfo` for the flags with values. /// This is an associated function. A method would result in a stack overflow due to a recurvice call: /// callers should first create an `FlagsClass` instance by calling `FlagsClass::with_type()` which indirectly /// calls `TypePluginRegisterImpl::register_dynamic_flags()` and `TypePluginImpl::complete_type_info()` /// and one of them should call `FlagsClass::with_type()` before calling this method. /// `const_static_values` is a reference on a wrapper of a slice of `FlagsValue`. /// It must be static to ensure flags values are never dropped, and ensures that slice is terminated /// by an `FlagsValue` with all members being 0, as expected by GLib. #[doc(alias = "g_flags_complete_type_info")] pub fn complete_type_info( type_: Type, const_static_values: &'static FlagsValues, ) -> Option { unsafe { let is_flags: bool = from_glib(gobject_ffi::g_type_is_a( type_.into_glib(), gobject_ffi::G_TYPE_FLAGS, )); if !is_flags { return None; } let info = TypeInfo::default(); gobject_ffi::g_flags_complete_type_info( type_.into_glib(), info.as_ptr(), const_static_values.to_glib_none().0, ); Some(info) } } } impl Drop for FlagsClass { #[inline] fn drop(&mut self) { unsafe { gobject_ffi::g_type_class_unref(self.0.as_ptr() as *mut _); } } } impl Clone for FlagsClass { #[inline] fn clone(&self) -> Self { unsafe { Self(ptr::NonNull::new(gobject_ffi::g_type_class_ref(self.type_().into_glib()) as *mut _).unwrap()) } } } #[derive(Debug)] pub struct ParseFlagsError(String); impl std::error::Error for ParseFlagsError {} impl fmt::Display for ParseFlagsError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Unknown flag: '{}'", self.0) } } impl ParseFlagsError { pub fn flag(&self) -> &str { &self.0 } } // rustdoc-stripper-ignore-next /// Representation of a single flags value of a `FlagsClass`. #[doc(alias = "GFlagsValue")] #[derive(Copy, Clone)] #[repr(transparent)] pub struct FlagsValue(gobject_ffi::GFlagsValue); unsafe impl Send for FlagsValue {} unsafe impl Sync for FlagsValue {} impl fmt::Debug for FlagsValue { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FlagsValue") .field("value", &self.value()) .field("name", &self.name()) .field("nick", &self.nick()) .finish() } } impl FlagsValue { // rustdoc-stripper-ignore-next /// # Safety /// /// It is the responsibility of the caller to ensure `GFlagsValue` is /// valid. pub const unsafe fn unsafe_from(g_value: gobject_ffi::GFlagsValue) -> Self { Self(g_value) } // rustdoc-stripper-ignore-next /// Get integer value corresponding to the value. #[doc(alias = "get_value")] pub fn value(&self) -> u32 { self.0.value } // rustdoc-stripper-ignore-next /// Get name corresponding to the value. #[doc(alias = "get_name")] pub fn name(&self) -> &str { unsafe { CStr::from_ptr(self.0.value_name).to_str().unwrap() } } // rustdoc-stripper-ignore-next /// Get nick corresponding to the value. #[doc(alias = "get_nick")] pub fn nick(&self) -> &str { unsafe { CStr::from_ptr(self.0.value_nick).to_str().unwrap() } } // rustdoc-stripper-ignore-next /// Convert flags value to a `Value`. pub fn to_value(&self, flags: &FlagsClass) -> Value { unsafe { let mut v = Value::from_type_unchecked(flags.type_()); gobject_ffi::g_value_set_flags(v.to_glib_none_mut().0, self.0.value); v } } // rustdoc-stripper-ignore-next /// Convert flags values from a `Value`. This returns all flags that are set. pub fn from_value(value: &Value) -> Option<(FlagsClass, Vec<&FlagsValue>)> { unsafe { let flags_class = FlagsClass::with_type(value.type_())?; let mut res = Vec::new(); let f = gobject_ffi::g_value_get_flags(value.to_glib_none().0); for v in flags_class.values() { if v.value() & f != 0 { res.push(&*(v as *const FlagsValue)); } } Some((flags_class, res)) } } } impl PartialEq for FlagsValue { fn eq(&self, other: &Self) -> bool { self.value().eq(&other.value()) } } impl Eq for FlagsValue {} impl UnsafeFrom for FlagsValue { unsafe fn unsafe_from(g_value: gobject_ffi::GFlagsValue) -> Self { Self::unsafe_from(g_value) } } // rustdoc-stripper-ignore-next /// Define the zero value and the associated GLib type. impl EnumerationValue for FlagsValue { type GlibType = gobject_ffi::GFlagsValue; const ZERO: FlagsValue = unsafe { FlagsValue::unsafe_from(gobject_ffi::GFlagsValue { value: 0, value_name: ptr::null(), value_nick: ptr::null(), }) }; } // rustdoc-stripper-ignore-next /// Storage of flags values. pub type FlagsValuesStorage = EnumerationValuesStorage; // rustdoc-stripper-ignore-next /// Representation of flags values wrapped by `FlagsValuesStorage` pub type FlagsValues = EnumerationValues; // rustdoc-stripper-ignore-next /// Builder for conveniently setting/unsetting flags and returning a `Value`. /// /// Example for getting a flags property, unsetting some flags and setting the updated flags on the /// object again: /// /// ```ignore /// let flags = obj.property("flags").unwrap(); /// let flags_class = FlagsClass::new(flags.type_()).unwrap(); /// let flags = flags_class.builder_with_value(flags).unwrap() /// .unset_by_nick("some-flag") /// .unset_by_nick("some-other-flag") /// .build() /// .unwrap(); /// obj.set_property("flags", &flags).unwrap(); /// ``` /// /// If setting/unsetting any value fails, `build()` returns `None`. #[must_use = "The builder must be built to be used"] pub struct FlagsBuilder<'a>(&'a FlagsClass, Option); impl FlagsBuilder<'_> { fn new(flags_class: &FlagsClass) -> FlagsBuilder { let value = unsafe { Value::from_type_unchecked(flags_class.type_()) }; FlagsBuilder(flags_class, Some(value)) } fn with_value(flags_class: &FlagsClass, value: Value) -> FlagsBuilder { FlagsBuilder(flags_class, Some(value)) } // rustdoc-stripper-ignore-next /// Set flags corresponding to integer value `f`. pub fn set(mut self, f: u32) -> Self { if let Some(value) = self.1.take() { self.1 = self.0.set(value, f).ok(); } self } // rustdoc-stripper-ignore-next /// Set flags corresponding to string name `name`. pub fn set_by_name(mut self, name: &str) -> Self { if let Some(value) = self.1.take() { self.1 = self.0.set_by_name(value, name).ok(); } self } // rustdoc-stripper-ignore-next /// Set flags corresponding to string nick `nick`. pub fn set_by_nick(mut self, nick: &str) -> Self { if let Some(value) = self.1.take() { self.1 = self.0.set_by_nick(value, nick).ok(); } self } // rustdoc-stripper-ignore-next /// 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 } // rustdoc-stripper-ignore-next /// Unset flags corresponding to string name `name`. pub fn unset_by_name(mut self, name: &str) -> Self { if let Some(value) = self.1.take() { self.1 = self.0.unset_by_name(value, name).ok(); } self } // rustdoc-stripper-ignore-next /// Unset flags corresponding to string nick `nick`. pub fn unset_by_nick(mut self, nick: &str) -> Self { if let Some(value) = self.1.take() { self.1 = self.0.unset_by_nick(value, nick).ok(); } self } // rustdoc-stripper-ignore-next /// Converts to the final `Value`, unless any previous setting/unsetting of flags failed. #[must_use = "Value returned from the builder should probably be used"] pub fn build(self) -> Option { self.1 } } unsafe impl<'a> crate::value::FromValue<'a> for Vec<&FlagsValue> { type Checker = FlagsTypeChecker; unsafe fn from_value(value: &'a Value) -> Self { let (_, v) = FlagsValue::from_value(value).unwrap(); // SAFETY: The enum class and its values live forever std::mem::transmute(v) } } pub struct FlagsTypeChecker(); unsafe impl crate::value::ValueTypeChecker for FlagsTypeChecker { type Error = InvalidFlagsError; fn check(value: &Value) -> Result<(), Self::Error> { let t = value.type_(); if t.is_a(Type::FLAGS) { Ok(()) } else { Err(InvalidFlagsError) } } } // rustdoc-stripper-ignore-next /// An error returned from the [`get`](struct.Value.html#method.get) function /// on a [`Value`](struct.Value.html) for flags types. #[derive(Clone, PartialEq, Eq, Debug)] pub struct InvalidFlagsError; impl fmt::Display for InvalidFlagsError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Value is not a flags") } } impl std::error::Error for InvalidFlagsError {} // rustdoc-stripper-ignore-next /// helper trait to define the zero value and the associated GLib type. pub trait EnumerationValue: Copy { type GlibType; const ZERO: E; } // rustdoc-stripper-ignore-next /// Storage of enumeration values terminated by a zero value. Should be used /// only as a storage location for `EnumValue` or `FlagsValue` when registering /// an enum or flags as a dynamic type. /// see `TypePluginRegisterImpl::register_dynamic_enum()`, `TypePluginRegisterImpl::register_dynamic_flags()` /// and `TypePluginImpl::complete_type_info()`. /// Inner is intentionally private to ensure other modules will not access the /// enum (or flags) values by this way. /// Use `EnumClass::values()` or `EnumClass::value()` to get the enum values. /// Use `FlagsClass::values()` or `FlagsClass::value()` to get the flags values. #[repr(C)] pub struct EnumerationValuesStorage, const S: usize>([E; S]); impl, const S: usize> EnumerationValuesStorage { // rustdoc-stripper-ignore-next /// creates a new `EnumerationValuesStorage` with the given values and a final zero value. pub const fn new(values: [E; N]) -> Self { #[repr(C)] #[derive(Copy, Clone)] struct Both([E; N], [E; 1]); #[repr(C)] union Transmute { from: Both, to: [E; S], } // SAFETY: Transmute is repr(C) and union fields are compatible in terms of size and alignment, so the access to union fields is safe. unsafe { // create an array with the values and terminated by a zero value. let all = Transmute { from: Both(values, [E::ZERO; 1]), } .to; Self(all) } } } impl, const S: usize> AsRef> for EnumerationValuesStorage { fn as_ref(&self) -> &EnumerationValues { // SAFETY: EnumerationStorage and EnumerationValues are repr(C) and their unique field are compatible (array and slice of the same type), so the cast is safe. unsafe { &*(&self.0 as *const [E] as *const EnumerationValues) } } } // rustdoc-stripper-ignore-next /// Representation of enumeration values wrapped by `EnumerationValuesStorage`. /// Easier to use because don't have a size parameter to be specify. Should be /// used only to register an enum or flags as a dynamic type. /// see `TypePluginRegisterImpl::register_dynamic_enum()`, `TypePluginRegisterImpl::register_dynamic_flags()` /// and `TypePluginImpl::complete_type_info()`. /// Field is intentionally private to ensure other modules will not access the /// enum (or flags) values by this way. /// Use `EnumClass::values()` or `EnumClass::value()` to get the enum values. /// Use `FlagsClass::values()` or `FlagsClass::value()` to get the flags values. #[repr(C)] pub struct EnumerationValues>([E]); impl> Deref for EnumerationValues { type Target = [E]; // rustdoc-stripper-ignore-next /// Dereferences the enumeration values as a slice, but excluding the last value which is zero. fn deref(&self) -> &Self::Target { // SAFETY: EnumerationValues contains at least the zero value which terminates the array. unsafe { std::slice::from_raw_parts(self.0.as_ptr(), self.0.len() - 1) } } } #[doc(hidden)] impl<'a, E: 'a + EnumerationValue> ToGlibPtr<'a, *const E::GlibType> for EnumerationValues { type Storage = &'a Self; fn to_glib_none(&'a self) -> Stash<'a, *const E::GlibType, Self> { Stash(self.0.as_ptr() as *const E::GlibType, self) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_flags() { let flags = FlagsClass::new::(); let values = flags.values(); let def1 = values .iter() .find(|v| v.name() == "G_BINDING_DEFAULT") .unwrap(); let def2 = flags.value_by_name("G_BINDING_DEFAULT").unwrap(); assert!(ptr::eq(def1, def2)); let value = flags.to_value(0).unwrap(); let values = value.get::>().unwrap(); assert_eq!(values.len(), 0); assert_eq!(def1.value(), crate::BindingFlags::DEFAULT.bits()); } } glib-0.20.9/src/error.rs000064400000000000000000000231121046102023000131160ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! `Error` binding and helper trait. use std::{borrow::Cow, convert::Infallible, error, ffi::CStr, fmt, str}; use crate::{ffi, translate::*, Quark}; wrapper! { // rustdoc-stripper-ignore-next /// A generic error capable of representing various error domains (types). #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GError")] pub struct Error(Boxed); match fn { copy => |ptr| ffi::g_error_copy(ptr), free => |ptr| ffi::g_error_free(ptr), type_ => || ffi::g_error_get_type(), } } unsafe impl Send for Error {} unsafe impl Sync for Error {} impl Error { // rustdoc-stripper-ignore-next /// Creates an error with supplied error enum variant and message. #[doc(alias = "g_error_new_literal")] #[doc(alias = "g_error_new")] pub fn new(error: T, message: &str) -> Error { unsafe { from_glib_full(ffi::g_error_new_literal( T::domain().into_glib(), error.code(), message.to_glib_none().0, )) } } // rustdoc-stripper-ignore-next /// Checks if the error domain matches `T`. pub fn is(&self) -> bool { self.inner.domain == T::domain().into_glib() } // rustdoc-stripper-ignore-next /// Returns the error domain quark pub fn domain(&self) -> Quark { unsafe { from_glib(self.inner.domain) } } // rustdoc-stripper-ignore-next /// Checks if the error matches the specified domain and error code. #[doc(alias = "g_error_matches")] pub fn matches(&self, err: T) -> bool { self.is::() && self.inner.code == err.code() } // rustdoc-stripper-ignore-next /// Tries to convert to a specific error enum. /// /// Returns `Some` if the error belongs to the enum's error domain and /// `None` otherwise. /// /// # Examples /// /// ```ignore /// if let Some(file_error) = error.kind::() { /// match file_error { /// FileError::Exist => ... /// FileError::Isdir => ... /// ... /// } /// } /// ``` pub fn kind(&self) -> Option { if self.is::() { T::from(self.inner.code) } else { None } } // rustdoc-stripper-ignore-next /// Returns the error message /// /// Most of the time you can simply print the error since it implements the `Display` /// trait, but you can use this method if you need to have the message as a `&str`. pub fn message(&self) -> &str { unsafe { let bytes = CStr::from_ptr(self.inner.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 fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Error") .field("domain", unsafe { &crate::Quark::from_glib(self.inner.domain) }) .field("code", &self.inner.code) .field("message", &self.message()) .finish() } } impl error::Error for Error {} impl From for Error { fn from(e: Infallible) -> Self { match e {} } } // rustdoc-stripper-ignore-next /// `GLib` error domain. /// /// This trait is implemented by error enums that represent error domains (types). pub trait ErrorDomain: Copy { // rustdoc-stripper-ignore-next /// Returns the quark identifying the error domain. /// /// As returned from `g_some_error_quark`. fn domain() -> Quark; // rustdoc-stripper-ignore-next /// Gets the integer representation of the variant. fn code(self) -> i32; // rustdoc-stripper-ignore-next /// 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; } // rustdoc-stripper-ignore-next /// Generic error used for functions that fail without any further information #[macro_export] macro_rules! bool_error( ($($msg:tt)*) => {{ match ::std::format_args!($($msg)*) { formatted => { if let Some(s) = formatted.as_str() { $crate::BoolError::new( s, file!(), $crate::function_name!(), line!() ) } else { $crate::BoolError::new( formatted.to_string(), file!(), $crate::function_name!(), line!(), ) } } } }}; ); #[macro_export] macro_rules! result_from_gboolean( ($ffi_bool:expr, $($msg:tt)*) => {{ match ::std::format_args!($($msg)*) { formatted => { if let Some(s) = formatted.as_str() { $crate::BoolError::from_glib( $ffi_bool, s, file!(), $crate::function_name!(), line!(), ) } else { $crate::BoolError::from_glib( $ffi_bool, formatted.to_string(), file!(), $crate::function_name!(), 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: impl Into>, filename: &'static str, function: &'static str, line: u32, ) -> Self { Self { message: message.into(), filename, function, line, } } pub fn from_glib( b: ffi::gboolean, message: impl Into>, filename: &'static str, function: &'static str, line: u32, ) -> Result<(), Self> { match b { ffi::GFALSE => Err(BoolError::new(message, filename, function, line)), _ => Ok(()), } } } impl fmt::Display for BoolError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(&self.message) } } impl error::Error for BoolError {} #[cfg(test)] mod tests { use std::ffi::CString; use super::*; use crate::prelude::*; #[test] fn test_error_matches() { let e = Error::new(crate::FileError::Failed, "Failed"); assert!(e.matches(crate::FileError::Failed)); assert!(!e.matches(crate::FileError::Again)); assert!(!e.matches(crate::KeyFileError::NotFound)); } #[test] fn test_error_kind() { let e = Error::new(crate::FileError::Failed, "Failed"); assert_eq!(e.kind::(), Some(crate::FileError::Failed)); assert_eq!(e.kind::(), None); } #[test] fn test_into_raw() { unsafe { let e: *mut ffi::GError = Error::new(crate::FileError::Failed, "Failed").into_glib_ptr(); assert_eq!((*e).domain, ffi::g_file_error_quark()); assert_eq!((*e).code, ffi::G_FILE_ERROR_FAILED); assert_eq!( CStr::from_ptr((*e).message), CString::new("Failed").unwrap().as_c_str() ); ffi::g_error_free(e); } } #[test] fn test_bool_error() { let from_static_msg = bool_error!("Static message"); assert_eq!(from_static_msg.to_string(), "Static message"); let from_dynamic_msg = bool_error!("{} message", "Dynamic"); assert_eq!(from_dynamic_msg.to_string(), "Dynamic message"); let false_static_res = result_from_gboolean!(ffi::GFALSE, "Static message"); assert!(false_static_res.is_err()); let static_err = false_static_res.err().unwrap(); assert_eq!(static_err.to_string(), "Static message"); let true_static_res = result_from_gboolean!(ffi::GTRUE, "Static message"); assert!(true_static_res.is_ok()); let false_dynamic_res = result_from_gboolean!(ffi::GFALSE, "{} message", "Dynamic"); assert!(false_dynamic_res.is_err()); let dynamic_err = false_dynamic_res.err().unwrap(); assert_eq!(dynamic_err.to_string(), "Dynamic message"); let true_dynamic_res = result_from_gboolean!(ffi::GTRUE, "{} message", "Dynamic"); assert!(true_dynamic_res.is_ok()); } #[test] fn test_value() { let e1 = Error::new(crate::FileError::Failed, "Failed"); // This creates a copy ... let v = e1.to_value(); // ... so we have to get the raw pointer from inside the value to check for equality. let ptr = unsafe { crate::gobject_ffi::g_value_get_boxed(v.to_glib_none().0) as *const ffi::GError }; let e2 = v.get::<&Error>().unwrap(); assert_eq!(ptr, e2.to_glib_none().0); } } glib-0.20.9/src/exit_code.rs000064400000000000000000000012501046102023000137270ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::process::Termination; #[derive(Clone, Copy, PartialEq, Eq, Debug, PartialOrd, Ord)] pub struct ExitCode(i32); impl ExitCode { pub const SUCCESS: Self = Self(0); pub const FAILURE: Self = Self(1); pub fn value(&self) -> i32 { self.0 } } impl From for ExitCode { fn from(value: i32) -> Self { Self(value) } } impl From for i32 { fn from(value: ExitCode) -> Self { value.0 } } impl Termination for ExitCode { fn report(self) -> std::process::ExitCode { std::process::ExitCode::from(self.0 as u8) } } glib-0.20.9/src/functions.rs000064400000000000000000000241551046102023000140050ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. pub use crate::auto::functions::*; #[cfg(not(windows))] use std::boxed::Box as Box_; #[cfg(not(windows))] use std::mem; #[cfg(not(windows))] #[cfg(feature = "v2_58")] use std::os::unix::io::AsRawFd; #[cfg(not(windows))] use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd}; use std::ptr; // #[cfg(windows)] // #[cfg(feature = "v2_58")] // use std::os::windows::io::AsRawHandle; use crate::{ffi, translate::*, ChecksumType, GStr}; #[cfg(not(windows))] use crate::{Error, Pid, SpawnFlags}; #[cfg(feature = "v2_58")] #[cfg(not(windows))] #[cfg_attr(docsrs, doc(cfg(all(feature = "v2_58", not(windows)))))] #[allow(clippy::too_many_arguments)] #[doc(alias = "g_spawn_async_with_fds")] pub fn spawn_async_with_fds, T: AsRawFd, U: AsRawFd, V: AsRawFd>( working_directory: P, argv: &[&str], envp: &[&str], flags: SpawnFlags, child_setup: Option>, stdin_fd: T, stdout_fd: U, stderr_fd: V, ) -> Result { let child_setup_data: Box_>> = Box_::new(child_setup); unsafe extern "C" fn child_setup_func(user_data: ffi::gpointer) { let callback: Box_>> = Box_::from_raw(user_data as *mut _); let callback = (*callback).expect("cannot get closure..."); callback() } let child_setup = if child_setup_data.is_some() { Some(child_setup_func as _) } else { None }; let super_callback0: Box_>> = child_setup_data; unsafe { let mut child_pid = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let _ = ffi::g_spawn_async_with_fds( working_directory.as_ref().to_glib_none().0, argv.to_glib_none().0, envp.to_glib_none().0, flags.into_glib(), child_setup, Box_::into_raw(super_callback0) as *mut _, child_pid.as_mut_ptr(), stdin_fd.as_raw_fd(), stdout_fd.as_raw_fd(), stderr_fd.as_raw_fd(), &mut error, ); let child_pid = from_glib(child_pid.assume_init()); if error.is_null() { Ok(child_pid) } else { Err(from_glib_full(error)) } } } // #[cfg(feature = "v2_58")] // #[cfg(windows)] // pub fn spawn_async_with_fds< // P: AsRef, // T: AsRawHandle, // U: AsRawHandle, // V: AsRawHandle, // >( // working_directory: P, // argv: &[&str], // envp: &[&str], // flags: SpawnFlags, // child_setup: Option>, // stdin_fd: T, // stdout_fd: U, // stderr_fd: V, // ) -> Result { // let child_setup_data: Box_>> = Box_::new(child_setup); // unsafe extern "C" fn child_setup_func>( // user_data: ffi::gpointer, // ) { // let callback: Box_>> = // Box_::from_raw(user_data as *mut _); // let callback = (*callback).expect("cannot get closure..."); // callback() // } // let child_setup = if child_setup_data.is_some() { // Some(child_setup_func::

as _) // } else { // None // }; // let super_callback0: Box_>> = child_setup_data; // unsafe { // let mut child_pid = mem::MaybeUninit::uninit(); // let mut error = ptr::null_mut(); // let _ = ffi::g_spawn_async_with_fds( // working_directory.as_ref().to_glib_none().0, // argv.to_glib_none().0, // envp.to_glib_none().0, // flags.into_glib(), // child_setup, // Box_::into_raw(super_callback0) as *mut _, // child_pid.as_mut_ptr(), // stdin_fd.as_raw_handle() as usize as _, // stdout_fd.as_raw_handle() as usize as _, // stderr_fd.as_raw_handle() as usize as _, // &mut error, // ); // let child_pid = from_glib(child_pid.assume_init()); // if error.is_null() { // Ok(child_pid) // } else { // Err(from_glib_full(error)) // } // } // } #[cfg(not(windows))] #[cfg_attr(docsrs, doc(cfg(not(windows))))] #[doc(alias = "g_spawn_async_with_pipes")] pub fn spawn_async_with_pipes< P: AsRef, T: FromRawFd, U: FromRawFd, V: FromRawFd, >( working_directory: P, argv: &[&std::path::Path], envp: &[&std::path::Path], flags: SpawnFlags, child_setup: Option>, ) -> Result<(Pid, T, U, V), Error> { let child_setup_data: Box_>> = Box_::new(child_setup); unsafe extern "C" fn child_setup_func(user_data: ffi::gpointer) { let callback: Box_>> = Box_::from_raw(user_data as *mut _); let callback = (*callback).expect("cannot get closure..."); callback() } let child_setup = if child_setup_data.is_some() { Some(child_setup_func as _) } else { None }; let super_callback0: Box_>> = child_setup_data; unsafe { let mut child_pid = mem::MaybeUninit::uninit(); let mut standard_input = mem::MaybeUninit::uninit(); let mut standard_output = mem::MaybeUninit::uninit(); let mut standard_error = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let _ = ffi::g_spawn_async_with_pipes( working_directory.as_ref().to_glib_none().0, argv.to_glib_none().0, envp.to_glib_none().0, flags.into_glib(), child_setup, Box_::into_raw(super_callback0) as *mut _, child_pid.as_mut_ptr(), standard_input.as_mut_ptr(), standard_output.as_mut_ptr(), standard_error.as_mut_ptr(), &mut error, ); let child_pid = from_glib(child_pid.assume_init()); let standard_input = standard_input.assume_init(); let standard_output = standard_output.assume_init(); let standard_error = standard_error.assume_init(); if error.is_null() { #[cfg(not(windows))] { Ok(( child_pid, FromRawFd::from_raw_fd(standard_input), FromRawFd::from_raw_fd(standard_output), FromRawFd::from_raw_fd(standard_error), )) } // #[cfg(windows)] // { // use std::os::windows::io::{FromRawHandle, RawHandle}; // Ok(( // child_pid, // File::from_raw_handle(standard_input as usize as RawHandle), // File::from_raw_handle(standard_output as usize as RawHandle), // File::from_raw_handle(standard_error as usize as RawHandle), // )) // } } else { Err(from_glib_full(error)) } } } // rustdoc-stripper-ignore-next /// Obtain the character set for the current locale. /// /// This returns whether the locale's encoding is UTF-8, and the current /// charset if available. #[doc(alias = "g_get_charset")] #[doc(alias = "get_charset")] pub fn charset() -> (bool, Option<&'static GStr>) { unsafe { let mut out_charset = ptr::null(); let is_utf8 = from_glib(ffi::g_get_charset(&mut out_charset)); let charset = from_glib_none(out_charset); (is_utf8, charset) } } #[doc(alias = "g_compute_checksum_for_string")] pub fn compute_checksum_for_string( checksum_type: ChecksumType, str: impl IntoGStr, ) -> Option { str.run_with_gstr(|str| unsafe { from_glib_full(ffi::g_compute_checksum_for_string( checksum_type.into_glib(), str.as_ptr(), str.len() as _, )) }) } #[cfg(unix)] #[doc(alias = "g_unix_open_pipe")] pub fn unix_open_pipe(flags: i32) -> Result<(RawFd, RawFd), Error> { unsafe { let mut fds = [0, 2]; let mut error = ptr::null_mut(); let _ = ffi::g_unix_open_pipe(&mut fds, flags, &mut error); if error.is_null() { Ok(( FromRawFd::from_raw_fd(fds[0]), FromRawFd::from_raw_fd(fds[1]), )) } else { Err(from_glib_full(error)) } } } #[cfg(unix)] #[doc(alias = "g_file_open_tmp")] pub fn file_open_tmp( tmpl: Option>, ) -> Result<(RawFd, std::path::PathBuf), crate::Error> { unsafe { let mut name_used = ptr::null_mut(); let mut error = ptr::null_mut(); let ret = ffi::g_file_open_tmp( tmpl.as_ref().map(|p| p.as_ref()).to_glib_none().0, &mut name_used, &mut error, ); if error.is_null() { Ok((ret.into_raw_fd(), from_glib_full(name_used))) } else { Err(from_glib_full(error)) } } } // rustdoc-stripper-ignore-next /// Spawn a new infallible `Future` on the thread-default 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_future + Send + 'static>( f: F, ) -> crate::JoinHandle { let ctx = crate::MainContext::ref_thread_default(); ctx.spawn(f) } // rustdoc-stripper-ignore-next /// Spawn a new infallible `Future` on the thread-default 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 /// `with_thread_default` or `acquire` on the main context. pub fn spawn_future_local + 'static>( f: F, ) -> crate::JoinHandle { let ctx = crate::MainContext::ref_thread_default(); ctx.spawn_local(f) } glib-0.20.9/src/future_with_timeout.rs000064400000000000000000000056061046102023000161100ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{error, fmt}; use futures_util::{ future::{self, Either, Future}, pin_mut, }; // rustdoc-stripper-ignore-next /// The error returned when a future times out. #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct FutureWithTimeoutError; impl fmt::Display for FutureWithTimeoutError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("The future timed out") } } impl error::Error for FutureWithTimeoutError {} // rustdoc-stripper-ignore-next /// Add a timeout to a `Future`. /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub async fn future_with_timeout_with_priority( priority: crate::Priority, timeout: std::time::Duration, fut: impl Future, ) -> Result { let timeout = crate::timeout_future_with_priority(priority, timeout); pin_mut!(fut); match future::select(fut, timeout).await { Either::Left((x, _)) => Ok(x), _ => Err(FutureWithTimeoutError), } } // rustdoc-stripper-ignore-next /// Add a timeout to a `Future`. /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub async fn future_with_timeout( timeout: std::time::Duration, fut: impl Future, ) -> Result { future_with_timeout_with_priority(crate::Priority::default(), timeout, fut).await } #[cfg(test)] mod tests { use std::time::Duration; use futures_util::FutureExt; use super::*; use crate::{MainContext, MainLoop}; #[test] fn test_future_with_timeout() { let c = MainContext::new(); let fut = future::pending::<()>(); let result = c.block_on(future_with_timeout(Duration::from_millis(20), fut)); assert_eq!(result, Err(FutureWithTimeoutError)); let fut = future::ready(()); let result = c.block_on(future_with_timeout(Duration::from_millis(20), fut)); assert_eq!(result, Ok(())); } #[test] fn test_future_with_timeout_send() { let c = MainContext::new(); let l = MainLoop::new(Some(&c), false); let l_clone = l.clone(); let fut = future::pending::<()>(); c.spawn( future_with_timeout(Duration::from_millis(20), fut).then(move |result| { l_clone.quit(); assert_eq!(result, Err(FutureWithTimeoutError)); futures_util::future::ready(()) }), ); l.run(); let l_clone = l.clone(); let fut = future::ready(()); c.spawn( future_with_timeout(Duration::from_millis(20), fut).then(move |result| { l_clone.quit(); assert_eq!(result, Ok(())); futures_util::future::ready(()) }), ); l.run(); } } glib-0.20.9/src/gobject/auto/binding.rs000064400000000000000000000031101046102023000157600ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::{ffi, translate::*, BindingFlags}; crate::wrapper! { #[doc(alias = "GBinding")] pub struct Binding(Object); match fn { type_ => || crate::gobject_ffi::g_binding_get_type(), } } impl Binding { #[doc(alias = "g_binding_get_flags")] #[doc(alias = "get_flags")] pub fn flags(&self) -> BindingFlags { unsafe { from_glib(crate::gobject_ffi::g_binding_get_flags( self.to_glib_none().0, )) } } #[doc(alias = "g_binding_get_source_property")] #[doc(alias = "get_source_property")] #[doc(alias = "source-property")] pub fn source_property(&self) -> crate::GString { unsafe { from_glib_none(crate::gobject_ffi::g_binding_get_source_property( self.to_glib_none().0, )) } } #[doc(alias = "g_binding_get_target_property")] #[doc(alias = "get_target_property")] #[doc(alias = "target-property")] pub fn target_property(&self) -> crate::GString { unsafe { from_glib_none(crate::gobject_ffi::g_binding_get_target_property( self.to_glib_none().0, )) } } #[doc(alias = "g_binding_unbind")] pub fn unbind(&self) { unsafe { crate::gobject_ffi::g_binding_unbind(self.to_glib_none().0); } } } unsafe impl Send for Binding {} unsafe impl Sync for Binding {} glib-0.20.9/src/gobject/auto/binding_group.rs000064400000000000000000000050161046102023000172030ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::{ ffi, prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, Object, }; use std::boxed::Box as Box_; crate::wrapper! { #[doc(alias = "GBindingGroup")] pub struct BindingGroup(Object); match fn { type_ => || crate::gobject_ffi::g_binding_group_get_type(), } } impl BindingGroup { #[doc(alias = "g_binding_group_new")] pub fn new() -> BindingGroup { unsafe { from_glib_full(crate::gobject_ffi::g_binding_group_new()) } } #[doc(alias = "g_binding_group_dup_source")] #[doc(alias = "dup_source")] pub fn source(&self) -> Option { unsafe { from_glib_none(crate::gobject_ffi::g_binding_group_dup_source( self.to_glib_none().0, )) } } #[doc(alias = "g_binding_group_set_source")] #[doc(alias = "source")] pub fn set_source(&self, source: Option<&impl IsA>) { unsafe { crate::gobject_ffi::g_binding_group_set_source( self.to_glib_none().0, source.map(|p| p.as_ref()).to_glib_none().0, ); } } #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] #[doc(alias = "source")] pub fn connect_source_notify( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn notify_source_trampoline< F: Fn(&BindingGroup) + Send + Sync + 'static, >( this: *mut crate::gobject_ffi::GBindingGroup, _param_spec: ffi::gpointer, f: ffi::gpointer, ) { let f: &F = &*(f as *const F); f(&from_glib_borrow(this)) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::source\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_source_trampoline:: as *const (), )), Box_::into_raw(f), ) } } } #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] impl Default for BindingGroup { fn default() -> Self { Self::new() } } unsafe impl Send for BindingGroup {} unsafe impl Sync for BindingGroup {} glib-0.20.9/src/gobject/auto/flags.rs000064400000000000000000000127471046102023000154620ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::{bitflags::bitflags, ffi, prelude::*, translate::*}; bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GBindingFlags")] pub struct BindingFlags: u32 { #[doc(alias = "G_BINDING_DEFAULT")] const DEFAULT = crate::gobject_ffi::G_BINDING_DEFAULT as _; #[doc(alias = "G_BINDING_BIDIRECTIONAL")] const BIDIRECTIONAL = crate::gobject_ffi::G_BINDING_BIDIRECTIONAL as _; #[doc(alias = "G_BINDING_SYNC_CREATE")] const SYNC_CREATE = crate::gobject_ffi::G_BINDING_SYNC_CREATE as _; #[doc(alias = "G_BINDING_INVERT_BOOLEAN")] const INVERT_BOOLEAN = crate::gobject_ffi::G_BINDING_INVERT_BOOLEAN as _; } } #[doc(hidden)] impl IntoGlib for BindingFlags { type GlibType = crate::gobject_ffi::GBindingFlags; #[inline] fn into_glib(self) -> crate::gobject_ffi::GBindingFlags { self.bits() } } #[doc(hidden)] impl FromGlib for BindingFlags { #[inline] unsafe fn from_glib(value: crate::gobject_ffi::GBindingFlags) -> Self { Self::from_bits_truncate(value) } } impl StaticType for BindingFlags { #[inline] #[doc(alias = "g_binding_flags_get_type")] fn static_type() -> crate::Type { unsafe { from_glib(crate::gobject_ffi::g_binding_flags_get_type()) } } } impl crate::HasParamSpec for BindingFlags { type ParamSpec = crate::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> crate::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl crate::value::ValueType for BindingFlags { type Type = Self; } unsafe impl<'a> crate::value::FromValue<'a> for BindingFlags { type Checker = crate::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a crate::Value) -> Self { from_glib(crate::gobject_ffi::g_value_get_flags( value.to_glib_none().0, )) } } impl ToValue for BindingFlags { #[inline] fn to_value(&self) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { crate::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> crate::Type { Self::static_type() } } impl From for crate::Value { #[inline] fn from(v: BindingFlags) -> Self { ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GSignalFlags")] pub struct SignalFlags: u32 { #[doc(alias = "G_SIGNAL_RUN_FIRST")] const RUN_FIRST = crate::gobject_ffi::G_SIGNAL_RUN_FIRST as _; #[doc(alias = "G_SIGNAL_RUN_LAST")] const RUN_LAST = crate::gobject_ffi::G_SIGNAL_RUN_LAST as _; #[doc(alias = "G_SIGNAL_RUN_CLEANUP")] const RUN_CLEANUP = crate::gobject_ffi::G_SIGNAL_RUN_CLEANUP as _; #[doc(alias = "G_SIGNAL_NO_RECURSE")] const NO_RECURSE = crate::gobject_ffi::G_SIGNAL_NO_RECURSE as _; #[doc(alias = "G_SIGNAL_DETAILED")] const DETAILED = crate::gobject_ffi::G_SIGNAL_DETAILED as _; #[doc(alias = "G_SIGNAL_ACTION")] const ACTION = crate::gobject_ffi::G_SIGNAL_ACTION as _; #[doc(alias = "G_SIGNAL_NO_HOOKS")] const NO_HOOKS = crate::gobject_ffi::G_SIGNAL_NO_HOOKS as _; #[doc(alias = "G_SIGNAL_MUST_COLLECT")] const MUST_COLLECT = crate::gobject_ffi::G_SIGNAL_MUST_COLLECT as _; #[doc(alias = "G_SIGNAL_DEPRECATED")] const DEPRECATED = crate::gobject_ffi::G_SIGNAL_DEPRECATED as _; #[doc(alias = "G_SIGNAL_ACCUMULATOR_FIRST_RUN")] const ACCUMULATOR_FIRST_RUN = crate::gobject_ffi::G_SIGNAL_ACCUMULATOR_FIRST_RUN as _; } } #[doc(hidden)] impl IntoGlib for SignalFlags { type GlibType = crate::gobject_ffi::GSignalFlags; #[inline] fn into_glib(self) -> crate::gobject_ffi::GSignalFlags { self.bits() } } #[doc(hidden)] impl FromGlib for SignalFlags { #[inline] unsafe fn from_glib(value: crate::gobject_ffi::GSignalFlags) -> Self { Self::from_bits_truncate(value) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GTypeFlags")] pub struct TypeFlags: u32 { #[doc(alias = "G_TYPE_FLAG_NONE")] const NONE = crate::gobject_ffi::G_TYPE_FLAG_NONE as _; #[doc(alias = "G_TYPE_FLAG_ABSTRACT")] const ABSTRACT = crate::gobject_ffi::G_TYPE_FLAG_ABSTRACT as _; #[doc(alias = "G_TYPE_FLAG_VALUE_ABSTRACT")] const VALUE_ABSTRACT = crate::gobject_ffi::G_TYPE_FLAG_VALUE_ABSTRACT as _; #[doc(alias = "G_TYPE_FLAG_FINAL")] const FINAL = crate::gobject_ffi::G_TYPE_FLAG_FINAL as _; #[doc(alias = "G_TYPE_FLAG_DEPRECATED")] const DEPRECATED = crate::gobject_ffi::G_TYPE_FLAG_DEPRECATED as _; } } #[doc(hidden)] impl IntoGlib for TypeFlags { type GlibType = crate::gobject_ffi::GTypeFlags; #[inline] fn into_glib(self) -> crate::gobject_ffi::GTypeFlags { self.bits() } } #[doc(hidden)] impl FromGlib for TypeFlags { #[inline] unsafe fn from_glib(value: crate::gobject_ffi::GTypeFlags) -> Self { Self::from_bits_truncate(value) } } glib-0.20.9/src/gobject/auto/mod.rs000064400000000000000000000013171046102023000151340ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT mod binding; pub use self::binding::Binding; #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] mod binding_group; #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] pub use self::binding_group::BindingGroup; #[cfg(feature = "v2_74")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))] mod signal_group; #[cfg(feature = "v2_74")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))] pub use self::signal_group::SignalGroup; mod flags; pub use self::flags::BindingFlags; pub use self::flags::SignalFlags; pub use self::flags::TypeFlags; glib-0.20.9/src/gobject/auto/signal_group.rs000064400000000000000000000037521046102023000170530ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT use crate::{ffi, prelude::*, translate::*, Object}; crate::wrapper! { #[doc(alias = "GSignalGroup")] pub struct SignalGroup(Object); match fn { type_ => || crate::gobject_ffi::g_signal_group_get_type(), } } impl SignalGroup { #[doc(alias = "g_signal_group_new")] #[doc(alias = "new")] pub fn with_type(target_type: crate::types::Type) -> SignalGroup { unsafe { from_glib_full(crate::gobject_ffi::g_signal_group_new( target_type.into_glib(), )) } } #[doc(alias = "g_signal_group_block")] pub fn block(&self) { unsafe { crate::gobject_ffi::g_signal_group_block(self.to_glib_none().0); } } #[doc(alias = "g_signal_group_dup_target")] #[doc(alias = "dup_target")] pub fn target(&self) -> Option { unsafe { from_glib_full(crate::gobject_ffi::g_signal_group_dup_target( self.to_glib_none().0, )) } } #[doc(alias = "g_signal_group_set_target")] #[doc(alias = "target")] pub fn set_target(&self, target: Option<&impl IsA>) { unsafe { crate::gobject_ffi::g_signal_group_set_target( self.to_glib_none().0, target.map(|p| p.as_ref()).to_glib_none().0, ); } } #[doc(alias = "g_signal_group_unblock")] pub fn unblock(&self) { unsafe { crate::gobject_ffi::g_signal_group_unblock(self.to_glib_none().0); } } #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] #[doc(alias = "target-type")] pub fn target_type(&self) -> crate::types::Type { ObjectExt::property(self, "target-type") } } unsafe impl Send for SignalGroup {} unsafe impl Sync for SignalGroup {} glib-0.20.9/src/gobject/binding.rs000064400000000000000000000224371046102023000150250ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::{prelude::*, Binding, Object}; impl Binding { #[doc(alias = "get_source")] pub fn source(&self) -> Option { self.property("source") } #[doc(alias = "get_target")] pub fn target(&self) -> Option { self.property("target") } } #[cfg(test)] mod test { use crate::{prelude::*, subclass::prelude::*}; #[test] fn binding() { let source = TestObject::default(); let target = TestObject::default(); assert!(source.find_property("name").is_some()); source .bind_property("name", &target, "name") .bidirectional() .build(); source.set_name("test_source_name"); assert_eq!(source.name(), target.name()); target.set_name("test_target_name"); assert_eq!(source.name(), target.name()); } #[test] fn binding_to_transform_with_values() { let source = TestObject::default(); let target = TestObject::default(); source .bind_property("name", &target, "name") .sync_create() .transform_to_with_values(|_binding, value| { let value = value.get::<&str>().unwrap(); Some(format!("{value} World").to_value()) }) .transform_from_with_values(|_binding, value| { let value = value.get::<&str>().unwrap(); Some(format!("{value} World").to_value()) }) .build(); source.set_name("Hello"); assert_eq!(target.name(), "Hello World"); } #[test] fn binding_from_transform_with_values() { let source = TestObject::default(); let target = TestObject::default(); source .bind_property("name", &target, "name") .sync_create() .bidirectional() .transform_to_with_values(|_binding, value| { let value = value.get::<&str>().unwrap(); Some(format!("{value} World").to_value()) }) .transform_from_with_values(|_binding, value| { let value = value.get::<&str>().unwrap(); Some(format!("{value} World").to_value()) }) .build(); target.set_name("Hello"); assert_eq!(source.name(), "Hello World"); } #[test] fn binding_to_transform_ref() { let source = TestObject::default(); let target = TestObject::default(); source .bind_property("name", &target, "name") .sync_create() .transform_to(|_binding, value: &str| Some(format!("{value} World"))) .transform_from(|_binding, value: &str| Some(format!("{value} World"))) .build(); source.set_name("Hello"); assert_eq!(target.name(), "Hello World"); } #[test] fn binding_to_transform_owned_ref() { let source = TestObject::default(); let target = TestObject::default(); source .bind_property("name", &target, "name") .sync_create() .transform_to(|_binding, value: String| Some(format!("{value} World"))) .transform_from(|_binding, value: &str| Some(format!("{value} World"))) .build(); source.set_name("Hello"); assert_eq!(target.name(), "Hello World"); } #[test] fn binding_from_transform() { let source = TestObject::default(); let target = TestObject::default(); source .bind_property("name", &target, "name") .sync_create() .bidirectional() .transform_to(|_binding, value: &str| Some(format!("{value} World"))) .transform_from(|_binding, value: &str| Some(format!("{value} World"))) .build(); target.set_name("Hello"); assert_eq!(source.name(), "Hello World"); } #[test] fn binding_to_transform_with_values_change_type() { let source = TestObject::default(); let target = TestObject::default(); source .bind_property("name", &target, "enabled") .sync_create() .transform_to_with_values(|_binding, value| { let value = value.get::<&str>().unwrap(); Some((value == "Hello").to_value()) }) .transform_from_with_values(|_binding, value| { let value = value.get::().unwrap(); Some((if value { "Hello" } else { "World" }).to_value()) }) .build(); source.set_name("Hello"); assert!(target.enabled()); source.set_name("Hello World"); assert!(!target.enabled()); } #[test] fn binding_from_transform_values_change_type() { let source = TestObject::default(); let target = TestObject::default(); source .bind_property("name", &target, "enabled") .sync_create() .bidirectional() .transform_to_with_values(|_binding, value| { let value = value.get::<&str>().unwrap(); Some((value == "Hello").to_value()) }) .transform_from_with_values(|_binding, value| { let value = value.get::().unwrap(); Some((if value { "Hello" } else { "World" }).to_value()) }) .build(); target.set_enabled(true); assert_eq!(source.name(), "Hello"); target.set_enabled(false); assert_eq!(source.name(), "World"); } #[test] fn binding_to_transform_change_type() { let source = TestObject::default(); let target = TestObject::default(); source .bind_property("name", &target, "enabled") .sync_create() .transform_to(|_binding, value: &str| Some(value == "Hello")) .transform_from(|_binding, value: bool| Some(if value { "Hello" } else { "World" })) .build(); source.set_name("Hello"); assert!(target.enabled()); source.set_name("Hello World"); assert!(!target.enabled()); } #[test] fn binding_from_transform_change_type() { let source = TestObject::default(); let target = TestObject::default(); source .bind_property("name", &target, "enabled") .sync_create() .bidirectional() .transform_to(|_binding, value: &str| Some(value == "Hello")) .transform_from(|_binding, value: bool| Some(if value { "Hello" } else { "World" })) .build(); target.set_enabled(true); assert_eq!(source.name(), "Hello"); target.set_enabled(false); assert_eq!(source.name(), "World"); } mod imp { use std::{cell::RefCell, sync::OnceLock}; use super::*; use crate as glib; #[derive(Debug, Default)] pub struct TestObject { pub name: RefCell, pub enabled: RefCell, } #[crate::object_subclass] impl ObjectSubclass for TestObject { const NAME: &'static str = "TestBinding"; type Type = super::TestObject; } impl ObjectImpl for TestObject { fn properties() -> &'static [crate::ParamSpec] { static PROPERTIES: OnceLock> = OnceLock::new(); PROPERTIES.get_or_init(|| { vec![ crate::ParamSpecString::builder("name") .explicit_notify() .build(), crate::ParamSpecBoolean::builder("enabled") .explicit_notify() .build(), ] }) } fn property(&self, _id: usize, pspec: &crate::ParamSpec) -> crate::Value { let obj = self.obj(); match pspec.name() { "name" => obj.name().to_value(), "enabled" => obj.enabled().to_value(), _ => unimplemented!(), } } fn set_property(&self, _id: usize, value: &crate::Value, pspec: &crate::ParamSpec) { let obj = self.obj(); match pspec.name() { "name" => obj.set_name(value.get().unwrap()), "enabled" => obj.set_enabled(value.get().unwrap()), _ => unimplemented!(), }; } } } crate::wrapper! { pub struct TestObject(ObjectSubclass); } impl Default for TestObject { fn default() -> Self { crate::Object::new() } } impl TestObject { fn name(&self) -> String { self.imp().name.borrow().clone() } fn set_name(&self, name: &str) { if name != self.imp().name.replace(name.to_string()).as_str() { self.notify("name"); } } fn enabled(&self) -> bool { *self.imp().enabled.borrow() } fn set_enabled(&self, enabled: bool) { if enabled != self.imp().enabled.replace(enabled) { self.notify("enabled"); } } } } glib-0.20.9/src/gobject/binding_group.rs000064400000000000000000000404541046102023000162400ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{fmt, ptr}; use crate::{ ffi, gobject_ffi, object::ObjectRef, prelude::*, translate::*, Binding, BindingFlags, BindingGroup, BoolError, Object, ParamSpec, Value, }; impl BindingGroup { #[doc(alias = "bind_with_closures")] pub fn bind<'a, O: ObjectType>( &'a self, source_property: &'a str, target: &'a O, target_property: &'a str, ) -> BindingGroupBuilder<'a> { BindingGroupBuilder::new(self, source_property, target, target_property) } } type TransformFn = Option Option + Send + Sync + 'static>>; // rustdoc-stripper-ignore-next /// Builder for binding group bindings. #[must_use = "The builder must be built to be used"] pub struct BindingGroupBuilder<'a> { group: &'a BindingGroup, source_property: &'a str, target: &'a ObjectRef, target_property: &'a str, flags: BindingFlags, transform_to: TransformFn, transform_from: TransformFn, } impl fmt::Debug for BindingGroupBuilder<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("BindingGroupBuilder") .field("group", &self.group) .field("source_property", &self.source_property) .field("target", &self.target) .field("target_property", &self.target_property) .field("flags", &self.flags) .finish() } } impl<'a> BindingGroupBuilder<'a> { fn new( group: &'a BindingGroup, source_property: &'a str, target: &'a impl ObjectType, target_property: &'a str, ) -> Self { Self { group, source_property, target: target.as_object_ref(), target_property, flags: BindingFlags::DEFAULT, transform_to: None, transform_from: None, } } // rustdoc-stripper-ignore-next /// Transform changed property values from the target object to the source object with the given closure. pub fn transform_from Option + Send + Sync + 'static>( self, func: F, ) -> Self { Self { transform_from: Some(Box::new(func)), ..self } } // rustdoc-stripper-ignore-next /// Transform changed property values from the source object to the target object with the given closure. pub fn transform_to Option + Send + Sync + 'static>( self, func: F, ) -> Self { Self { transform_to: Some(Box::new(func)), ..self } } // rustdoc-stripper-ignore-next /// Bind the properties with the given flags. pub fn flags(self, flags: BindingFlags) -> Self { Self { flags, ..self } } // rustdoc-stripper-ignore-next /// Set the binding flags to [`BIDIRECTIONAL`][crate::BindingFlags::BIDIRECTIONAL]. pub fn bidirectional(mut self) -> Self { self.flags |= crate::BindingFlags::BIDIRECTIONAL; self } // rustdoc-stripper-ignore-next /// Set the binding flags to [`SYNC_CREATE`][crate::BindingFlags::SYNC_CREATE]. pub fn sync_create(mut self) -> Self { self.flags |= crate::BindingFlags::SYNC_CREATE; self } // rustdoc-stripper-ignore-next /// Set the binding flags to [`INVERT_BOOLEAN`][crate::BindingFlags::INVERT_BOOLEAN]. pub fn invert_boolean(mut self) -> Self { self.flags |= crate::BindingFlags::INVERT_BOOLEAN; self } // rustdoc-stripper-ignore-next /// Establish the property binding. /// /// This fails if the provided properties do not exist. pub fn try_build(self) -> Result<(), BoolError> { unsafe extern "C" fn transform_to_trampoline( binding: *mut gobject_ffi::GBinding, from_value: *const gobject_ffi::GValue, to_value: *mut gobject_ffi::GValue, user_data: ffi::gpointer, ) -> ffi::gboolean { let transform_data = &*(user_data as *const (TransformFn, TransformFn, String, ParamSpec)); match (transform_data.0.as_ref().unwrap())( &from_glib_borrow(binding), &*(from_value as *const Value), ) { None => false, Some(res) => { assert!( res.type_().is_a(transform_data.3.value_type()), "Target property {} expected type {} but transform_to function returned {}", transform_data.3.name(), transform_data.3.value_type(), res.type_() ); *to_value = res.into_raw(); true } } .into_glib() } unsafe extern "C" fn transform_from_trampoline( binding: *mut gobject_ffi::GBinding, from_value: *const gobject_ffi::GValue, to_value: *mut gobject_ffi::GValue, user_data: ffi::gpointer, ) -> ffi::gboolean { let transform_data = &*(user_data as *const (TransformFn, TransformFn, String, ParamSpec)); let binding = from_glib_borrow(binding); match (transform_data.1.as_ref().unwrap())( &binding, &*(from_value as *const Value), ) { None => false, Some(res) => { let pspec_name = transform_data.2.clone(); let source = binding.source().unwrap(); let pspec = source.find_property(&pspec_name); assert!(pspec.is_some(), "Source object does not have a property {pspec_name}"); let pspec = pspec.unwrap(); assert!( res.type_().is_a(pspec.value_type()), "Source property {pspec_name} expected type {} but transform_from function returned {}", pspec.value_type(), res.type_() ); *to_value = res.into_raw(); true } } .into_glib() } unsafe extern "C" fn free_transform_data(data: ffi::gpointer) { let _ = Box::from_raw(data as *mut (TransformFn, TransformFn, String, ParamSpec)); } let mut _source_property_name_cstr = None; let source_property_name = if let Some(source) = self.group.source() { let source_property = source.find_property(self.source_property).ok_or_else(|| { bool_error!( "Source property {} on type {} not found", self.source_property, source.type_() ) })?; // This is NUL-terminated from the C side source_property.name().as_ptr() } else { // This is a Rust &str and needs to be NUL-terminated first let source_property_name = std::ffi::CString::new(self.source_property).unwrap(); let source_property_name_ptr = source_property_name.as_ptr() as *const u8; _source_property_name_cstr = Some(source_property_name); source_property_name_ptr }; unsafe { let target: Object = from_glib_none(self.target.clone().to_glib_none().0); let target_property = target.find_property(self.target_property).ok_or_else(|| { bool_error!( "Target property {} on type {} not found", self.target_property, target.type_() ) })?; let target_property_name = target_property.name().as_ptr(); let have_transform_to = self.transform_to.is_some(); let have_transform_from = self.transform_from.is_some(); let transform_data = if have_transform_to || have_transform_from { Box::into_raw(Box::new(( self.transform_to, self.transform_from, String::from_glib_none(source_property_name as *const _), target_property, ))) } else { ptr::null_mut() }; gobject_ffi::g_binding_group_bind_full( self.group.to_glib_none().0, source_property_name as *const _, target.to_glib_none().0, target_property_name as *const _, self.flags.into_glib(), if have_transform_to { Some(transform_to_trampoline) } else { None }, if have_transform_from { Some(transform_from_trampoline) } else { None }, transform_data as ffi::gpointer, if transform_data.is_null() { None } else { Some(free_transform_data) }, ); } Ok(()) } // rustdoc-stripper-ignore-next /// Similar to `try_build` but panics instead of failing. pub fn build(self) { self.try_build().unwrap() } } #[cfg(test)] mod test { use crate::{prelude::*, subclass::prelude::*}; #[test] fn binding_without_source() { let binding_group = crate::BindingGroup::new(); let source = TestObject::default(); let target = TestObject::default(); assert!(source.find_property("name").is_some()); binding_group .bind("name", &target, "name") .bidirectional() .build(); binding_group.set_source(Some(&source)); source.set_name("test_source_name"); assert_eq!(source.name(), target.name()); target.set_name("test_target_name"); assert_eq!(source.name(), target.name()); } #[test] fn binding_with_source() { let binding_group = crate::BindingGroup::new(); let source = TestObject::default(); let target = TestObject::default(); binding_group.set_source(Some(&source)); binding_group.bind("name", &target, "name").build(); source.set_name("test_source_name"); assert_eq!(source.name(), target.name()); } #[test] fn binding_to_transform() { let binding_group = crate::BindingGroup::new(); let source = TestObject::default(); let target = TestObject::default(); binding_group.set_source(Some(&source)); binding_group .bind("name", &target, "name") .sync_create() .transform_to(|_binding, value| { let value = value.get::<&str>().unwrap(); Some(format!("{value} World").to_value()) }) .transform_from(|_binding, value| { let value = value.get::<&str>().unwrap(); Some(format!("{value} World").to_value()) }) .build(); source.set_name("Hello"); assert_eq!(target.name(), "Hello World"); } #[test] fn binding_from_transform() { let binding_group = crate::BindingGroup::new(); let source = TestObject::default(); let target = TestObject::default(); binding_group.set_source(Some(&source)); binding_group .bind("name", &target, "name") .sync_create() .bidirectional() .transform_to(|_binding, value| { let value = value.get::<&str>().unwrap(); Some(format!("{value} World").to_value()) }) .transform_from(|_binding, value| { let value = value.get::<&str>().unwrap(); Some(format!("{value} World").to_value()) }) .build(); target.set_name("Hello"); assert_eq!(source.name(), "Hello World"); } #[test] fn binding_to_transform_change_type() { let binding_group = crate::BindingGroup::new(); let source = TestObject::default(); let target = TestObject::default(); binding_group.set_source(Some(&source)); binding_group .bind("name", &target, "enabled") .sync_create() .transform_to(|_binding, value| { let value = value.get::<&str>().unwrap(); Some((value == "Hello").to_value()) }) .transform_from(|_binding, value| { let value = value.get::().unwrap(); Some((if value { "Hello" } else { "World" }).to_value()) }) .build(); source.set_name("Hello"); assert!(target.enabled()); source.set_name("Hello World"); assert!(!target.enabled()); } #[test] fn binding_from_transform_change_type() { let binding_group = crate::BindingGroup::new(); let source = TestObject::default(); let target = TestObject::default(); binding_group.set_source(Some(&source)); binding_group .bind("name", &target, "enabled") .sync_create() .bidirectional() .transform_to(|_binding, value| { let value = value.get::<&str>().unwrap(); Some((value == "Hello").to_value()) }) .transform_from(|_binding, value| { let value = value.get::().unwrap(); Some((if value { "Hello" } else { "World" }).to_value()) }) .build(); target.set_enabled(true); assert_eq!(source.name(), "Hello"); target.set_enabled(false); assert_eq!(source.name(), "World"); } mod imp { use std::{cell::RefCell, sync::OnceLock}; use super::*; use crate as glib; #[derive(Debug, Default)] pub struct TestObject { pub name: RefCell, pub enabled: RefCell, } #[crate::object_subclass] impl ObjectSubclass for TestObject { const NAME: &'static str = "TestBindingGroup"; type Type = super::TestObject; } impl ObjectImpl for TestObject { fn properties() -> &'static [crate::ParamSpec] { static PROPERTIES: OnceLock> = OnceLock::new(); PROPERTIES.get_or_init(|| { vec![ crate::ParamSpecString::builder("name") .explicit_notify() .build(), crate::ParamSpecBoolean::builder("enabled") .explicit_notify() .build(), ] }) } fn property(&self, _id: usize, pspec: &crate::ParamSpec) -> crate::Value { let obj = self.obj(); match pspec.name() { "name" => obj.name().to_value(), "enabled" => obj.enabled().to_value(), _ => unimplemented!(), } } fn set_property(&self, _id: usize, value: &crate::Value, pspec: &crate::ParamSpec) { let obj = self.obj(); match pspec.name() { "name" => obj.set_name(value.get().unwrap()), "enabled" => obj.set_enabled(value.get().unwrap()), _ => unimplemented!(), }; } } } crate::wrapper! { pub struct TestObject(ObjectSubclass); } impl Default for TestObject { fn default() -> Self { crate::Object::new() } } impl TestObject { fn name(&self) -> String { self.imp().name.borrow().clone() } fn set_name(&self, name: &str) { if name != self.imp().name.replace(name.to_string()).as_str() { self.notify("name"); } } fn enabled(&self) -> bool { *self.imp().enabled.borrow() } fn set_enabled(&self, enabled: bool) { if enabled != self.imp().enabled.replace(enabled) { self.notify("enabled"); } } } } glib-0.20.9/src/gobject/dynamic_object.rs000064400000000000000000000064361046102023000163660ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::{ enums::{EnumValues, FlagsValues}, prelude::*, subclass::prelude::*, InterfaceInfo, TypeFlags, TypeInfo, TypeModule, TypePlugin, }; mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait DynamicObjectRegisterExt: AsRef + sealed::Sealed + 'static { fn add_dynamic_interface( &self, instance_type: crate::types::Type, interface_type: crate::types::Type, interface_info: &InterfaceInfo, ); fn register_dynamic_enum( &self, name: &str, const_static_values: &'static EnumValues, ) -> crate::types::Type; fn register_dynamic_flags( &self, name: &str, const_static_values: &'static FlagsValues, ) -> crate::types::Type; fn register_dynamic_type( &self, parent_type: crate::types::Type, type_name: &str, type_info: &TypeInfo, flags: TypeFlags, ) -> crate::types::Type; } impl + ObjectSubclassIsExt> DynamicObjectRegisterExt for O where O::Subclass: TypePluginRegisterImpl, { fn add_dynamic_interface( &self, instance_type: crate::types::Type, interface_type: crate::types::Type, interface_info: &InterfaceInfo, ) { self.imp() .add_dynamic_interface(instance_type, interface_type, interface_info); } fn register_dynamic_enum( &self, name: &str, const_static_values: &'static EnumValues, ) -> crate::types::Type { self.imp().register_dynamic_enum(name, const_static_values) } fn register_dynamic_flags( &self, name: &str, const_static_values: &'static FlagsValues, ) -> crate::types::Type { self.imp().register_dynamic_flags(name, const_static_values) } fn register_dynamic_type( &self, parent_type: crate::types::Type, type_name: &str, type_info: &TypeInfo, flags: TypeFlags, ) -> crate::types::Type { self.imp() .register_dynamic_type(parent_type, type_name, type_info, flags) } } impl DynamicObjectRegisterExt for TypeModule { fn add_dynamic_interface( &self, instance_type: crate::types::Type, interface_type: crate::types::Type, interface_info: &InterfaceInfo, ) { ::add_interface(self, instance_type, interface_type, interface_info); } fn register_dynamic_enum( &self, name: &str, const_static_values: &'static EnumValues, ) -> crate::types::Type { ::register_enum(self, name, const_static_values) } fn register_dynamic_flags( &self, name: &str, const_static_values: &'static FlagsValues, ) -> crate::types::Type { ::register_flags(self, name, const_static_values) } fn register_dynamic_type( &self, parent_type: crate::types::Type, type_name: &str, type_info: &TypeInfo, flags: TypeFlags, ) -> crate::types::Type { ::register_type(self, parent_type, type_name, type_info, flags) } } glib-0.20.9/src/gobject/flags.rs000064400000000000000000000036041046102023000145020ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::{gobject_ffi, translate::*}; bitflags::bitflags! { #[doc(alias = "GParamFlags")] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct ParamFlags: u32 { #[doc(alias = "G_PARAM_READABLE")] const READABLE = gobject_ffi::G_PARAM_READABLE as _; #[doc(alias = "G_PARAM_WRITABLE")] const WRITABLE = gobject_ffi::G_PARAM_WRITABLE as _; #[doc(alias = "G_PARAM_READWRITE")] const READWRITE = gobject_ffi::G_PARAM_READWRITE as _; #[doc(alias = "G_PARAM_CONSTRUCT")] const CONSTRUCT = gobject_ffi::G_PARAM_CONSTRUCT as _; #[doc(alias = "G_PARAM_CONSTRUCT_ONLY")] const CONSTRUCT_ONLY = gobject_ffi::G_PARAM_CONSTRUCT_ONLY as _; #[doc(alias = "G_PARAM_LAX_VALIDATION")] const LAX_VALIDATION = gobject_ffi::G_PARAM_LAX_VALIDATION as _; const USER_0 = 256; const USER_1 = 512; const USER_2 = 1024; const USER_3 = 2048; const USER_4 = 4096; const USER_5 = 8192; const USER_6 = 16384; const USER_7 = 32768; const USER_8 = 65536; #[doc(alias = "G_PARAM_EXPLICIT_NOTIFY")] const EXPLICIT_NOTIFY = gobject_ffi::G_PARAM_EXPLICIT_NOTIFY as _; #[doc(alias = "G_PARAM_DEPRECATED")] const DEPRECATED = gobject_ffi::G_PARAM_DEPRECATED as _; } } impl Default for ParamFlags { fn default() -> Self { ParamFlags::READWRITE } } #[doc(hidden)] impl IntoGlib for ParamFlags { type GlibType = gobject_ffi::GParamFlags; #[inline] fn into_glib(self) -> gobject_ffi::GParamFlags { self.bits() } } #[doc(hidden)] impl FromGlib for ParamFlags { #[inline] unsafe fn from_glib(value: gobject_ffi::GParamFlags) -> Self { Self::from_bits_truncate(value) } } glib-0.20.9/src/gobject/interface_info.rs000064400000000000000000000021651046102023000163620ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::gobject_ffi; #[derive(Debug, Copy, Clone)] #[doc(alias = "GInterfaceInfo")] #[repr(transparent)] pub struct InterfaceInfo(pub(crate) gobject_ffi::GInterfaceInfo); impl InterfaceInfo { // rustdoc-stripper-ignore-next /// Returns a `GInterfaceInfo` pointer. #[doc(hidden)] #[inline] pub fn as_ptr(&self) -> *mut gobject_ffi::GInterfaceInfo { &self.0 as *const gobject_ffi::GInterfaceInfo as *mut _ } // rustdoc-stripper-ignore-next /// Borrows the underlying C value mutably. #[doc(hidden)] #[inline] pub unsafe fn from_glib_ptr_borrow_mut<'a>( ptr: *mut gobject_ffi::GInterfaceInfo, ) -> &'a mut Self { &mut *(ptr as *mut Self) } } impl Default for InterfaceInfo { // rustdoc-stripper-ignore-next /// Creates a new InterfaceInfo with default value. fn default() -> Self { Self(gobject_ffi::GInterfaceInfo { interface_init: None, interface_finalize: None, interface_data: ::std::ptr::null_mut(), }) } } glib-0.20.9/src/gobject/mod.rs000064400000000000000000000020541046102023000141630ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! GObject bindings #[allow(unused_imports)] mod auto; mod binding; #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] mod binding_group; mod flags; #[cfg(feature = "v2_74")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))] mod signal_group; #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] pub use binding_group::BindingGroupBuilder; pub use self::{auto::*, flags::*}; //pub use self::auto::functions::*; mod interface_info; pub use interface_info::InterfaceInfo; mod type_info; pub use type_info::TypeInfo; mod type_value_table; pub use type_value_table::TypeValueTable; mod type_module; pub use self::type_module::TypeModule; mod type_plugin; pub use self::type_plugin::TypePlugin; mod dynamic_object; #[doc(hidden)] pub mod traits { pub use super::dynamic_object::DynamicObjectRegisterExt; pub use super::type_module::TypeModuleExt; pub use super::type_plugin::TypePluginExt; } glib-0.20.9/src/gobject/signal_group.rs000064400000000000000000000202331046102023000160740ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::mem::transmute; use crate::{ ffi, gobject_ffi, prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, Object, RustClosure, SignalGroup, Value, }; impl SignalGroup { #[doc(alias = "g_signal_group_new")] pub fn new>() -> Self { Self::with_type(T::static_type()) } #[doc(alias = "g_signal_group_connect_closure")] pub fn connect_closure(&self, signal_name: &str, after: bool, closure: RustClosure) { unsafe { gobject_ffi::g_signal_group_connect_closure( self.to_glib_none().0, signal_name.to_glib_none().0, closure.as_ref().to_glib_none().0, after.into_glib(), ); } } #[doc(alias = "g_signal_group_connect")] #[inline] pub fn connect(&self, signal_name: &str, after: bool, callback: F) where F: Fn(&[Value]) -> Option + Send + Sync + 'static, { self.connect_closure(signal_name, after, RustClosure::new(callback)); } // rustdoc-stripper-ignore-next /// Like [`Self::connect`] but doesn't require a `Send+Sync` closure. Signal emission will /// panic if the signal on the current target is emitted from a different thread from the /// thread that connected the signal. #[inline] pub fn connect_local(&self, signal_name: &str, after: bool, callback: F) where F: Fn(&[Value]) -> Option + 'static, { self.connect_closure(signal_name, after, RustClosure::new_local(callback)); } #[inline] pub fn connect_notify(&self, name: Option<&str>, callback: F) where F: Fn(&crate::Object, &crate::ParamSpec) + Send + Sync + 'static, { let signal_name = if let Some(name) = name { format!("notify::{name}") } else { "notify".into() }; let closure = crate::RustClosure::new(move |values| { let obj = values[0].get().unwrap(); let pspec = values[1].get().unwrap(); callback(obj, pspec); None }); self.connect_closure(&signal_name, false, closure); } #[inline] pub fn connect_notify_local(&self, name: Option<&str>, callback: F) where F: Fn(&crate::Object, &crate::ParamSpec) + 'static, { let signal_name = if let Some(name) = name { format!("notify::{name}") } else { "notify".into() }; let closure = crate::RustClosure::new_local(move |values| { let obj = values[0].get().unwrap(); let pspec = values[1].get().unwrap(); callback(obj, pspec); None }); self.connect_closure(&signal_name, false, closure); } unsafe fn connect_bind_unsafe(&self, f: F) -> SignalHandlerId { unsafe extern "C" fn bind_trampoline( this: *mut crate::gobject_ffi::GSignalGroup, instance: *mut crate::gobject_ffi::GObject, f: ffi::gpointer, ) { let f: &F = &*(f as *const F); f(&from_glib_borrow(this), &from_glib_borrow(instance)) } let f: Box = Box::new(f); connect_raw( self.as_ptr() as *mut _, b"bind\0".as_ptr() as *const _, Some(transmute::<*const (), unsafe extern "C" fn()>( bind_trampoline:: as *const (), )), Box::into_raw(f), ) } unsafe fn connect_unbind_unsafe(&self, f: F) -> SignalHandlerId { unsafe extern "C" fn unbind_trampoline( this: *mut crate::gobject_ffi::GSignalGroup, f: ffi::gpointer, ) { let f: &F = &*(f as *const F); f(&from_glib_borrow(this)) } let f: Box = Box::new(f); connect_raw( self.as_ptr() as *mut _, b"unbind\0".as_ptr() as *const _, Some(transmute::<*const (), unsafe extern "C" fn()>( unbind_trampoline:: as *const (), )), Box::into_raw(f), ) } #[doc(alias = "bind")] pub fn connect_bind( &self, f: F, ) -> SignalHandlerId { unsafe { self.connect_bind_unsafe(f) } } // rustdoc-stripper-ignore-next /// Like [`Self::connect_bind`] but doesn't require a `Send+Sync` closure. Signal emission will /// panic if the signal is emitted from a different thread from the thread that connected the /// signal. pub fn connect_bind_local(&self, f: F) -> SignalHandlerId { let f = crate::thread_guard::ThreadGuard::new(f); unsafe { self.connect_bind_unsafe(move |s, o| { (f.get_ref())(s, o); }) } } #[doc(alias = "unbind")] pub fn connect_unbind(&self, f: F) -> SignalHandlerId { unsafe { self.connect_unbind_unsafe(f) } } // rustdoc-stripper-ignore-next /// Like [`Self::connect_unbind`] but doesn't require a `Send+Sync` closure. Signal emission /// will panic if the signal is emitted from a different thread from the thread that connected /// the signal. pub fn connect_unbind_local(&self, f: F) -> SignalHandlerId { let f = crate::thread_guard::ThreadGuard::new(f); unsafe { self.connect_unbind_unsafe(move |s| { (f.get_ref())(s); }) } } } #[cfg(test)] mod tests { use std::{cell::RefCell, rc::Rc, sync::OnceLock}; use super::*; use crate as glib; mod imp { use super::*; use crate::subclass::{prelude::*, Signal}; #[derive(Default)] pub struct SignalObject {} #[glib::object_subclass] impl ObjectSubclass for SignalObject { const NAME: &'static str = "SignalObject"; type Type = super::SignalObject; } impl ObjectImpl for SignalObject { fn signals() -> &'static [Signal] { static SIGNALS: OnceLock> = OnceLock::new(); SIGNALS.get_or_init(|| { vec![ Signal::builder("sig-with-args") .param_types([u32::static_type(), String::static_type()]) .build(), Signal::builder("sig-with-ret") .return_type::() .build(), ] }) } } } wrapper! { pub struct SignalObject(ObjectSubclass); } #[test] fn group_emit() { let group = SignalGroup::new::(); let obj = Object::new::(); let store = Rc::new(RefCell::new(String::new())); group.connect_closure( "sig-with-args", false, glib::closure_local!( #[watch] obj, #[strong] store, move |o: &SignalObject, a: u32, b: &str| { assert_eq!(o, obj); store.replace(format!("a {a} b {b}")); } ), ); group.connect_closure( "sig-with-ret", false, glib::closure_local!( #[watch] obj, move |o: &SignalObject| -> &'static crate::GStr { assert_eq!(o, obj); crate::gstr!("Hello") } ), ); group.set_target(Some(&obj)); obj.emit_by_name::<()>("sig-with-args", &[&5u32, &"World"]); assert_eq!(*store.borrow(), "a 5 b World"); let ret = obj.emit_by_name::("sig-with-ret", &[]); assert_eq!(ret, "Hello"); group.set_target(Object::NONE); let ret = obj.emit_by_name::>("sig-with-ret", &[]); assert_eq!(ret, None); } } glib-0.20.9/src/gobject/type_info.rs000064400000000000000000000024031046102023000153760ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::gobject_ffi; #[derive(Debug, Copy, Clone)] #[doc(alias = "GTypeInfo")] #[repr(transparent)] pub struct TypeInfo(pub(crate) gobject_ffi::GTypeInfo); impl TypeInfo { // rustdoc-stripper-ignore-next /// Returns a `GTypeInfo` pointer. #[doc(hidden)] #[inline] pub fn as_ptr(&self) -> *mut gobject_ffi::GTypeInfo { &self.0 as *const gobject_ffi::GTypeInfo as *mut _ } // rustdoc-stripper-ignore-next /// Borrows the underlying C value mutably. #[doc(hidden)] #[inline] pub unsafe fn from_glib_ptr_borrow_mut<'a>(ptr: *mut gobject_ffi::GTypeInfo) -> &'a mut Self { &mut *(ptr as *mut Self) } } impl Default for TypeInfo { // rustdoc-stripper-ignore-next /// Creates a new TypeInfo with default value. fn default() -> Self { Self(gobject_ffi::GTypeInfo { class_size: 0u16, base_init: None, base_finalize: None, class_init: None, class_finalize: None, class_data: ::std::ptr::null(), instance_size: 0, n_preallocs: 0, instance_init: None, value_table: ::std::ptr::null(), }) } } glib-0.20.9/src/gobject/type_module.rs000064400000000000000000000065321046102023000157370ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::{ enums::{EnumValues, FlagsValues}, gobject_ffi, prelude::*, translate::*, InterfaceInfo, TypeFlags, TypeInfo, TypePlugin, }; crate::wrapper! { #[doc(alias = "GTypeModule")] pub struct TypeModule(Object) @implements TypePlugin; match fn { type_ => || gobject_ffi::g_type_module_get_type(), } } impl TypeModule { pub const NONE: Option<&'static TypeModule> = None; } mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait TypeModuleExt: IsA + sealed::Sealed + 'static { #[doc(alias = "g_type_module_add_interface")] fn add_interface( &self, instance_type: crate::types::Type, interface_type: crate::types::Type, interface_info: &InterfaceInfo, ) { unsafe { gobject_ffi::g_type_module_add_interface( self.as_ref().to_glib_none().0, instance_type.into_glib(), interface_type.into_glib(), interface_info.as_ptr(), ); } } #[doc(alias = "g_type_module_register_enum")] fn register_enum( &self, name: &str, const_static_values: &'static EnumValues, ) -> crate::types::Type { unsafe { from_glib(gobject_ffi::g_type_module_register_enum( self.as_ref().to_glib_none().0, name.to_glib_none().0, const_static_values.to_glib_none().0, )) } } #[doc(alias = "g_type_module_register_flags")] fn register_flags( &self, name: &str, const_static_values: &'static FlagsValues, ) -> crate::types::Type { unsafe { from_glib(gobject_ffi::g_type_module_register_flags( self.as_ref().to_glib_none().0, name.to_glib_none().0, const_static_values.to_glib_none().0, )) } } #[doc(alias = "g_type_module_register_type")] fn register_type( &self, parent_type: crate::types::Type, type_name: &str, type_info: &TypeInfo, flags: TypeFlags, ) -> crate::types::Type { unsafe { from_glib(gobject_ffi::g_type_module_register_type( self.as_ref().to_glib_none().0, parent_type.into_glib(), type_name.to_glib_none().0, type_info.as_ptr(), flags.into_glib(), )) } } #[doc(alias = "g_type_module_set_name")] fn set_name(&self, name: &str) { unsafe { gobject_ffi::g_type_module_set_name( self.as_ref().to_glib_none().0, name.to_glib_none().0, ); } } #[doc(alias = "g_type_module_unuse")] fn unuse(&self) { unsafe { gobject_ffi::g_type_module_unuse(self.as_ref().to_glib_none().0); } } #[doc(alias = "g_type_module_use")] #[doc(alias = "use")] fn use_(&self) -> bool { unsafe { from_glib(gobject_ffi::g_type_module_use( self.as_ref().to_glib_none().0, )) } } } impl> TypeModuleExt for O {} glib-0.20.9/src/gobject/type_plugin.rs000064400000000000000000000041611046102023000157440ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::{gobject_ffi, prelude::*, translate::*, InterfaceInfo, TypeInfo, TypeValueTable}; crate::wrapper! { #[doc(alias = "GTypePlugin")] pub struct TypePlugin(Interface); match fn { type_ => || gobject_ffi::g_type_plugin_get_type(), } } impl TypePlugin { pub const NONE: Option<&'static TypePlugin> = None; } mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait TypePluginExt: IsA + sealed::Sealed + 'static { #[doc(alias = "g_type_plugin_complete_interface_info")] fn complete_interface_info( &self, instance_type: crate::types::Type, interface_type: crate::types::Type, ) -> InterfaceInfo { let info = InterfaceInfo::default(); unsafe { gobject_ffi::g_type_plugin_complete_interface_info( self.as_ref().to_glib_none().0, instance_type.into_glib(), interface_type.into_glib(), info.as_ptr(), ); } info } #[doc(alias = "g_type_plugin_complete_type_info")] fn complete_type_info(&self, g_type: crate::types::Type) -> (TypeInfo, TypeValueTable) { let info = TypeInfo::default(); let value_table = TypeValueTable::default(); unsafe { gobject_ffi::g_type_plugin_complete_type_info( self.as_ref().to_glib_none().0, g_type.into_glib(), info.as_ptr(), value_table.as_ptr(), ); } (info, value_table) } #[doc(alias = "g_type_plugin_unuse")] fn unuse(&self) { unsafe { gobject_ffi::g_type_plugin_unuse(self.as_ref().to_glib_none().0); } } #[doc(alias = "g_type_plugin_use")] #[doc(alias = "use")] fn use_(&self) { unsafe { gobject_ffi::g_type_plugin_use(self.as_ref().to_glib_none().0); } } } impl> TypePluginExt for O {} glib-0.20.9/src/gobject/type_value_table.rs000064400000000000000000000024421046102023000167310ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::gobject_ffi; #[derive(Debug, Copy, Clone)] #[doc(alias = "GTypeValueTable")] #[repr(transparent)] pub struct TypeValueTable(pub(crate) gobject_ffi::GTypeValueTable); impl TypeValueTable { // rustdoc-stripper-ignore-next /// Returns a `GTypeValueTable` pointer. #[doc(hidden)] #[inline] pub fn as_ptr(&self) -> *mut gobject_ffi::GTypeValueTable { &self.0 as *const gobject_ffi::GTypeValueTable as *mut _ } // rustdoc-stripper-ignore-next /// Borrows the underlying C value mutably. #[doc(hidden)] #[inline] pub unsafe fn from_glib_ptr_borrow_mut<'a>( ptr: *mut gobject_ffi::GTypeValueTable, ) -> &'a mut Self { &mut *(ptr as *mut Self) } } impl Default for TypeValueTable { // rustdoc-stripper-ignore-next /// Creates a new TypeValueTable with default value. fn default() -> Self { Self(gobject_ffi::GTypeValueTable { value_init: None, value_free: None, value_copy: None, value_peek_pointer: None, collect_format: ::std::ptr::null(), collect_value: None, lcopy_format: ::std::ptr::null(), lcopy_value: None, }) } } glib-0.20.9/src/gstring.rs000064400000000000000000002264661046102023000134630ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ borrow::{Borrow, Cow}, cmp::Ordering, ffi::{CStr, CString, OsStr, OsString}, fmt, hash, marker::PhantomData, mem, ops::Deref, os::raw::{c_char, c_void}, path::{Path, PathBuf}, ptr, slice, }; use crate::{ffi, gobject_ffi, prelude::*, translate::*, Type, Value}; // rustdoc-stripper-ignore-next /// Representation of a borrowed [`GString`]. /// /// This type is very similar to [`std::ffi::CStr`], but with one added constraint: the string /// must also be valid UTF-8. #[repr(transparent)] pub struct GStr(str); impl GStr { // rustdoc-stripper-ignore-next /// Creates a GLib string wrapper from a byte slice. /// /// This function will cast the provided bytes to a `GStr` wrapper after ensuring that the byte /// slice is valid UTF-8 and is nul-terminated. #[inline] pub fn from_utf8_with_nul(bytes: &[u8]) -> Result<&Self, GStrError> { Self::check_trailing_nul(bytes)?; std::str::from_utf8(bytes)?; Ok(unsafe { mem::transmute::<&[u8], &GStr>(bytes) }) } // rustdoc-stripper-ignore-next /// Creates a GLib string wrapper from a byte slice, checking for interior nul-bytes. /// /// This function will cast the provided bytes to a `GStr` wrapper after ensuring that the byte /// slice is valid UTF-8, is nul-terminated, and does not contain any interior nul-bytes. #[inline] pub fn from_utf8_with_nul_checked(bytes: &[u8]) -> Result<&Self, GStrError> { Self::check_nuls(bytes)?; std::str::from_utf8(bytes)?; Ok(unsafe { mem::transmute::<&[u8], &GStr>(bytes) }) } // rustdoc-stripper-ignore-next /// Unsafely creates a GLib string wrapper from a byte slice. /// /// This function will cast the provided `bytes` to a `GStr` wrapper without performing any /// sanity checks. /// /// # Safety /// /// The provided slice **must** be valid UTF-8 and nul-terminated. It is undefined behavior to /// pass a slice that does not uphold those conditions. #[inline] pub const unsafe fn from_utf8_with_nul_unchecked(bytes: &[u8]) -> &Self { debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0); debug_assert!(std::str::from_utf8(bytes).is_ok()); mem::transmute::<&[u8], &GStr>(bytes) } // rustdoc-stripper-ignore-next /// Creates a GLib string wrapper from a byte slice, truncating it at the first nul-byte. /// /// This function will cast the provided bytes to a `GStr` wrapper after ensuring that the byte /// slice is valid UTF-8 and contains at least one nul-byte. #[inline] pub fn from_utf8_until_nul(bytes: &[u8]) -> Result<&Self, GStrError> { let nul_pos = memchr::memchr(0, bytes).ok_or(GStrError::NoTrailingNul)?; let bytes = unsafe { bytes.get_unchecked(..nul_pos + 1) }; std::str::from_utf8(bytes)?; Ok(unsafe { mem::transmute::<&[u8], &GStr>(bytes) }) } // rustdoc-stripper-ignore-next /// Creates a GLib string wrapper from a string slice. /// /// The string slice must be terminated with a nul-byte. /// /// This function will cast the provided bytes to a `GStr` wrapper after ensuring /// that the string slice is nul-terminated. #[inline] pub fn from_str_with_nul(s: &str) -> Result<&Self, GStrError> { Self::check_trailing_nul(s)?; Ok(unsafe { mem::transmute::<&str, &GStr>(s) }) } // rustdoc-stripper-ignore-next /// Creates a GLib string wrapper from a string slice, checking for interior nul-bytes. /// /// The string slice must be terminated with a nul-byte. /// /// This function will cast the provided bytes to a `GStr` wrapper after ensuring /// that the string slice is nul-terminated and does not contain any interior nul-bytes. #[inline] pub fn from_str_with_nul_checked(s: &str) -> Result<&Self, GStrError> { Self::check_nuls(s)?; Ok(unsafe { mem::transmute::<&str, &GStr>(s) }) } // rustdoc-stripper-ignore-next /// Unsafely creates a GLib string wrapper from a string slice. The string slice must be /// terminated with a nul-byte. /// /// This function will cast the provided string slice to a `GStr` without performing any sanity /// checks. /// /// # Safety /// /// The provided string slice **must** be nul-terminated. It is undefined behavior to pass a /// slice that does not uphold those conditions. #[inline] pub const unsafe fn from_str_with_nul_unchecked(s: &str) -> &Self { debug_assert!(!s.is_empty() && s.as_bytes()[s.len() - 1] == 0); mem::transmute::<&str, &GStr>(s) } // rustdoc-stripper-ignore-next /// Creates a GLib string wrapper from a string slice, truncating it at the first nul-byte. /// /// The string slice must contain at least one nul-byte. /// /// This function will cast the provided bytes to a `GStr` wrapper after ensuring /// that the string slice contains at least one nul-byte. #[inline] pub fn from_str_until_nul(s: &str) -> Result<&Self, GStrError> { let b = s.as_bytes(); let nul_pos = memchr::memchr(0, b).ok_or(GStrError::NoTrailingNul)?; let s = unsafe { std::str::from_utf8_unchecked(b.get_unchecked(..nul_pos + 1)) }; Ok(unsafe { mem::transmute::<&str, &GStr>(s) }) } // rustdoc-stripper-ignore-next /// Wraps a raw C string with a safe GLib string wrapper. The provided C string **must** be /// valid UTF-8 and nul-terminated. All constraints from [`CStr::from_ptr`] also apply here. /// /// # Safety /// /// See [`CStr::from_ptr`](std::ffi::CStr#safety). #[inline] pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a Self { let cstr = CStr::from_ptr(ptr); Self::from_utf8_with_nul_unchecked(cstr.to_bytes_with_nul()) } // rustdoc-stripper-ignore-next /// Wraps a raw C string with a safe GLib string wrapper. The provided C string **must** be /// nul-terminated. All constraints from [`std::ffi::CStr::from_ptr`] also apply here. /// /// If the string is valid UTF-8 then it is directly returned, otherwise `None` is returned. #[inline] pub unsafe fn from_ptr_checked<'a>(ptr: *const c_char) -> Option<&'a Self> { let mut end_ptr = ptr::null(); if ffi::g_utf8_validate(ptr as *const _, -1, &mut end_ptr) != ffi::GFALSE { Some(Self::from_utf8_with_nul_unchecked(slice::from_raw_parts( ptr as *const u8, end_ptr.offset_from(ptr) as usize + 1, ))) } else { None } } // rustdoc-stripper-ignore-next /// Wraps a raw C string with a safe GLib string wrapper. The provided C string **must** be /// nul-terminated. All constraints from [`std::ffi::CStr::from_ptr`] also apply here. /// /// If the string is valid UTF-8 then it is directly returned otherwise a copy is created with /// every invalid character replaced by the Unicode replacement character (U+FFFD). #[inline] pub unsafe fn from_ptr_lossy<'a>(ptr: *const c_char) -> Cow<'a, Self> { if let Some(gs) = Self::from_ptr_checked(ptr) { Cow::Borrowed(gs) } else { Cow::Owned(GString::from_glib_full(ffi::g_utf8_make_valid( ptr as *const _, -1, ))) } } // rustdoc-stripper-ignore-next /// Converts this GLib string to a byte slice containing the trailing 0 byte. /// /// This function is the equivalent of [`GStr::as_bytes`] except that it will retain the /// trailing nul terminator instead of chopping it off. #[inline] pub const fn as_bytes_with_nul(&self) -> &[u8] { self.0.as_bytes() } // rustdoc-stripper-ignore-next /// Converts this GLib string to a byte slice. /// /// The returned slice will **not** contain the trailing nul terminator that this GLib /// string has. #[inline] pub const fn as_bytes(&self) -> &[u8] { self.as_str().as_bytes() } // rustdoc-stripper-ignore-next /// Returns the inner pointer to this GLib string. /// /// The returned pointer will be valid for as long as `self` is, and points to a contiguous /// region of memory terminated with a 0 byte to represent the end of the string. /// /// **WARNING** /// /// The returned pointer is read-only; writing to it (including passing it to C code that /// writes to it) causes undefined behavior. It is your responsibility to make /// sure that the underlying memory is not freed too early. #[inline] pub const fn as_ptr(&self) -> *const c_char { self.0.as_ptr() as *const _ } // rustdoc-stripper-ignore-next /// Converts this GLib string to a string slice. #[inline] pub const fn as_str(&self) -> &str { // Clip off the nul-byte unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts( self.as_ptr() as *const _, self.0.len() - 1, )) } } // rustdoc-stripper-ignore-next /// Converts this GLib string to a C string slice, checking for interior nul-bytes. /// /// Returns `Err` if the string contains any interior nul-bytes. #[inline] pub fn to_cstr(&self) -> Result<&CStr, GStrInteriorNulError> { Self::check_interior_nuls(self.as_bytes())?; Ok(unsafe { self.to_cstr_unchecked() }) } // rustdoc-stripper-ignore-next /// Converts this GLib string to a C string slice, truncating it at the first nul-byte. #[inline] pub fn to_cstr_until_nul(&self) -> &CStr { let b = self.as_bytes_with_nul(); let nul_pos = memchr::memchr(0, b).unwrap(); unsafe { CStr::from_bytes_with_nul_unchecked(b.get_unchecked(..nul_pos + 1)) } } // rustdoc-stripper-ignore-next /// Converts this GLib string to a C string slice, without checking for interior nul-bytes. /// /// # Safety /// /// `self` **must** not contain any interior nul-bytes besides the final terminating nul-byte. /// It is undefined behavior to call this on a string that contains interior nul-bytes. #[inline] pub const unsafe fn to_cstr_unchecked(&self) -> &CStr { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) } #[doc(alias = "g_utf8_collate")] #[doc(alias = "utf8_collate")] pub fn collate(&self, other: impl IntoGStr) -> Ordering { other.run_with_gstr(|other| { unsafe { ffi::g_utf8_collate(self.to_glib_none().0, other.to_glib_none().0) }.cmp(&0) }) } #[inline] fn check_nuls(s: impl AsRef<[u8]>) -> Result<(), GStrError> { let s = s.as_ref(); if let Some(nul_pos) = memchr::memchr(0, s) { if s.len() == nul_pos + 1 { Ok(()) } else { Err(GStrInteriorNulError(nul_pos).into()) } } else { Err(GStrError::NoTrailingNul) } } #[inline] fn check_trailing_nul(s: impl AsRef<[u8]>) -> Result<(), GStrError> { if let Some(c) = s.as_ref().last().copied() { if c == 0 { return Ok(()); } } Err(GStrError::NoTrailingNul) } // rustdoc-stripper-ignore-next /// Returns `Err` if the string slice contains any nul-bytes. #[inline] pub(crate) fn check_interior_nuls(s: impl AsRef<[u8]>) -> Result<(), GStrInteriorNulError> { if let Some(nul_pos) = memchr::memchr(0, s.as_ref()) { Err(GStrInteriorNulError(nul_pos)) } else { Ok(()) } } pub const NONE: Option<&'static GStr> = None; } // rustdoc-stripper-ignore-next /// Error type holding all possible failures when creating a [`GStr`] reference. #[derive(Debug)] pub enum GStrError { InvalidUtf8(std::str::Utf8Error), InteriorNul(GStrInteriorNulError), NoTrailingNul, } impl std::error::Error for GStrError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { Self::InvalidUtf8(err) => std::error::Error::source(err), Self::InteriorNul(err) => std::error::Error::source(err), Self::NoTrailingNul => None, } } } impl fmt::Display for GStrError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { Self::InvalidUtf8(err) => fmt::Display::fmt(err, fmt), Self::InteriorNul(err) => fmt::Display::fmt(err, fmt), Self::NoTrailingNul => fmt.write_str("data provided is not nul terminated"), } } } impl std::convert::From for GStrError { fn from(err: std::str::Utf8Error) -> Self { Self::InvalidUtf8(err) } } impl std::convert::From for GStrError { fn from(err: GStrInteriorNulError) -> Self { Self::InteriorNul(err) } } // rustdoc-stripper-ignore-next /// Error type indicating that a buffer had unexpected nul-bytes. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct GStrInteriorNulError(usize); impl std::error::Error for GStrInteriorNulError {} impl fmt::Display for GStrInteriorNulError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!( fmt, "data provided contains an interior nul-byte at byte pos {}", self.0 ) } } impl GStrInteriorNulError { // rustdoc-stripper-ignore-next /// Returns the position of the nul-byte in the slice that caused the conversion to fail. #[inline] pub fn nul_position(&self) -> usize { self.0 } } // rustdoc-stripper-ignore-next /// Converts a static string literal into a static nul-terminated string. /// /// The expanded expression has type [`&'static GStr`]. This macro will panic if the /// string literal contains any interior nul-bytes. /// /// # Examples /// /// ``` /// # fn main() { /// use glib::{gstr, GStr, GString}; /// /// const MY_STRING: &GStr = gstr!("Hello"); /// assert_eq!(MY_STRING.as_bytes_with_nul()[5], 0u8); /// let owned: GString = MY_STRING.to_owned(); /// assert_eq!(MY_STRING, owned); /// # } /// ``` /// /// [`&'static GStr`]: crate::GStr #[macro_export] macro_rules! gstr { ($s:literal) => { unsafe { $crate::GStr::from_utf8_with_nul_unchecked($crate::cstr_bytes!($s)) } }; } impl fmt::Debug for GStr { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { <&str as fmt::Debug>::fmt(&self.as_str(), f) } } impl PartialEq for GStr { #[inline] fn eq(&self, other: &Self) -> bool { self.as_str().eq(other.as_str()) } } impl Eq for GStr {} impl PartialOrd for GStr { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for GStr { #[inline] fn cmp(&self, other: &Self) -> Ordering { self.as_str().cmp(other.as_str()) } } impl hash::Hash for GStr { #[inline] fn hash(&self, state: &mut H) { self.as_str().hash(state) } } impl Default for &GStr { #[inline] fn default() -> Self { const SLICE: &[c_char] = &[0]; unsafe { GStr::from_ptr(SLICE.as_ptr()) } } } impl fmt::Display for GStr { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.as_str()) } } impl<'a> TryFrom<&'a CStr> for &'a GStr { type Error = std::str::Utf8Error; #[inline] fn try_from(s: &'a CStr) -> Result { s.to_str()?; Ok(unsafe { GStr::from_utf8_with_nul_unchecked(s.to_bytes_with_nul()) }) } } impl PartialEq for String { #[inline] fn eq(&self, other: &GStr) -> bool { self.as_str() == other.as_str() } } impl PartialEq for GStr { #[inline] fn eq(&self, other: &str) -> bool { self.as_str() == other } } impl PartialEq<&str> for GStr { #[inline] fn eq(&self, other: &&str) -> bool { self.as_str() == *other } } impl PartialEq for &str { #[inline] fn eq(&self, other: &GStr) -> bool { *self == other.as_str() } } impl PartialEq for GStr { #[inline] fn eq(&self, other: &String) -> bool { self.as_str() == other.as_str() } } impl PartialEq for str { #[inline] fn eq(&self, other: &GStr) -> bool { self == other.as_str() } } impl PartialOrd for String { #[inline] fn partial_cmp(&self, other: &GStr) -> Option { Some(self.cmp(&String::from(other.as_str()))) } } impl PartialOrd for GStr { #[inline] fn partial_cmp(&self, other: &String) -> Option { Some(self.as_str().cmp(other.as_str())) } } impl PartialOrd for str { #[inline] fn partial_cmp(&self, other: &GStr) -> Option { Some(self.cmp(other.as_str())) } } impl PartialOrd for GStr { #[inline] fn partial_cmp(&self, other: &str) -> Option { Some(self.as_str().cmp(other)) } } impl AsRef for GStr { #[inline] fn as_ref(&self) -> &GStr { self } } impl AsRef for GStr { #[inline] fn as_ref(&self) -> &str { self.as_str() } } impl AsRef for GStr { #[inline] fn as_ref(&self) -> &OsStr { OsStr::new(self.as_str()) } } impl AsRef for GStr { #[inline] fn as_ref(&self) -> &Path { Path::new(self.as_str()) } } impl AsRef<[u8]> for GStr { #[inline] fn as_ref(&self) -> &[u8] { self.as_bytes() } } impl Deref for GStr { type Target = str; #[inline] fn deref(&self) -> &str { self.as_str() } } impl ToOwned for GStr { type Owned = GString; #[inline] fn to_owned(&self) -> Self::Owned { let b = self.as_bytes_with_nul(); if self.len() < INLINE_LEN { let mut data = <[u8; INLINE_LEN]>::default(); let b = self.as_bytes(); unsafe { data.get_unchecked_mut(..b.len()) }.copy_from_slice(b); return GString(Inner::Inline { len: self.len() as u8, data, }); } let inner = unsafe { let copy = ffi::g_strndup(b.as_ptr() as *const c_char, b.len()); Inner::Foreign { ptr: ptr::NonNull::new_unchecked(copy), len: b.len() - 1, } }; GString(inner) } } impl GlibPtrDefault for GStr { type GlibType = *mut c_char; } impl StaticType for GStr { #[inline] fn static_type() -> Type { str::static_type() } } #[doc(hidden)] impl FromGlibPtrNone<*const u8> for &GStr { #[inline] unsafe fn from_glib_none(ptr: *const u8) -> Self { debug_assert!(!ptr.is_null()); let cstr = CStr::from_ptr(ptr as *const _); debug_assert!(cstr.to_str().is_ok(), "C string is not valid utf-8"); GStr::from_utf8_with_nul_unchecked(cstr.to_bytes_with_nul()) } } #[doc(hidden)] impl FromGlibPtrNone<*const i8> for &GStr { #[inline] unsafe fn from_glib_none(ptr: *const i8) -> Self { from_glib_none(ptr as *const u8) } } #[doc(hidden)] impl FromGlibPtrNone<*mut u8> for &GStr { #[inline] unsafe fn from_glib_none(ptr: *mut u8) -> Self { from_glib_none(ptr as *const u8) } } #[doc(hidden)] impl FromGlibPtrNone<*mut i8> for &GStr { #[inline] unsafe fn from_glib_none(ptr: *mut i8) -> Self { from_glib_none(ptr as *const u8) } } unsafe impl<'a> crate::value::FromValue<'a> for &'a GStr { type Checker = crate::value::GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a Value) -> Self { let ptr = gobject_ffi::g_value_get_string(value.to_glib_none().0); let cstr = CStr::from_ptr(ptr); debug_assert!( cstr.to_str().is_ok(), "C string in glib::Value is not valid utf-8" ); GStr::from_utf8_with_nul_unchecked(cstr.to_bytes_with_nul()) } } impl ToValue for GStr { #[inline] fn to_value(&self) -> Value { self.as_str().to_value() } #[inline] fn value_type(&self) -> Type { str::static_type() } } impl ToValue for &GStr { #[inline] fn to_value(&self) -> Value { (*self).to_value() } #[inline] fn value_type(&self) -> Type { str::static_type() } } impl crate::value::ToValueOptional for GStr { #[inline] fn to_value_optional(s: Option<&Self>) -> Value { crate::value::ToValueOptional::to_value_optional(s.map(|s| s.as_str())) } } #[doc(hidden)] impl<'a> ToGlibPtr<'a, *const c_char> for GStr { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> { Stash(self.as_ptr(), PhantomData) } #[inline] fn to_glib_full(&self) -> *const c_char { self.as_str().to_glib_full() } } #[doc(hidden)] impl<'a> ToGlibPtr<'a, *mut c_char> for GStr { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> { Stash(self.as_ptr() as *mut c_char, PhantomData) } #[inline] fn to_glib_full(&self) -> *mut c_char { self.as_str().to_glib_full() } } // rustdoc-stripper-ignore-next /// `NULL`-terminated UTF-8 string as stored in [`StrV`](crate::StrV). /// /// Unlike [`&GStr`](crate::GStr) this does not have its length stored. #[repr(transparent)] pub struct GStringPtr(ptr::NonNull); #[doc(hidden)] unsafe impl TransparentPtrType for GStringPtr {} #[doc(hidden)] impl GlibPtrDefault for GStringPtr { type GlibType = *mut c_char; } impl GStringPtr { // rustdoc-stripper-ignore-next /// Returns the corresponding [`&GStr`](crate::GStr). #[inline] pub fn to_gstr(&self) -> &GStr { unsafe { GStr::from_ptr(self.0.as_ptr()) } } // rustdoc-stripper-ignore-next /// Returns the corresponding [`&str`]. #[inline] pub fn as_str(&self) -> &str { self.to_gstr().as_str() } // rustdoc-stripper-ignore-next /// This is just an alias for [`as_str`](GStringPtr::as_str). #[inline] #[deprecated = "Use as_str instead"] pub fn to_str(&self) -> &str { self } // rustdoc-stripper-ignore-next /// Returns the string's C pointer. #[inline] pub const fn as_ptr(&self) -> *const c_char { self.0.as_ptr() } // rustdoc-stripper-ignore-next /// Wrapper around `libc::strcmp` returning `Ordering`. /// /// # Safety /// /// `a` and `b` must be non-null pointers to nul-terminated C strings. #[inline] unsafe fn strcmp(a: *const c_char, b: *const c_char) -> Ordering { from_glib(libc::strcmp(a, b)) } } impl Clone for GStringPtr { #[inline] fn clone(&self) -> GStringPtr { unsafe { GStringPtr(ptr::NonNull::new_unchecked(ffi::g_strdup(self.0.as_ptr()))) } } } impl Deref for GStringPtr { type Target = str; #[inline] fn deref(&self) -> &str { self.as_str() } } impl IntoGlibPtr<*mut c_char> for GStringPtr { #[inline] unsafe fn into_glib_ptr(self) -> *mut c_char { self.0.as_ptr() } } impl Drop for GStringPtr { #[inline] fn drop(&mut self) { unsafe { ffi::g_free(self.0.as_ptr() as *mut _); } } } impl fmt::Debug for GStringPtr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { <&GStr as fmt::Debug>::fmt(&self.to_gstr(), f) } } impl fmt::Display for GStringPtr { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.as_str()) } } impl Eq for GStringPtr {} impl PartialEq for GStringPtr { #[inline] fn eq(&self, other: &GStringPtr) -> bool { self.partial_cmp(other) == Some(Ordering::Equal) } } impl PartialEq for String { #[inline] fn eq(&self, other: &GStringPtr) -> bool { self.partial_cmp(other) == Some(Ordering::Equal) } } impl PartialEq for GString { #[inline] fn eq(&self, other: &GStringPtr) -> bool { self.partial_cmp(other) == Some(Ordering::Equal) } } impl PartialEq for GStringPtr { #[inline] fn eq(&self, other: &str) -> bool { self.partial_cmp(other) == Some(Ordering::Equal) } } impl PartialEq<&str> for GStringPtr { #[inline] fn eq(&self, other: &&str) -> bool { self.partial_cmp(other) == Some(Ordering::Equal) } } impl PartialEq for GStringPtr { #[inline] fn eq(&self, other: &GStr) -> bool { self.partial_cmp(other) == Some(Ordering::Equal) } } impl PartialEq<&GStr> for GStringPtr { #[inline] fn eq(&self, other: &&GStr) -> bool { self.partial_cmp(other) == Some(Ordering::Equal) } } impl PartialEq for &str { #[inline] fn eq(&self, other: &GStringPtr) -> bool { self.partial_cmp(other) == Some(Ordering::Equal) } } impl PartialEq for &GStr { #[inline] fn eq(&self, other: &GStringPtr) -> bool { self.partial_cmp(other) == Some(Ordering::Equal) } } impl PartialEq for GStringPtr { #[inline] fn eq(&self, other: &String) -> bool { self.partial_cmp(other) == Some(Ordering::Equal) } } impl PartialEq for GStringPtr { #[inline] fn eq(&self, other: &GString) -> bool { self.partial_cmp(other) == Some(Ordering::Equal) } } impl PartialEq for str { #[inline] fn eq(&self, other: &GStringPtr) -> bool { self.partial_cmp(other) == Some(Ordering::Equal) } } impl PartialEq for GStr { #[inline] fn eq(&self, other: &GStringPtr) -> bool { self.partial_cmp(other) == Some(Ordering::Equal) } } impl PartialOrd for GStringPtr { #[inline] fn partial_cmp(&self, other: &GStringPtr) -> Option { Some(self.cmp(other)) } } impl Ord for GStringPtr { #[inline] fn cmp(&self, other: &Self) -> std::cmp::Ordering { unsafe { GStringPtr::strcmp(self.as_ptr(), other.as_ptr()) } } } impl PartialOrd for String { #[inline] fn partial_cmp(&self, other: &GStringPtr) -> Option { Some(self.as_str().cmp(other)) } } impl PartialOrd for GString { #[inline] fn partial_cmp(&self, other: &GStringPtr) -> Option { Some(unsafe { GStringPtr::strcmp(self.as_ptr(), other.as_ptr()) }) } } impl PartialOrd for GStringPtr { #[inline] fn partial_cmp(&self, other: &String) -> Option { Some(self.as_str().cmp(other)) } } impl PartialOrd for GStringPtr { #[inline] fn partial_cmp(&self, other: &GString) -> Option { Some(unsafe { GStringPtr::strcmp(self.as_ptr(), other.as_ptr()) }) } } impl PartialOrd for str { #[inline] fn partial_cmp(&self, other: &GStringPtr) -> Option { Some(self.cmp(other.as_str())) } } impl PartialOrd for GStr { #[inline] fn partial_cmp(&self, other: &GStringPtr) -> Option { Some(unsafe { GStringPtr::strcmp(self.as_ptr(), other.as_ptr()) }) } } impl PartialOrd for GStringPtr { #[inline] fn partial_cmp(&self, other: &str) -> Option { Some(self.as_str().cmp(other)) } } impl PartialOrd<&str> for GStringPtr { #[inline] fn partial_cmp(&self, other: &&str) -> Option { Some(self.as_str().cmp(other)) } } impl PartialOrd for GStringPtr { #[inline] fn partial_cmp(&self, other: &GStr) -> Option { Some(unsafe { GStringPtr::strcmp(self.as_ptr(), other.as_ptr()) }) } } impl PartialOrd<&GStr> for GStringPtr { #[inline] fn partial_cmp(&self, other: &&GStr) -> Option { Some(unsafe { GStringPtr::strcmp(self.as_ptr(), other.as_ptr()) }) } } impl PartialOrd for &str { #[inline] fn partial_cmp(&self, other: &GStringPtr) -> Option { Some(self.cmp(&other.as_str())) } } impl PartialOrd for &GStr { #[inline] fn partial_cmp(&self, other: &GStringPtr) -> Option { Some(unsafe { GStringPtr::strcmp(self.as_ptr(), other.as_ptr()) }) } } impl AsRef for GStringPtr { #[inline] fn as_ref(&self) -> &GStringPtr { self } } impl std::hash::Hash for GStringPtr { #[inline] fn hash(&self, state: &mut H) { self.as_str().hash(state); } } // size_of::() minus two bytes for length and enum discriminant const INLINE_LEN: usize = mem::size_of::>>() + mem::size_of::() - mem::size_of::() * 2; // rustdoc-stripper-ignore-next /// A type representing an owned, C-compatible, nul-terminated UTF-8 string. /// /// `GString` is to &[GStr] as [`String`] is to &[str]: the former in /// each pair are owned strings; the latter are borrowed references. /// /// This type is similar to [`std::ffi::CString`], but with some special behavior. When debug /// assertions are enabled, [From]<[String]> will panic if there are interior /// nul-bytes. In production builds, no checks will be made for interior nul-bytes, and strings /// that contain interior nul-bytes will simply end at first nul-byte when converting to a C /// string. /// /// The constructors beginning with `from_utf8` and `from_string` can also be used to further /// control how interior nul-bytes are handled. pub struct GString(Inner); enum Inner { Native(Box), Foreign { ptr: ptr::NonNull, len: usize, }, Inline { len: u8, data: [u8; INLINE_LEN], }, } unsafe impl Send for GString {} unsafe impl Sync for GString {} impl GString { // rustdoc-stripper-ignore-next /// Creates a new empty [`GString`]. /// /// Does not allocate. #[inline] pub fn new() -> Self { Self(Inner::Inline { len: 0, data: Default::default(), }) } // rustdoc-stripper-ignore-next /// Formats an [`Arguments`](std::fmt::Arguments) into a [`GString`]. /// /// This function is the same as [`std::fmt::format`], except it returns a [`GString`]. The /// [`Arguments`](std::fmt::Arguments) instance can be created with the /// [`format_args!`](std::format_args) macro. /// /// Please note that using [`gformat!`](crate::gformat) might be preferable. pub fn format(args: fmt::Arguments) -> Self { if let Some(s) = args.as_str() { return Self::from(s); } let mut s = crate::GStringBuilder::default(); fmt::Write::write_fmt(&mut s, args).unwrap(); s.into_string() } // rustdoc-stripper-ignore-next /// Creates a GLib string by consuming a byte vector. /// /// Takes ownership of `bytes`. Returns `Err` if it contains invalid UTF-8. /// /// A trailing nul-byte will be appended by this function. #[inline] pub fn from_utf8(bytes: Vec) -> Result { Ok(Self::from_string_unchecked(String::from_utf8(bytes)?)) } // rustdoc-stripper-ignore-next /// Creates a GLib string by consuming a byte vector, checking for interior nul-bytes. /// /// Takes ownership of `bytes`, as long as it is valid UTF-8 and does not contain any interior /// nul-bytes. Otherwise, `Err` is returned. /// /// A trailing nul-byte will be appended by this function. #[inline] pub fn from_utf8_checked(bytes: Vec) -> Result>> { Ok(Self::from_string_checked(String::from_utf8(bytes)?) .map_err(|e| GStringInteriorNulError(e.0.into_bytes(), e.1))?) } // rustdoc-stripper-ignore-next /// Unsafely creates a GLib string by consuming a byte vector, without checking for UTF-8 or /// interior nul-bytes. /// /// A trailing nul-byte will be appended by this function. /// /// # Safety /// /// The byte vector **must** not contain invalid UTF-8 characters. It is undefined behavior to /// pass a vector that contains invalid UTF-8. #[inline] pub unsafe fn from_utf8_unchecked(mut v: Vec) -> Self { if v.is_empty() { Self::new() } else { v.reserve_exact(1); v.push(0); Self(Inner::Native(String::from_utf8_unchecked(v).into())) } } // rustdoc-stripper-ignore-next /// Creates a GLib string by consuming a nul-terminated byte vector, without checking for /// interior nul-bytes. /// /// Takes ownership of `bytes`. Returns `Err` if it contains invalid UTF-8 or does not have a /// trailing nul-byte. #[inline] pub fn from_utf8_with_nul(bytes: Vec) -> Result>> { let s = String::from_utf8(bytes)?; if s.as_bytes().last().copied() != Some(0u8) { return Err(GStringNoTrailingNulError(s.into_bytes()).into()); } if s.len() == 1 { Ok(Self::new()) } else { Ok(Self(Inner::Native(s.into()))) } } // rustdoc-stripper-ignore-next /// Creates a GLib string by consuming a nul-terminated byte vector. /// /// Takes ownership of `bytes`. Returns `Err` if it contains invalid UTF-8, does not have a /// trailing nul-byte, or contains interior nul-bytes. #[inline] pub fn from_utf8_with_nul_checked(bytes: Vec) -> Result>> { let s = Self::from_utf8_with_nul(bytes)?; if let Err(e) = GStr::check_interior_nuls(&s) { return Err(GStringInteriorNulError(s.into_bytes(), e).into()); } Ok(s) } // rustdoc-stripper-ignore-next /// Creates a GLib string by consuming a byte vector, without checking for UTF-8, a trailing /// nul-byte, or interior nul-bytes. /// /// # Safety /// /// The byte vector **must** not contain invalid UTF-8 characters, and **must** have a trailing /// nul-byte. It is undefined behavior to pass a vector that does not uphold those conditions. #[inline] pub unsafe fn from_utf8_with_nul_unchecked(v: Vec) -> Self { debug_assert!(!v.is_empty() && v[v.len() - 1] == 0); let s = if cfg!(debug_assertions) { let s = String::from_utf8(v).unwrap(); GStr::check_interior_nuls(&s[..s.len() - 1]).unwrap(); s } else { String::from_utf8_unchecked(v) }; if s.len() == 1 { Self::new() } else { Self(Inner::Native(s.into())) } } // rustdoc-stripper-ignore-next /// Creates a GLib string by consuming a nul-terminated byte vector, truncating it at the first /// nul-byte. /// /// Takes ownership of `bytes`. Returns `Err` if it contains invalid UTF-8 or does not contain /// at least one nul-byte. #[inline] pub fn from_utf8_until_nul(mut bytes: Vec) -> Result>> { let nul_pos = if let Some(nul_pos) = memchr::memchr(0, &bytes) { nul_pos } else { return Err(GStringNoTrailingNulError(bytes).into()); }; if nul_pos == 0 { Ok(Self::new()) } else { if let Err(e) = std::str::from_utf8(unsafe { bytes.get_unchecked(..nul_pos) }) { return Err(GStringUtf8Error(bytes, e).into()); } bytes.truncate(nul_pos + 1); let s = unsafe { String::from_utf8_unchecked(bytes) }; Ok(Self(Inner::Native(s.into()))) } } // rustdoc-stripper-ignore-next /// Creates a GLib string by consuming a string, checking for interior nul-bytes. /// /// Takes ownership of `s`, as long as it does not contain any interior nul-bytes. Otherwise, /// `Err` is returned. /// /// A trailing nul-byte will be appended by this function. #[inline] pub fn from_string_checked(s: String) -> Result> { if let Err(e) = GStr::check_interior_nuls(&s) { return Err(GStringInteriorNulError(s, e)); } Ok(Self::from_string_unchecked(s)) } // rustdoc-stripper-ignore-next /// Creates a GLib string by consuming a string, without checking for interior nul-bytes. /// /// A trailing nul-byte will be appended by this function. #[inline] pub fn from_string_unchecked(mut s: String) -> Self { if s.is_empty() { Self::new() } else { s.reserve_exact(1); s.push('\0'); Self(Inner::Native(s.into())) } } // rustdoc-stripper-ignore-next /// Wraps a raw C string with a safe GLib string wrapper. The provided C string **must** be /// nul-terminated. All constraints from [`std::ffi::CStr::from_ptr`] also apply here. /// /// If the string is valid UTF-8 then it is directly returned otherwise a copy is created with /// every invalid character replaced by the Unicode replacement character (U+FFFD). #[inline] pub unsafe fn from_ptr_lossy<'a>(ptr: *const c_char) -> Cow<'a, GStr> { GStr::from_ptr_lossy(ptr) } // rustdoc-stripper-ignore-next /// Wraps a raw C string with a safe GLib string wrapper. The provided C string **must** be /// nul-terminated. All constraints from [`std::ffi::CStr::from_ptr`] also apply here. /// /// `len` is the length without the nul-terminator, i.e. if `len == 0` is passed then `*ptr` /// must be the nul-terminator. #[inline] pub unsafe fn from_ptr_and_len_unchecked(ptr: *const c_char, len: usize) -> Self { debug_assert!(!ptr.is_null()); GString(Inner::Foreign { ptr: ptr::NonNull::new_unchecked(ptr as *mut _), len, }) } // rustdoc-stripper-ignore-next /// Return the `GString` as string slice. #[inline] pub fn as_str(&self) -> &str { unsafe { let (ptr, len) = match self.0 { Inner::Native(ref s) => (s.as_ptr(), s.len() - 1), Inner::Foreign { ptr, len } => (ptr.as_ptr() as *const u8, len), Inner::Inline { len, ref data } => (data.as_ptr(), len as usize), }; if len == 0 { "" } else { let slice = slice::from_raw_parts(ptr, len); std::str::from_utf8_unchecked(slice) } } } // rustdoc-stripper-ignore-next /// Extracts the [`GStr`] containing the entire string. #[inline] pub fn as_gstr(&self) -> &GStr { let bytes = match self.0 { Inner::Native(ref s) => s.as_bytes(), Inner::Foreign { len: 0, .. } => &[0], Inner::Foreign { ptr, len } => unsafe { slice::from_raw_parts(ptr.as_ptr() as *const _, len + 1) }, Inner::Inline { len, ref data } => unsafe { data.get_unchecked(..len as usize + 1) }, }; unsafe { GStr::from_utf8_with_nul_unchecked(bytes) } } // rustdoc-stripper-ignore-next /// Return the underlying pointer of the `GString`. #[inline] pub fn as_ptr(&self) -> *const c_char { match self.0 { Inner::Native(ref s) => s.as_ptr() as *const _, Inner::Foreign { ptr, .. } => ptr.as_ptr(), Inner::Inline { ref data, .. } => data.as_ptr() as *const _, } } // rustdoc-stripper-ignore-next /// Consumes the `GString` and returns the underlying byte buffer. /// /// The returned buffer is not guaranteed to contain a trailing nul-byte. #[inline] pub fn into_bytes(mut self) -> Vec { match &mut self.0 { Inner::Native(s) => { let mut s = String::from(mem::replace(s, "".into())); let _nul = s.pop(); debug_assert_eq!(_nul, Some('\0')); s.into_bytes() } Inner::Foreign { ptr, len } => { let bytes = unsafe { slice::from_raw_parts(ptr.as_ptr() as *const u8, *len - 1) }; bytes.to_owned() } Inner::Inline { len, data } => { unsafe { data.get_unchecked(..*len as usize) }.to_owned() } } } // rustdoc-stripper-ignore-next /// Consumes the `GString` and returns the underlying byte buffer, with trailing nul-byte. #[inline] pub fn into_bytes_with_nul(mut self) -> Vec { match &mut self.0 { Inner::Native(s) => str::into_boxed_bytes(mem::replace(s, "".into())).into(), Inner::Foreign { ptr, len } => { let bytes = unsafe { slice::from_raw_parts(ptr.as_ptr() as *const u8, *len) }; bytes.to_owned() } Inner::Inline { len, data } => { unsafe { data.get_unchecked(..*len as usize + 1) }.to_owned() } } } } // rustdoc-stripper-ignore-next /// Creates a [`GString`] using interpolation of runtime expressions. /// /// This macro is the same as [`std::format!`] except it returns a [`GString`]. It is faster than /// creating a [`String`] and then converting it manually to a [`GString`]. #[macro_export] macro_rules! gformat { ($($arg:tt)*) => { $crate::GString::format(std::format_args!($($arg)*)) }; } // rustdoc-stripper-ignore-next /// Error type indicating that a buffer did not have a trailing nul-byte. /// /// `T` is the type of the value the conversion was attempted from. #[derive(Clone, PartialEq, Eq, Debug)] pub struct GStringNoTrailingNulError(T); impl std::error::Error for GStringNoTrailingNulError where T: fmt::Debug {} impl fmt::Display for GStringNoTrailingNulError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.write_str("data provided is not nul terminated") } } impl GStringNoTrailingNulError { // rustdoc-stripper-ignore-next /// Returns the original value that was attempted to convert to [`GString`]. #[inline] pub fn into_inner(self) -> T { self.0 } } // rustdoc-stripper-ignore-next /// Error type indicating that a buffer had unexpected nul-bytes. /// /// `T` is the type of the value the conversion was attempted from. #[derive(Clone, PartialEq, Eq, Debug)] pub struct GStringInteriorNulError(T, GStrInteriorNulError); impl std::error::Error for GStringInteriorNulError where T: fmt::Debug {} impl fmt::Display for GStringInteriorNulError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.1, fmt) } } impl GStringInteriorNulError { // rustdoc-stripper-ignore-next /// Returns the original value that was attempted to convert to [`GString`]. #[inline] pub fn into_inner(self) -> T { self.0 } // rustdoc-stripper-ignore-next /// Fetch a [`GStrInteriorNulError`] to get more details about the conversion failure. #[inline] pub fn nul_error(&self) -> GStrInteriorNulError { self.1 } } // rustdoc-stripper-ignore-next /// Error type indicating that a buffer had invalid UTF-8. /// /// `T` is the type of the value the conversion was attempted from. #[derive(Clone, PartialEq, Eq, Debug)] pub struct GStringUtf8Error(T, std::str::Utf8Error); impl std::error::Error for GStringUtf8Error where T: fmt::Debug {} impl fmt::Display for GStringUtf8Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.1, fmt) } } impl GStringUtf8Error { // rustdoc-stripper-ignore-next /// Returns the original value that was attempted to convert to [`GString`]. #[inline] pub fn into_inner(self) -> T { self.0 } // rustdoc-stripper-ignore-next /// Fetch a [`Utf8Error`](std::str::Utf8Error) to get more details about the conversion /// failure. #[inline] pub fn utf8_error(&self) -> std::str::Utf8Error { self.1 } } // rustdoc-stripper-ignore-next /// Error type holding all possible failures when creating a [`GString`]. #[derive(Debug)] pub enum GStringFromError { NoTrailingNul(GStringNoTrailingNulError), InteriorNul(GStringInteriorNulError), InvalidUtf8(GStringUtf8Error), Unspecified(T), } impl std::error::Error for GStringFromError where T: fmt::Debug, { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { Self::NoTrailingNul(err) => std::error::Error::source(err), Self::InteriorNul(err) => std::error::Error::source(err), Self::InvalidUtf8(err) => std::error::Error::source(err), Self::Unspecified { .. } => None, } } } impl fmt::Display for GStringFromError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { Self::NoTrailingNul(err) => fmt::Display::fmt(err, fmt), Self::InteriorNul(err) => fmt::Display::fmt(err, fmt), Self::InvalidUtf8(err) => fmt::Display::fmt(err, fmt), Self::Unspecified(_) => fmt.write_str("unable to convert"), } } } impl std::convert::From> for GStringFromError { fn from(err: GStringNoTrailingNulError) -> Self { GStringFromError::NoTrailingNul(err) } } impl std::convert::From> for GStringFromError { fn from(err: GStringInteriorNulError) -> Self { GStringFromError::InteriorNul(err) } } impl std::convert::From> for GStringFromError { fn from(err: GStringUtf8Error) -> Self { GStringFromError::InvalidUtf8(err) } } impl GStringFromError { pub fn into_inner(self) -> T { match self { Self::NoTrailingNul(GStringNoTrailingNulError(t)) => t, Self::InteriorNul(GStringInteriorNulError(t, _)) => t, Self::InvalidUtf8(GStringUtf8Error(t, _)) => t, Self::Unspecified(t) => t, } } #[inline] fn convert(self, func: impl FnOnce(T) -> R) -> GStringFromError { match self { Self::NoTrailingNul(GStringNoTrailingNulError(t)) => { GStringFromError::NoTrailingNul(GStringNoTrailingNulError(func(t))) } Self::InteriorNul(GStringInteriorNulError(t, e)) => { GStringFromError::InteriorNul(GStringInteriorNulError(func(t), e)) } Self::InvalidUtf8(GStringUtf8Error(t, e)) => { GStringFromError::InvalidUtf8(GStringUtf8Error(func(t), e)) } Self::Unspecified(t) => GStringFromError::Unspecified(func(t)), } } } impl From for GStringFromError> { #[inline] fn from(e: std::string::FromUtf8Error) -> Self { let ue = e.utf8_error(); Self::InvalidUtf8(GStringUtf8Error(e.into_bytes(), ue)) } } impl IntoGlibPtr<*mut c_char> for GString { // rustdoc-stripper-ignore-next /// Transform into a nul-terminated raw C string pointer. #[inline] unsafe fn into_glib_ptr(self) -> *mut c_char { match self.0 { Inner::Native(ref s) => ffi::g_strndup(s.as_ptr() as *const _, s.len()), Inner::Foreign { ptr, .. } => { let _s = mem::ManuallyDrop::new(self); ptr.as_ptr() } Inner::Inline { len, ref data } => { ffi::g_strndup(data.as_ptr() as *const _, len as usize) } } } } impl Default for GString { #[inline] fn default() -> Self { Self::new() } } impl Clone for GString { #[inline] fn clone(&self) -> GString { self.as_str().into() } } impl fmt::Debug for GString { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { <&str as fmt::Debug>::fmt(&self.as_str(), f) } } impl Drop for GString { #[inline] fn drop(&mut self) { if let Inner::Foreign { ptr, .. } = self.0 { unsafe { ffi::g_free(ptr.as_ptr() as *mut _); } } } } impl fmt::Display for GString { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.as_str()) } } impl hash::Hash for GString { #[inline] fn hash(&self, state: &mut H) { self.as_str().hash(state) } } impl Borrow for GString { #[inline] fn borrow(&self) -> &GStr { self.as_gstr() } } impl Borrow for GString { #[inline] fn borrow(&self) -> &str { self.as_str() } } impl Ord for GString { #[inline] fn cmp(&self, other: &GString) -> Ordering { self.as_str().cmp(other.as_str()) } } impl PartialOrd for GString { #[inline] fn partial_cmp(&self, other: &GString) -> Option { Some(self.cmp(other)) } } impl PartialEq for GString { #[inline] fn eq(&self, other: &GString) -> bool { self.as_str() == other.as_str() } } impl PartialEq for String { #[inline] fn eq(&self, other: &GString) -> bool { self.as_str() == other.as_str() } } impl PartialEq for GString { #[inline] fn eq(&self, other: &GStr) -> bool { self.as_str() == other.as_str() } } impl PartialEq<&GStr> for GString { #[inline] fn eq(&self, other: &&GStr) -> bool { self.as_str() == other.as_str() } } impl PartialEq for GString { #[inline] fn eq(&self, other: &str) -> bool { self.as_str() == other } } impl PartialEq<&str> for GString { #[inline] fn eq(&self, other: &&str) -> bool { self.as_str() == *other } } impl PartialEq for &GStr { #[inline] fn eq(&self, other: &GString) -> bool { self.as_str() == other.as_str() } } impl PartialEq for &str { #[inline] fn eq(&self, other: &GString) -> bool { *self == other.as_str() } } impl PartialEq for GString { #[inline] fn eq(&self, other: &String) -> bool { self.as_str() == other.as_str() } } impl PartialEq for str { #[inline] fn eq(&self, other: &GString) -> bool { self == other.as_str() } } impl PartialEq for GStr { #[inline] fn eq(&self, other: &GString) -> bool { self.as_str() == other.as_str() } } impl PartialOrd for String { #[inline] fn partial_cmp(&self, other: &GString) -> Option { Some(self.cmp(&String::from(other.as_str()))) } } impl PartialOrd for GString { #[inline] fn partial_cmp(&self, other: &String) -> Option { Some(self.as_str().cmp(other.as_str())) } } impl PartialOrd for GStr { #[inline] fn partial_cmp(&self, other: &GString) -> Option { Some(self.as_str().cmp(other)) } } impl PartialOrd for GString { #[inline] fn partial_cmp(&self, other: &GStr) -> Option { Some(self.as_str().cmp(other.as_str())) } } impl PartialOrd for str { #[inline] fn partial_cmp(&self, other: &GString) -> Option { Some(self.cmp(other)) } } impl PartialOrd for GString { #[inline] fn partial_cmp(&self, other: &str) -> Option { Some(self.as_str().cmp(other)) } } impl Eq for GString {} impl AsRef for GString { #[inline] fn as_ref(&self) -> &GStr { self.as_gstr() } } impl AsRef for GString { #[inline] fn as_ref(&self) -> &str { self.as_str() } } impl AsRef for GString { #[inline] fn as_ref(&self) -> &OsStr { OsStr::new(self.as_str()) } } impl AsRef for GString { #[inline] fn as_ref(&self) -> &Path { Path::new(self.as_str()) } } impl AsRef<[u8]> for GString { #[inline] fn as_ref(&self) -> &[u8] { self.as_str().as_bytes() } } impl Deref for GString { type Target = str; #[inline] fn deref(&self) -> &str { self.as_str() } } impl From for String { #[inline] fn from(mut s: GString) -> Self { match &mut s.0 { Inner::Native(s) => { // Moves the underlying string let mut s = String::from(mem::replace(s, "".into())); let _nul = s.pop(); debug_assert_eq!(_nul, Some('\0')); s } Inner::Foreign { len, .. } if *len == 0 => String::new(), Inner::Foreign { ptr, len } => unsafe { // Creates a copy let slice = slice::from_raw_parts(ptr.as_ptr() as *const u8, *len); std::str::from_utf8_unchecked(slice).into() }, Inner::Inline { len, data } => unsafe { std::str::from_utf8_unchecked(data.get_unchecked(..*len as usize)).to_owned() }, } } } impl From for Box { #[inline] fn from(s: GString) -> Self { // Potentially creates a copy String::from(s).into() } } impl From for Vec { #[inline] fn from(value: GString) -> Vec { value.into_bytes_with_nul() } } impl TryFrom for CString { type Error = GStringInteriorNulError; #[inline] fn try_from(value: GString) -> Result { if let Some(nul_pos) = memchr::memchr(0, value.as_bytes()) { return Err(GStringInteriorNulError( value, GStrInteriorNulError(nul_pos), )); } let v = value.into_bytes_with_nul(); Ok(unsafe { CString::from_vec_with_nul_unchecked(v) }) } } impl From for OsString { #[inline] fn from(s: GString) -> Self { OsString::from(String::from(s)) } } impl From for PathBuf { #[inline] fn from(s: GString) -> Self { PathBuf::from(OsString::from(s)) } } impl From for GString { #[inline] fn from(mut s: String) -> Self { // Moves the content of the String if cfg!(debug_assertions) { GStr::check_interior_nuls(&s).unwrap(); } if s.is_empty() { Self::new() } else { s.reserve_exact(1); s.push('\0'); // No check for valid UTF-8 here Self(Inner::Native(s.into())) } } } impl From> for GString { #[inline] fn from(s: Box) -> Self { // Moves the content of the String s.into_string().into() } } impl<'a> From> for GString { #[inline] fn from(s: Cow<'a, str>) -> Self { match s { Cow::Borrowed(s) => Self::from(s), Cow::Owned(s) => Self::from(s), } } } impl From<&GStr> for GString { #[inline] fn from(s: &GStr) -> GString { s.to_owned() } } impl From<&str> for GString { #[inline] fn from(s: &str) -> Self { if cfg!(debug_assertions) { GStr::check_interior_nuls(s).unwrap(); } if s.len() < INLINE_LEN { let mut data = <[u8; INLINE_LEN]>::default(); let b = s.as_bytes(); unsafe { data.get_unchecked_mut(..b.len()) }.copy_from_slice(b); return Self(Inner::Inline { len: b.len() as u8, data, }); } // Allocates with the GLib allocator unsafe { // No check for valid UTF-8 here let copy = ffi::g_strndup(s.as_ptr() as *const c_char, s.len()); GString(Inner::Foreign { ptr: ptr::NonNull::new_unchecked(copy), len: s.len(), }) } } } impl From<&String> for GString { #[inline] fn from(s: &String) -> Self { GString::from(s.as_str()) } } impl From for GString { #[inline] fn from(s: GStringPtr) -> Self { let s = mem::ManuallyDrop::new(s); let len = unsafe { GStr::from_ptr(s.0.as_ptr()).len() }; GString(Inner::Foreign { ptr: s.0, len }) } } impl TryFrom for GString { type Error = GStringUtf8Error; #[inline] fn try_from(value: CString) -> Result { if value.as_bytes().is_empty() { Ok(Self::new()) } else { // Moves the content of the CString // Also check if it's valid UTF-8 let s = String::from_utf8(value.into_bytes_with_nul()).map_err(|e| { let err = e.utf8_error(); GStringUtf8Error( unsafe { CString::from_vec_with_nul_unchecked(e.into_bytes()) }, err, ) })?; Ok(Self(Inner::Native(s.into()))) } } } impl TryFrom for GString { type Error = GStringFromError; #[inline] fn try_from(value: OsString) -> Result { Self::from_string_checked(value.into_string().map_err(GStringFromError::Unspecified)?) .map_err(|e| GStringFromError::from(e).convert(OsString::from)) } } impl TryFrom for GString { type Error = GStringFromError; #[inline] fn try_from(value: PathBuf) -> Result { GString::try_from(value.into_os_string()).map_err(|e| e.convert(PathBuf::from)) } } impl TryFrom<&CStr> for GString { type Error = std::str::Utf8Error; #[inline] fn try_from(value: &CStr) -> Result { // Check if it's valid UTF-8 value.to_str()?; let gstr = unsafe { GStr::from_utf8_with_nul_unchecked(value.to_bytes_with_nul()) }; Ok(gstr.to_owned()) } } impl<'a> From> for GString { #[inline] fn from(s: Cow<'a, GStr>) -> Self { s.into_owned() } } impl<'a> From<&'a GString> for Cow<'a, GStr> { #[inline] fn from(s: &'a GString) -> Self { Cow::Borrowed(s.as_gstr()) } } impl From for Cow<'_, GStr> { #[inline] fn from(v: GString) -> Self { Cow::Owned(v) } } impl<'a> From<&'a GStr> for Cow<'a, GStr> { #[inline] fn from(v: &'a GStr) -> Self { Cow::Borrowed(v) } } #[doc(hidden)] impl FromGlibPtrFull<*mut u8> for GString { #[inline] unsafe fn from_glib_full(ptr: *mut u8) -> Self { debug_assert!(!ptr.is_null()); let cstr = CStr::from_ptr(ptr as *const _); // Check for valid UTF-8 here debug_assert!(cstr.to_str().is_ok()); Self(Inner::Foreign { ptr: ptr::NonNull::new_unchecked(ptr as *mut _), len: cstr.to_bytes().len(), }) } } #[doc(hidden)] impl FromGlibPtrFull<*mut i8> for GString { #[inline] unsafe fn from_glib_full(ptr: *mut i8) -> Self { from_glib_full(ptr as *mut u8) } } #[doc(hidden)] impl FromGlibPtrFull<*const u8> for GString { #[inline] unsafe fn from_glib_full(ptr: *const u8) -> Self { from_glib_full(ptr as *mut u8) } } #[doc(hidden)] impl FromGlibPtrFull<*const i8> for GString { #[inline] unsafe fn from_glib_full(ptr: *const i8) -> Self { from_glib_full(ptr as *mut u8) } } #[doc(hidden)] impl FromGlibPtrNone<*const u8> for GString { #[inline] unsafe fn from_glib_none(ptr: *const u8) -> Self { debug_assert!(!ptr.is_null()); <&GStr>::from_glib_none(ptr).into() } } #[doc(hidden)] impl FromGlibPtrNone<*const i8> for GString { #[inline] unsafe fn from_glib_none(ptr: *const i8) -> Self { from_glib_none(ptr as *const u8) } } #[doc(hidden)] impl FromGlibPtrNone<*mut u8> for GString { #[inline] unsafe fn from_glib_none(ptr: *mut u8) -> Self { from_glib_none(ptr as *const u8) } } #[doc(hidden)] impl FromGlibPtrNone<*mut i8> for GString { #[inline] unsafe fn from_glib_none(ptr: *mut i8) -> Self { from_glib_none(ptr as *const u8) } } #[doc(hidden)] impl FromGlibPtrBorrow<*const u8> for GString { #[inline] unsafe fn from_glib_borrow(ptr: *const u8) -> Borrowed { debug_assert!(!ptr.is_null()); // Check for valid UTF-8 here let cstr = CStr::from_ptr(ptr as *const _); debug_assert!(cstr.to_str().is_ok()); Borrowed::new(Self(Inner::Foreign { ptr: ptr::NonNull::new_unchecked(ptr as *mut _), len: cstr.to_bytes().len(), })) } } #[doc(hidden)] impl FromGlibPtrBorrow<*const i8> for GString { #[inline] unsafe fn from_glib_borrow(ptr: *const i8) -> Borrowed { from_glib_borrow(ptr as *const u8) } } #[doc(hidden)] impl FromGlibPtrBorrow<*mut u8> for GString { #[inline] unsafe fn from_glib_borrow(ptr: *mut u8) -> Borrowed { from_glib_borrow(ptr as *const u8) } } #[doc(hidden)] impl FromGlibPtrBorrow<*mut i8> for GString { #[inline] unsafe fn from_glib_borrow(ptr: *mut i8) -> Borrowed { from_glib_borrow(ptr as *const u8) } } #[allow(clippy::unnecessary_cast)] #[doc(hidden)] impl<'a> ToGlibPtr<'a, *const u8> for GString { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const u8, Self> { Stash(self.as_ptr() as *const u8, PhantomData) } #[inline] fn to_glib_full(&self) -> *const u8 { unsafe { self.clone().into_glib_ptr() as *const u8 } } } #[allow(clippy::unnecessary_cast)] #[doc(hidden)] impl<'a> ToGlibPtr<'a, *const i8> for GString { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const i8, Self> { Stash(self.as_ptr() as *const i8, PhantomData) } #[inline] fn to_glib_full(&self) -> *const i8 { unsafe { self.clone().into_glib_ptr() as *const i8 } } } #[allow(clippy::unnecessary_cast)] #[doc(hidden)] impl<'a> ToGlibPtr<'a, *mut u8> for GString { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut u8, Self> { Stash(self.as_ptr() as *mut u8, PhantomData) } #[inline] fn to_glib_full(&self) -> *mut u8 { unsafe { self.clone().into_glib_ptr() as *mut u8 } } } #[allow(clippy::unnecessary_cast)] #[doc(hidden)] impl<'a> ToGlibPtr<'a, *mut i8> for GString { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut i8, Self> { Stash(self.as_ptr() as *mut i8, PhantomData) } #[inline] fn to_glib_full(&self) -> *mut i8 { unsafe { self.clone().into_glib_ptr() as *mut i8 } } } #[doc(hidden)] impl FromGlibContainer<*const c_char, *const i8> for GString { unsafe fn from_glib_none_num(ptr: *const i8, num: usize) -> Self { if num == 0 || ptr.is_null() { return Self::default(); } let slice = slice::from_raw_parts(ptr as *const u8, num); if cfg!(debug_assertions) { // Also check if it's valid UTF-8 std::str::from_utf8(slice).unwrap().into() } else { std::str::from_utf8_unchecked(slice).into() } } unsafe fn from_glib_container_num(ptr: *const i8, num: usize) -> Self { if num == 0 || ptr.is_null() { return Self::default(); } if cfg!(debug_assertions) { // Check if it's valid UTF-8 let slice = slice::from_raw_parts(ptr as *const u8, num); std::str::from_utf8(slice).unwrap(); } GString(Inner::Foreign { ptr: ptr::NonNull::new_unchecked(ptr as *mut _), len: num, }) } unsafe fn from_glib_full_num(ptr: *const i8, num: usize) -> Self { if num == 0 || ptr.is_null() { return Self::default(); } if cfg!(debug_assertions) { // Check if it's valid UTF-8 let slice = slice::from_raw_parts(ptr as *const u8, num); std::str::from_utf8(slice).unwrap(); } GString(Inner::Foreign { ptr: ptr::NonNull::new_unchecked(ptr as *mut _), len: num, }) } } #[doc(hidden)] impl FromGlibContainer<*const c_char, *mut i8> for GString { unsafe fn from_glib_none_num(ptr: *mut i8, num: usize) -> Self { FromGlibContainer::from_glib_none_num(ptr as *const i8, num) } unsafe fn from_glib_container_num(ptr: *mut i8, num: usize) -> Self { FromGlibContainer::from_glib_container_num(ptr as *const i8, num) } unsafe fn from_glib_full_num(ptr: *mut i8, num: usize) -> Self { FromGlibContainer::from_glib_full_num(ptr as *const i8, num) } } #[doc(hidden)] impl FromGlibContainer<*const c_char, *const u8> for GString { unsafe fn from_glib_none_num(ptr: *const u8, num: usize) -> Self { FromGlibContainer::from_glib_none_num(ptr as *const i8, num) } unsafe fn from_glib_container_num(ptr: *const u8, num: usize) -> Self { FromGlibContainer::from_glib_container_num(ptr as *const i8, num) } unsafe fn from_glib_full_num(ptr: *const u8, num: usize) -> Self { FromGlibContainer::from_glib_full_num(ptr as *const i8, num) } } #[doc(hidden)] impl FromGlibContainer<*const c_char, *mut u8> for GString { unsafe fn from_glib_none_num(ptr: *mut u8, num: usize) -> Self { FromGlibContainer::from_glib_none_num(ptr as *const i8, num) } unsafe fn from_glib_container_num(ptr: *mut u8, num: usize) -> Self { FromGlibContainer::from_glib_container_num(ptr as *const i8, num) } unsafe fn from_glib_full_num(ptr: *mut u8, num: usize) -> Self { FromGlibContainer::from_glib_full_num(ptr as *const i8, num) } } impl GlibPtrDefault for GString { type GlibType = *const c_char; } impl StaticType for GString { #[inline] fn static_type() -> Type { String::static_type() } } impl crate::value::ValueType for GString { type Type = String; } impl crate::value::ValueTypeOptional for GString {} unsafe impl<'a> crate::value::FromValue<'a> for GString { type Checker = crate::value::GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a Value) -> Self { Self::from(<&str>::from_value(value)) } } impl crate::value::ToValue for GString { #[inline] fn to_value(&self) -> Value { <&str>::to_value(&self.as_str()) } #[inline] fn value_type(&self) -> Type { String::static_type() } } impl crate::value::ToValueOptional for GString { #[inline] fn to_value_optional(s: Option<&Self>) -> Value { ::to_value_optional(s.as_ref().map(|s| s.as_str())) } } impl From for Value { #[inline] fn from(s: GString) -> Self { unsafe { let mut value = Value::for_value_type::(); gobject_ffi::g_value_take_string(value.to_glib_none_mut().0, s.into_glib_ptr()); value } } } impl StaticType for Vec { #[inline] fn static_type() -> Type { >::static_type() } } impl crate::value::ValueType for Vec { type Type = Vec; } unsafe impl<'a> crate::value::FromValue<'a> for Vec { type Checker = crate::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a Value) -> Self { let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char; FromGlibPtrContainer::from_glib_none(ptr) } } impl ToValue for Vec { #[inline] fn to_value(&self) -> Value { unsafe { let mut value = Value::for_value_type::(); let ptr: *mut *mut c_char = self.to_glib_full(); gobject_ffi::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void); value } } #[inline] fn value_type(&self) -> Type { >::static_type() } } impl From> for Value { #[inline] fn from(mut v: Vec) -> Self { unsafe { let mut value = Value::for_value_type::>(); let container = ToGlibContainerFromSlice::<*mut *mut c_char>::to_glib_container_from_slice(&v); gobject_ffi::g_value_take_boxed( value.to_glib_none_mut().0, container.0 as *const c_void, ); v.set_len(0); value } } } impl_from_glib_container_as_vec_string!(GString, *const c_char); impl_from_glib_container_as_vec_string!(GString, *mut c_char); // rustdoc-stripper-ignore-next /// A trait to accept both &[str] or &[GStr] as an argument. pub trait IntoGStr { fn run_with_gstr T>(self, f: F) -> T; } impl IntoGStr for &GStr { #[inline] fn run_with_gstr T>(self, f: F) -> T { f(self) } } impl IntoGStr for GString { #[inline] fn run_with_gstr T>(self, f: F) -> T { f(self.as_gstr()) } } impl IntoGStr for &GString { #[inline] fn run_with_gstr T>(self, f: F) -> T { f(self.as_gstr()) } } // Limit borrowed from rust std CStr optimization: // https://github.com/rust-lang/rust/blob/master/library/std/src/sys/common/small_c_string.rs#L10 const MAX_STACK_ALLOCATION: usize = 384; impl IntoGStr for &str { #[inline] fn run_with_gstr T>(self, f: F) -> T { if self.len() < MAX_STACK_ALLOCATION { let mut s = mem::MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit(); let ptr = s.as_mut_ptr() as *mut u8; let gs = unsafe { ptr::copy_nonoverlapping(self.as_ptr(), ptr, self.len()); ptr.add(self.len()).write(0); GStr::from_utf8_with_nul_unchecked(slice::from_raw_parts(ptr, self.len() + 1)) }; f(gs) } else { f(GString::from(self).as_gstr()) } } } impl IntoGStr for String { #[inline] fn run_with_gstr T>(mut self, f: F) -> T { let len = self.len(); if len < self.capacity() { self.reserve_exact(1); self.push('\0'); let gs = unsafe { GStr::from_utf8_with_nul_unchecked(self.as_bytes()) }; f(gs) } else if len < MAX_STACK_ALLOCATION { self.as_str().run_with_gstr(f) } else { f(GString::from(self).as_gstr()) } } } impl IntoGStr for &String { #[inline] fn run_with_gstr T>(self, f: F) -> T { self.as_str().run_with_gstr(f) } } pub const NONE_STR: Option<&'static str> = None; // rustdoc-stripper-ignore-next /// A trait to accept both [Option]<&[str]> or [Option]<&[GStr]> as /// an argument. pub trait IntoOptionalGStr { fn run_with_gstr) -> T>(self, f: F) -> T; } impl IntoOptionalGStr for Option { #[inline] fn run_with_gstr) -> T>(self, f: F) -> T { match self { Some(t) => t.run_with_gstr(|s| f(Some(s))), None => f(None), } } } #[cfg(test)] #[allow(clippy::disallowed_names)] mod tests { use std::ffi::CString; use super::*; #[test] fn test_gstring() { let data = CString::new("foo").unwrap(); let ptr = data.as_ptr(); unsafe { let ptr_copy = ffi::g_strdup(ptr); let gstring = GString::from_glib_full(ptr_copy); assert_eq!(gstring.as_str(), "foo"); let foo: Box = gstring.into(); assert_eq!(foo.as_ref(), "foo"); } } #[test] fn test_owned_glib_string() { let data = CString::new("foo").unwrap(); let ptr = data.as_ptr(); unsafe { let ptr_copy = ffi::g_strdup(ptr); let gstr = GString::from_glib_full(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_string_from_gstring() { let gstring = GString::from("foo"); assert_eq!(gstring.as_str(), "foo"); let s = String::from(gstring); assert_eq!(s, "foo"); } #[test] fn test_gstring_from_cstring() { let cstr = CString::new("foo").unwrap(); let gstring = GString::try_from(cstr).unwrap(); assert_eq!(gstring.as_str(), "foo"); let foo: Box = gstring.into(); assert_eq!(foo.as_ref(), "foo"); } #[test] fn test_string_from_gstring_from_cstring() { let cstr = CString::new("foo").unwrap(); let gstring = GString::try_from(cstr).unwrap(); assert_eq!(gstring.as_str(), "foo"); let s = String::from(gstring); assert_eq!(s, "foo"); } #[test] fn test_vec_u8_to_gstring() { let v: &[u8] = b"foo"; let s: GString = GString::from_utf8(Vec::from(v)).unwrap(); assert_eq!(s.as_str(), "foo"); } #[test] fn test_as_ref_path() { fn foo>(_path: P) {} let gstring: GString = "/my/path/".into(); let gstr: &GStr = gstring.as_gstr(); foo(gstr); foo(gstring); } #[test] fn test_from_glib_container() { unsafe { let test_a: GString = FromGlibContainer::from_glib_container_num( ffi::g_strdup("hello_world\0".as_ptr() as *const _), 5, ); assert_eq!("hello", test_a.as_str()); let test_b: GString = FromGlibContainer::from_glib_none_num("hello_world".as_ptr(), 5); assert_eq!("hello", test_b.as_str()); let test_c: GString = FromGlibContainer::from_glib_none_num(std::ptr::null::(), 0); assert_eq!("", test_c.as_str()); let test_d: GString = FromGlibContainer::from_glib_none_num("".as_ptr(), 0); assert_eq!("", test_d.as_str()); let test_e: GString = FromGlibContainer::from_glib_container_num(ffi::g_strdup(std::ptr::null()), 0); assert_eq!("", test_e.as_str()); } } #[test] fn test_hashmap() { use std::collections::HashMap; let gstring = GString::from("foo"); 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)); } #[test] fn test_gstring_from_ptr_lossy() { let data = CString::new("foo").unwrap(); let ptr = data.as_ptr(); unsafe { let gstring = GString::from_ptr_lossy(ptr); assert_eq!(gstring.as_str(), "foo"); assert_eq!(ptr, gstring.as_ptr()); } let data = b"foo\xF0\x90\x80bar\0"; let ptr = data.as_ptr(); unsafe { let gstring = GString::from_ptr_lossy(ptr as *const _); assert_eq!(gstring.as_str(), "foo���bar"); assert_ne!(ptr, gstring.as_ptr() as *const _); } } #[test] fn gformat() { let s = gformat!("bla bla {} bla", 123); assert_eq!(s, "bla bla 123 bla"); } #[test] fn layout() { // ensure the inline variant is not wider than the other variants enum NoInline { _Native(Box), _Foreign(ptr::NonNull, usize), } assert_eq!(mem::size_of::(), mem::size_of::()); assert_eq!(mem::size_of::(), mem::size_of::()); } } glib-0.20.9/src/gstring_builder.rs000064400000000000000000000223241046102023000151540ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{cmp, fmt, hash, mem, ops, ptr, slice, str}; use crate::{ffi, translate::*, GStr}; wrapper! { // rustdoc-stripper-ignore-next /// A mutable text buffer that grows automatically. #[doc(alias = "GString")] #[must_use = "The builder must be built to be used"] pub struct GStringBuilder(BoxedInline); match fn { copy => |ptr| ffi::g_string_new_len((*ptr).str, (*ptr).len as isize), free => |ptr| ffi::g_string_free(ptr, ffi::GTRUE), init => |ptr| unsafe { let inner = ffi::GString { str: ffi::g_malloc(64) as *mut _, len: 0, allocated_len: 64, }; ptr::write(inner.str, 0); *ptr = inner; }, copy_into => |dest, src| { debug_assert!((*src).allocated_len > (*src).len); let allocated_len = (*src).allocated_len; let inner = ffi::GString { str: ffi::g_malloc(allocated_len) as *mut _, len: 0, allocated_len, }; // +1 to also copy the NUL-terminator ptr::copy_nonoverlapping((*src).str, inner.str, (*src).len + 1); *dest = inner; }, clear => |ptr| { ffi::g_free((*ptr).str as *mut _); }, type_ => || ffi::g_gstring_get_type(), } } unsafe impl Send for GStringBuilder {} unsafe impl Sync for GStringBuilder {} impl GStringBuilder { #[doc(alias = "g_string_new_len")] #[inline] pub fn new>(data: T) -> GStringBuilder { let data = data.as_ref(); assert!(data.len() < usize::MAX - 1); unsafe { let allocated_len = usize::next_power_of_two(std::cmp::max(data.len(), 64) + 1); assert_ne!(allocated_len, 0); let inner = ffi::GString { str: ffi::g_malloc(allocated_len) as *mut _, len: data.len(), allocated_len, }; if data.is_empty() { ptr::write(inner.str, 0); } else { ptr::copy_nonoverlapping(data.as_ptr() as *const _, inner.str, data.len()); ptr::write(inner.str.add(data.len()), 0); } Self { inner } } } #[doc(alias = "g_string_append")] #[doc(alias = "g_string_append_len")] #[inline] pub fn append(&mut self, val: &str) { unsafe { ffi::g_string_append_len( self.to_glib_none_mut().0, val.as_ptr() as *const _, val.len() as isize, ); } } #[doc(alias = "g_string_prepend")] #[doc(alias = "g_string_prepend_len")] #[inline] pub fn prepend(&mut self, val: &str) { unsafe { ffi::g_string_prepend_len( self.to_glib_none_mut().0, val.as_ptr() as *const _, val.len() as isize, ); } } #[doc(alias = "g_string_append_c")] #[doc(alias = "g_string_append_unichar")] #[inline] pub fn append_c(&mut self, val: char) { unsafe { ffi::g_string_append_unichar(self.to_glib_none_mut().0, val.into_glib()); } } #[doc(alias = "g_string_prepend_c")] #[doc(alias = "g_string_prepend_unichar")] #[inline] pub fn prepend_c(&mut self, val: char) { unsafe { ffi::g_string_prepend_unichar(self.to_glib_none_mut().0, val.into_glib()); } } // rustdoc-stripper-ignore-next /// Returns `&[str]` slice. #[inline] pub fn as_str(&self) -> &str { unsafe { let ptr: *const u8 = self.inner.str as _; let len: usize = self.inner.len; if len == 0 { return ""; } let slice = slice::from_raw_parts(ptr, len); std::str::from_utf8_unchecked(slice) } } // rustdoc-stripper-ignore-next /// Returns &[GStr] slice. #[inline] pub fn as_gstr(&self) -> &GStr { unsafe { let ptr: *const u8 = self.inner.str as _; let len: usize = self.inner.len; if len == 0 { return Default::default(); } let slice = slice::from_raw_parts(ptr, len + 1); GStr::from_utf8_with_nul_unchecked(slice) } } // rustdoc-stripper-ignore-next /// Finalizes the builder, converting it to a [`GString`](crate::GString). #[must_use = "String returned from the builder should probably be used"] #[inline] pub fn into_string(self) -> crate::GString { unsafe { let s = mem::ManuallyDrop::new(self); crate::GString::from_ptr_and_len_unchecked(s.inner.str, s.inner.len) } } } impl Default for GStringBuilder { // rustdoc-stripper-ignore-next /// Creates a new empty string. #[inline] fn default() -> Self { Self::new("") } } impl fmt::Debug for GStringBuilder { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.as_str()) } } impl fmt::Display for GStringBuilder { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.as_str()) } } impl PartialEq for GStringBuilder { #[inline] fn eq(&self, other: &Self) -> bool { self.as_str() == other.as_str() } } impl PartialEq for GStringBuilder { #[inline] fn eq(&self, other: &str) -> bool { self.as_str() == other } } impl PartialEq for str { #[inline] fn eq(&self, other: &GStringBuilder) -> bool { self == other.as_str() } } impl PartialEq for GStringBuilder { #[inline] fn eq(&self, other: &GStr) -> bool { self.as_gstr() == other } } impl PartialEq for GStr { #[inline] fn eq(&self, other: &GStringBuilder) -> bool { self == other.as_gstr() } } impl Eq for GStringBuilder {} impl cmp::PartialOrd for GStringBuilder { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl cmp::PartialOrd for GStringBuilder { #[inline] fn partial_cmp(&self, other: &str) -> Option { Some(self.as_str().cmp(other)) } } impl cmp::PartialOrd for str { #[inline] fn partial_cmp(&self, other: &GStringBuilder) -> Option { Some(self.cmp(other.as_str())) } } impl cmp::PartialOrd for GStringBuilder { #[inline] fn partial_cmp(&self, other: &GStr) -> Option { Some(self.as_gstr().cmp(other)) } } impl cmp::PartialOrd for GStr { #[inline] fn partial_cmp(&self, other: &GStringBuilder) -> Option { Some(self.cmp(other.as_gstr())) } } impl cmp::Ord for GStringBuilder { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { self.as_str().cmp(other.as_str()) } } impl hash::Hash for GStringBuilder { #[inline] fn hash(&self, state: &mut H) where H: hash::Hasher, { self.as_str().hash(state) } } impl AsRef<[u8]> for GStringBuilder { #[inline] fn as_ref(&self) -> &[u8] { self.as_bytes() } } impl AsRef for GStringBuilder { #[inline] fn as_ref(&self) -> &str { self.as_str() } } impl AsRef for GStringBuilder { #[inline] fn as_ref(&self) -> &GStr { self.as_gstr() } } impl ops::Deref for GStringBuilder { type Target = str; #[inline] fn deref(&self) -> &str { self.as_str() } } impl fmt::Write for GStringBuilder { #[inline] fn write_str(&mut self, s: &str) -> fmt::Result { self.append(s); Ok(()) } #[inline] fn write_char(&mut self, c: char) -> fmt::Result { self.append_c(c); Ok(()) } } #[cfg(test)] mod tests { #[test] fn append() { let mut s = crate::GStringBuilder::new(""); assert_eq!(&*s, ""); s.append("Hello"); s.append(" "); s.append("there!"); assert_eq!(&*s, "Hello there!"); assert_eq!(s.into_string().as_str(), "Hello there!"); } #[test] fn prepend() { let mut s = crate::GStringBuilder::new("456"); assert_eq!(&*s, "456"); s.prepend("123"); assert_eq!(&*s, "123456"); } #[test] fn default() { let s1: crate::GStringBuilder = Default::default(); assert_eq!(&*s1, ""); } #[test] fn display() { let s: crate::GStringBuilder = crate::GStringBuilder::new("This is a string."); assert_eq!(&format!("{s}"), "This is a string."); } #[test] fn eq() { let a1 = crate::GStringBuilder::new("a"); let a2 = crate::GStringBuilder::new("a"); let b = crate::GStringBuilder::new("b"); assert_eq!(a1, a2); assert_ne!(a1, b); assert_ne!(a2, b); } #[test] fn write() { use std::fmt::Write; let mut s = crate::GStringBuilder::default(); write!(&mut s, "bla bla {} bla", 123).unwrap(); assert_eq!(&*s, "bla bla 123 bla"); } } glib-0.20.9/src/key_file.rs000064400000000000000000000221741046102023000135630ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{mem, path, ptr}; use crate::{ffi, translate::*, Error, GString, GStringPtr, KeyFile, KeyFileFlags, PtrSlice}; impl KeyFile { #[doc(alias = "g_key_file_save_to_file")] pub fn save_to_file>(&self, filename: T) -> Result<(), Error> { unsafe { let mut error = ptr::null_mut(); let _ = ffi::g_key_file_save_to_file( self.to_glib_none().0, filename.as_ref().to_glib_none().0, &mut error, ); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_load_from_data_dirs")] pub fn load_from_data_dirs>( &self, file: T, flags: KeyFileFlags, ) -> Result { unsafe { let mut error = ptr::null_mut(); let mut full_path: *mut libc::c_char = ptr::null_mut(); let _ = ffi::g_key_file_load_from_data_dirs( self.to_glib_none().0, file.as_ref().to_glib_none().0, &mut full_path, flags.into_glib(), &mut error, ); if error.is_null() { let path: GString = from_glib_full(full_path); Ok(path::PathBuf::from(&path)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_load_from_dirs")] pub fn load_from_dirs, U: AsRef>( &self, file: T, search_dirs: &[U], flags: KeyFileFlags, ) -> Result { unsafe { let search_dirs: Vec<&std::path::Path> = search_dirs.iter().map(AsRef::as_ref).collect(); let mut error = ptr::null_mut(); let mut full_path: *mut libc::c_char = ptr::null_mut(); let _ = ffi::g_key_file_load_from_dirs( self.to_glib_none().0, file.as_ref().to_glib_none().0, search_dirs.to_glib_none().0, &mut full_path, flags.into_glib(), &mut error, ); if error.is_null() { let path: GString = from_glib_full(full_path); Ok(path::PathBuf::from(&path)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_to_data")] pub fn to_data(&self) -> GString { unsafe { let ret = ffi::g_key_file_to_data(self.to_glib_none().0, ptr::null_mut(), ptr::null_mut()); from_glib_full(ret) } } #[doc(alias = "g_key_file_get_groups")] #[doc(alias = "get_groups")] pub fn groups(&self) -> PtrSlice { unsafe { let mut length = mem::MaybeUninit::uninit(); let ret = ffi::g_key_file_get_groups(self.to_glib_none().0, length.as_mut_ptr()); FromGlibContainer::from_glib_full_num(ret, length.assume_init() as _) } } #[doc(alias = "g_key_file_get_keys")] #[doc(alias = "get_keys")] pub fn keys(&self, group_name: &str) -> Result, crate::Error> { unsafe { let mut length = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_keys( self.to_glib_none().0, group_name.to_glib_none().0, length.as_mut_ptr(), &mut error, ); if error.is_null() { Ok(FromGlibContainer::from_glib_full_num( ret, length.assume_init() as _, )) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_boolean")] #[doc(alias = "get_boolean")] pub fn boolean(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_boolean( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(from_glib(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_has_key")] pub fn has_key(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_key_file_has_key( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(from_glib(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_boolean_list")] #[doc(alias = "get_boolean_list")] pub fn boolean_list(&self, group_name: &str, key: &str) -> Result, Error> { unsafe { let mut length = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_boolean_list( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, length.as_mut_ptr(), &mut error, ); if !error.is_null() { return Err(from_glib_full(error)); } Ok(FromGlibContainer::from_glib_container_num( ret, length.assume_init() as _, )) } } #[doc(alias = "g_key_file_get_string")] #[doc(alias = "get_string")] pub fn string(&self, group_name: &str, key: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_string( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { ffi::g_free(ret as *mut _); Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_string_list")] #[doc(alias = "get_string_list")] pub fn string_list(&self, group_name: &str, key: &str) -> Result, Error> { unsafe { let mut length = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_string_list( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, length.as_mut_ptr(), &mut error, ); if error.is_null() { Ok(FromGlibContainer::from_glib_full_num( ret, length.assume_init() as _, )) } else { ffi::g_strfreev(ret); Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_locale_string")] #[doc(alias = "get_locale_string")] pub fn locale_string( &self, group_name: &str, key: &str, locale: Option<&str>, ) -> Result { unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_locale_string( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, locale.to_glib_none().0, &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { ffi::g_free(ret as *mut _); Err(from_glib_full(error)) } } } #[doc(alias = "g_key_file_get_locale_string_list")] #[doc(alias = "get_locale_string_list")] pub fn locale_string_list( &self, group_name: &str, key: &str, locale: Option<&str>, ) -> Result, Error> { unsafe { let mut length = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let ret = ffi::g_key_file_get_locale_string_list( self.to_glib_none().0, group_name.to_glib_none().0, key.to_glib_none().0, locale.to_glib_none().0, length.as_mut_ptr(), &mut error, ); if error.is_null() { Ok(FromGlibContainer::from_glib_full_num( ret, length.assume_init() as _, )) } else { ffi::g_strfreev(ret); Err(from_glib_full(error)) } } } } glib-0.20.9/src/lib.rs000064400000000000000000000165331046102023000125440ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #![cfg_attr(docsrs, feature(doc_cfg))] #![allow(clippy::missing_safety_doc)] #![allow(clippy::manual_c_str_literals)] #![allow(renamed_and_removed_lints)] // Override docs references to point to locally generated docs // rustdoc-stripper-ignore-next //! [`Type`]: struct@Type //! [`StaticType`]: trait@types::StaticType //! [`Value`]: struct@Value //! [`Variant``]: struct@Variant //! [`StaticVariantType`]: trait@variant::StaticVariantType //! [`Error`]: struct@Error //! [`FileError`]: enum@FileError //! [`Object`]: struct@Object //! [`Rc>`]: mod@std::cell#introducing-mutability-inside-of-something-immutable //! [`IsA`]: trait@object::IsA //! [`Cast`]: trait@object::Cast //! [`ObjectExt`]: trait@object::ObjectExt //! [`wrapper!`]: macro@wrapper //! [`wrapper`]: mod@wrapper //! [`boxed`]: mod@boxed //! [`shared`]: mod@shared //! [mod@object]: mod@object //! [`translate`]: mod@translate #![doc = include_str!("../README.md")] pub use bitflags; #[doc(hidden)] pub use glib_macros::cstr_bytes; pub use glib_macros::{ async_test, clone, closure, closure_local, derived_properties, flags, object_interface, object_subclass, Boxed, Downgrade, Enum, ErrorDomain, Properties, SharedBoxed, ValueDelegate, Variant, }; pub use glib_sys as ffi; pub use gobject_sys as gobject_ffi; pub use self::{ byte_array::ByteArray, bytes::Bytes, closure::{Closure, RustClosure}, enums::{EnumClass, EnumValue, FlagsBuilder, FlagsClass, FlagsValue, UserDirectory}, error::{BoolError, Error}, object::{BorrowedObject, Class, InitiallyUnowned, Interface, Object, SendWeakRef, WeakRef}, signal::{ signal_handler_block, signal_handler_disconnect, signal_handler_unblock, signal_stop_emission_by_name, Propagation, SignalHandlerId, }, types::{ILong, Pointer, Type, ULong}, value::{BoxedValue, SendValue, Value}, variant::{FixedSizeVariantArray, Variant}, variant_dict::VariantDict, variant_iter::{VariantIter, VariantStrIter}, variant_type::{VariantTy, VariantTyIterator, VariantType}, FileError, }; // Hack for the time being to retrieve the current function's name as a string. // Based on the stdext cratelicensed under the MIT license. // // Copyright (c) 2020 Igor Aleksanov // // Previous attempts to get such a macro into std: // * https://github.com/rust-lang/rfcs/pull/466 // * https://github.com/rust-lang/rfcs/pull/1719 // * https://github.com/rust-lang/rfcs/issues/1743 // * https://github.com/rust-lang/rfcs/pull/2818 // * ... // rustdoc-stripper-ignore-next /// This macro returns the name of the enclosing function. /// As the internal implementation is based on the [`std::any::type_name`], this macro derives /// all the limitations of this function. /// /// ## Examples /// /// ```rust /// mod bar { /// pub fn sample_function() { /// assert!(glib::function_name!().ends_with("bar::sample_function")); /// } /// } /// /// bar::sample_function(); /// ``` /// /// [`std::any::type_name`]: https://doc.rust-lang.org/std/any/fn.type_name.html #[macro_export] macro_rules! function_name { () => {{ // Okay, this is ugly, I get it. However, this is the best we can get on a stable rust. fn f() {} fn type_name_of(_: T) -> &'static str { std::any::type_name::() } let name = type_name_of(f); // `3` is the length of the `::f`. &name[..name.len() - 3] }}; } pub mod clone; #[macro_use] pub mod wrapper; #[macro_use] pub mod boxed; #[macro_use] pub mod boxed_inline; #[macro_use] pub mod shared; #[macro_use] pub mod error; #[macro_use] pub mod object; mod boxed_any_object; pub use boxed_any_object::BoxedAnyObject; mod exit_code; pub use exit_code::ExitCode; pub mod collections; pub use collections::{List, PtrSlice, SList, Slice, StrV}; pub use self::auto::*; #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] #[allow(unused_imports)] #[allow(non_upper_case_globals)] mod auto; #[cfg(feature = "v2_74")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))] pub use self::gobject::SignalGroup; pub use self::gobject::{ Binding, BindingFlags, InterfaceInfo, ParamFlags, SignalFlags, TypeFlags, TypeInfo, TypeModule, TypePlugin, TypeValueTable, }; #[cfg(feature = "v2_72")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] pub use self::gobject::{BindingGroup, BindingGroupBuilder}; mod gobject; mod byte_array; mod bytes; mod control_flow; pub use self::control_flow::ControlFlow; pub mod char; pub use self::char::{Char, UChar}; mod checksum; pub mod closure; mod convert; pub use self::convert::*; pub mod enums; mod functions; pub use self::functions::*; mod key_file; pub mod prelude; pub mod signal; pub mod source; pub use self::source::*; #[macro_use] pub mod translate; mod gstring; pub use self::gstring::*; mod gstring_builder; pub use self::gstring_builder::GStringBuilder; pub mod types; mod unicollate; pub use self::unicollate::{CollationKey, FilenameCollationKey}; mod utils; pub use self::utils::*; mod unichar; pub use self::unichar::*; mod main_context; pub use self::main_context::MainContextAcquireGuard; mod date; mod date_time; mod time_span; mod time_zone; pub use self::time_span::TimeSpan; pub mod value; pub mod variant; mod variant_dict; mod variant_iter; mod variant_type; pub use self::date::Date; mod value_array; pub use self::value_array::ValueArray; mod param_spec; pub use self::param_spec::*; pub mod property; mod quark; pub use self::quark::Quark; pub mod match_info; pub use self::match_info::MatchInfo; pub mod regex; #[macro_use] mod log; #[doc(hidden)] #[cfg(feature = "log_macros")] #[cfg_attr(docsrs, doc(cfg(feature = "log_macros")))] pub use rs_log; pub use self::log::{ log_default_handler, log_remove_handler, log_set_always_fatal, log_set_default_handler, log_set_fatal_mask, log_set_handler, log_set_writer_func, log_structured_array, log_unset_default_handler, log_variant, log_writer_default, log_writer_format_fields, log_writer_journald, log_writer_standard_streams, set_print_handler, set_printerr_handler, unset_print_handler, unset_printerr_handler, LogField, LogHandlerId, LogLevel, LogLevels, }; #[cfg(feature = "v2_68")] pub use self::log::{log_writer_default_set_use_stderr, log_writer_default_would_drop}; #[cfg(unix)] pub use self::log::{log_writer_is_journald, log_writer_supports_color}; #[cfg(feature = "log")] #[cfg_attr(docsrs, doc(cfg(feature = "log")))] #[macro_use] mod bridged_logging; #[cfg(feature = "log")] #[cfg_attr(docsrs, doc(cfg(feature = "log")))] pub use self::bridged_logging::{rust_log_handler, GlibLogger, GlibLoggerDomain, GlibLoggerFormat}; #[macro_use] pub mod subclass; mod main_context_futures; pub use main_context_futures::{JoinError, JoinHandle, SpawnWithinJoinHandle}; mod source_futures; pub use self::source_futures::*; mod future_with_timeout; pub use self::future_with_timeout::*; mod thread_pool; pub use self::thread_pool::{ThreadHandle, ThreadPool}; pub mod thread_guard; // rustdoc-stripper-ignore-next /// This is the log domain used by the [`clone!`][crate::clone!] macro. If you want to use a custom /// logger (it prints to stdout by default), you can set your own logger using the corresponding /// `log` functions. pub const CLONE_MACRO_LOG_DOMAIN: &str = "glib-rs-clone"; #[cfg(target_family = "windows")] mod win32; #[cfg(target_family = "windows")] pub use self::win32::*; glib-0.20.9/src/log.rs000064400000000000000000001033771046102023000125620ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #[cfg(unix)] use std::os::unix::io::AsRawFd; use std::{ boxed::Box as Box_, sync::{Arc, Mutex, OnceLock}, }; use crate::{ffi, translate::*, GStr, GString, LogWriterOutput}; #[derive(Debug)] pub struct LogHandlerId(u32); #[doc(hidden)] impl FromGlib for LogHandlerId { #[inline] unsafe fn from_glib(value: u32) -> Self { Self(value) } } #[doc(hidden)] impl IntoGlib for LogHandlerId { type GlibType = u32; #[inline] fn into_glib(self) -> u32 { self.0 } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum LogLevel { #[doc(alias = "G_LOG_LEVEL_ERROR")] Error, #[doc(alias = "G_LOG_LEVEL_CRITICAL")] Critical, #[doc(alias = "G_LOG_LEVEL_WARNING")] Warning, #[doc(alias = "G_LOG_LEVEL_MESSAGE")] Message, #[doc(alias = "G_LOG_LEVEL_INFO")] Info, #[doc(alias = "G_LOG_LEVEL_DEBUG")] Debug, } #[doc(hidden)] impl IntoGlib for LogLevel { type GlibType = u32; #[inline] fn into_glib(self) -> u32 { match self { Self::Error => ffi::G_LOG_LEVEL_ERROR, Self::Critical => ffi::G_LOG_LEVEL_CRITICAL, Self::Warning => ffi::G_LOG_LEVEL_WARNING, Self::Message => ffi::G_LOG_LEVEL_MESSAGE, Self::Info => ffi::G_LOG_LEVEL_INFO, Self::Debug => ffi::G_LOG_LEVEL_DEBUG, } } } #[doc(hidden)] impl FromGlib for LogLevel { #[inline] unsafe fn from_glib(value: u32) -> Self { if value & ffi::G_LOG_LEVEL_ERROR != 0 { Self::Error } else if value & ffi::G_LOG_LEVEL_CRITICAL != 0 { Self::Critical } else if value & ffi::G_LOG_LEVEL_WARNING != 0 { Self::Warning } else if value & ffi::G_LOG_LEVEL_MESSAGE != 0 { Self::Message } else if value & ffi::G_LOG_LEVEL_INFO != 0 { Self::Info } else if value & ffi::G_LOG_LEVEL_DEBUG != 0 { Self::Debug } else { panic!("Unknown log level: {value}") } } } impl LogLevel { #[doc(hidden)] pub fn priority(&self) -> &'static str { match self { Self::Error => "3", Self::Critical => "4", Self::Warning => "4", Self::Message => "5", Self::Info => "6", Self::Debug => "7", } } } bitflags::bitflags! { #[doc(alias = "GLogLevelFlags")] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct LogLevels: u32 { #[doc(alias = "G_LOG_LEVEL_ERROR")] const LEVEL_ERROR = ffi::G_LOG_LEVEL_ERROR; #[doc(alias = "G_LOG_LEVEL_CRITICAL")] const LEVEL_CRITICAL = ffi::G_LOG_LEVEL_CRITICAL; #[doc(alias = "G_LOG_LEVEL_WARNING")] const LEVEL_WARNING = ffi::G_LOG_LEVEL_WARNING; #[doc(alias = "G_LOG_LEVEL_MESSAGE")] const LEVEL_MESSAGE = ffi::G_LOG_LEVEL_MESSAGE; #[doc(alias = "G_LOG_LEVEL_INFO")] const LEVEL_INFO = ffi::G_LOG_LEVEL_INFO; #[doc(alias = "G_LOG_LEVEL_DEBUG")] const LEVEL_DEBUG = ffi::G_LOG_LEVEL_DEBUG; } } #[doc(hidden)] impl IntoGlib for LogLevels { type GlibType = ffi::GLogLevelFlags; #[inline] fn into_glib(self) -> ffi::GLogLevelFlags { self.bits() } } #[doc(hidden)] impl FromGlib for LogLevels { #[inline] unsafe fn from_glib(value: ffi::GLogLevelFlags) -> Self { Self::from_bits_truncate(value) } } fn to_log_flags(fatal: bool, recursion: bool) -> u32 { (if fatal { ffi::G_LOG_FLAG_FATAL } else { 0 }) | if recursion { ffi::G_LOG_FLAG_RECURSION } else { 0 } } #[doc(alias = "g_log_set_handler_full")] pub fn log_set_handler, LogLevel, &str) + Send + Sync + 'static>( log_domain: Option<&str>, log_levels: LogLevels, fatal: bool, recursion: bool, log_func: P, ) -> LogHandlerId { let log_func_data: Box_

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

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

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

as _); let super_callback0: Box_

= log_func_data; unsafe { from_glib(ffi::g_log_set_handler_full( log_domain.to_glib_none().0, log_levels.into_glib() | to_log_flags(fatal, recursion), log_func, Box_::into_raw(super_callback0) as *mut _, destroy_call4, )) } } #[doc(alias = "g_log_remove_handler")] pub fn log_remove_handler(log_domain: Option<&str>, handler_id: LogHandlerId) { unsafe { ffi::g_log_remove_handler(log_domain.to_glib_none().0, handler_id.into_glib()); } } #[doc(alias = "g_log_set_always_fatal")] pub fn log_set_always_fatal(fatal_levels: LogLevels) -> LogLevels { unsafe { from_glib(ffi::g_log_set_always_fatal(fatal_levels.into_glib())) } } #[doc(alias = "g_log_set_fatal_mask")] pub fn log_set_fatal_mask(log_domain: Option<&str>, fatal_levels: LogLevels) -> LogLevels { unsafe { from_glib(ffi::g_log_set_fatal_mask( log_domain.to_glib_none().0, fatal_levels.into_glib(), )) } } type PrintCallback = dyn Fn(&str) + Send + Sync + 'static; fn print_handler() -> &'static Mutex>> { static MUTEX: OnceLock>>> = OnceLock::new(); MUTEX.get_or_init(|| Mutex::new(None)) } // rustdoc-stripper-ignore-next /// To set back the default print handler, use the [`unset_print_handler`] function. #[doc(alias = "g_set_print_handler")] pub fn set_print_handler(func: P) { unsafe extern "C" fn func_func(string: *const libc::c_char) { if let Some(callback) = print_handler() .lock() .expect("Failed to lock PRINT_HANDLER") .as_ref() .map(Arc::clone) { let string: Borrowed = from_glib_borrow(string); (*callback)(string.as_str()) } } *print_handler() .lock() .expect("Failed to lock PRINT_HANDLER to change callback") = Some(Arc::new(func)); unsafe { ffi::g_set_print_handler(Some(func_func as _)) }; } // rustdoc-stripper-ignore-next /// To set the default print handler, use the [`set_print_handler`] function. pub fn unset_print_handler() { *print_handler() .lock() .expect("Failed to lock PRINT_HANDLER to remove callback") = None; unsafe { ffi::g_set_print_handler(None) }; } fn printerr_handler() -> &'static Mutex>> { static MUTEX: OnceLock>>> = OnceLock::new(); MUTEX.get_or_init(|| Mutex::new(None)) } // rustdoc-stripper-ignore-next /// To set back the default print handler, use the [`unset_printerr_handler`] function. #[doc(alias = "g_set_printerr_handler")] pub fn set_printerr_handler(func: P) { unsafe extern "C" fn func_func(string: *const libc::c_char) { if let Some(callback) = printerr_handler() .lock() .expect("Failed to lock PRINTERR_HANDLER") .as_ref() .map(Arc::clone) { let string: Borrowed = from_glib_borrow(string); (*callback)(string.as_str()) } } *printerr_handler() .lock() .expect("Failed to lock PRINTERR_HANDLER to change callback") = Some(Arc::new(func)); unsafe { ffi::g_set_printerr_handler(Some(func_func as _)) }; } // rustdoc-stripper-ignore-next /// To set the default print handler, use the [`set_printerr_handler`] function. pub fn unset_printerr_handler() { *printerr_handler() .lock() .expect("Failed to lock PRINTERR_HANDLER to remove callback") = None; unsafe { ffi::g_set_printerr_handler(None) }; } type LogCallback = dyn Fn(Option<&str>, LogLevel, &str) + Send + Sync + 'static; fn default_handler() -> &'static Mutex>> { static MUTEX: OnceLock>>> = OnceLock::new(); MUTEX.get_or_init(|| Mutex::new(None)) } // rustdoc-stripper-ignore-next /// To set back the default print handler, use the [`log_unset_default_handler`] function. #[doc(alias = "g_log_set_default_handler")] pub fn log_set_default_handler, LogLevel, &str) + Send + Sync + 'static>( log_func: P, ) { unsafe extern "C" fn func_func( log_domain: *const libc::c_char, log_levels: ffi::GLogLevelFlags, message: *const libc::c_char, _user_data: ffi::gpointer, ) { if let Some(callback) = default_handler() .lock() .expect("Failed to lock DEFAULT_HANDLER") .as_ref() .map(Arc::clone) { let log_domain: Borrowed> = from_glib_borrow(log_domain); let message: Borrowed = from_glib_borrow(message); (*callback)( (*log_domain).as_ref().map(|s| s.as_str()), from_glib(log_levels), message.as_str(), ); } } *default_handler() .lock() .expect("Failed to lock DEFAULT_HANDLER to change callback") = Some(Arc::new(log_func)); unsafe { ffi::g_log_set_default_handler(Some(func_func as _), std::ptr::null_mut()) }; } // rustdoc-stripper-ignore-next /// To set the default print handler, use the [`log_set_default_handler`] function. #[doc(alias = "g_log_set_default_handler")] pub fn log_unset_default_handler() { *default_handler() .lock() .expect("Failed to lock DEFAULT_HANDLER to remove callback") = None; unsafe { ffi::g_log_set_default_handler(Some(ffi::g_log_default_handler), std::ptr::null_mut()) }; } #[doc(alias = "g_log_default_handler")] pub fn log_default_handler(log_domain: Option<&str>, log_level: LogLevel, message: Option<&str>) { unsafe { ffi::g_log_default_handler( log_domain.to_glib_none().0, log_level.into_glib(), message.to_glib_none().0, std::ptr::null_mut(), ) } } // rustdoc-stripper-ignore-next /// Structure representing a single field in a structured log entry. /// /// See [`g_log_structured`][gls] for details. Log fields may contain UTF-8 strings, binary with /// embedded nul bytes, or arbitrary pointers. /// /// [gls]: https://docs.gtk.org/glib/func.log_structured.html #[repr(transparent)] #[derive(Debug)] #[doc(alias = "GLogField")] pub struct LogField<'a>(ffi::GLogField, std::marker::PhantomData<&'a GStr>); impl<'a> LogField<'a> { // rustdoc-stripper-ignore-next /// Creates a field from a borrowed key and value. pub fn new(key: &'a GStr, value: &[u8]) -> Self { let (value, length) = if value.is_empty() { // Use an empty C string to represent empty data, since length: 0 is reserved for user // data fields. (&[0u8] as &[u8], -1isize) } else { (value, value.len().try_into().unwrap()) }; Self( ffi::GLogField { key: key.as_ptr(), value: value.as_ptr() as *const _, length, }, Default::default(), ) } // rustdoc-stripper-ignore-next /// Creates a field with an empty value and `data` as a user data key. Fields created with this /// function are ignored by the default log writer. These fields are used to pass custom data /// into a writer function set with [`log_set_writer_func`], where it can be retrieved using /// [`Self::user_data`]. /// /// The passed `usize` can be used by the log writer as a key into a static data structure. /// Thread locals are preferred since the log writer function will run in the same thread that /// invoked [`log_structured_array`]. pub fn new_user_data(key: &'a GStr, data: usize) -> Self { Self( ffi::GLogField { key: key.as_ptr(), value: data as *const _, length: 0, }, Default::default(), ) } // rustdoc-stripper-ignore-next /// Retrieves the field key. pub fn key(&self) -> &str { unsafe { std::ffi::CStr::from_ptr(self.0.key as *const _) } .to_str() .unwrap() } // rustdoc-stripper-ignore-next /// Retrieves a byte array of the field value. Returns `None` if the field was created with /// [`Self::new_user_data`]. pub fn value_bytes(&self) -> Option<&[u8]> { match self.0.length { 0 => None, n if n < 0 => { Some(unsafe { std::ffi::CStr::from_ptr(self.0.value as *const _) }.to_bytes()) } _ => Some(unsafe { std::slice::from_raw_parts(self.0.value as *const u8, self.0.length as usize) }), } } // rustdoc-stripper-ignore-next /// Retrieves a string of the field value, or `None` if the string is not valid UTF-8. Also /// returns `None` if the field was created with [`Self::new_user_data`]. pub fn value_str(&self) -> Option<&str> { std::str::from_utf8(self.value_bytes()?).ok() } // rustdoc-stripper-ignore-next /// Retrieves the the user data value from a field created with [`Self::new_user_data`]. /// Returns `None` if the field was created with [`Self::new`]. pub fn user_data(&self) -> Option { (self.0.length == 0).then_some(self.0.value as usize) } } type WriterCallback = dyn Fn(LogLevel, &[LogField<'_>]) -> LogWriterOutput + Send + Sync + 'static; static WRITER_FUNC: OnceLock> = OnceLock::new(); #[doc(alias = "g_log_set_writer_func")] pub fn log_set_writer_func< P: Fn(LogLevel, &[LogField<'_>]) -> LogWriterOutput + Send + Sync + 'static, >( writer_func: P, ) { if WRITER_FUNC.set(Box::new(writer_func)).is_err() { panic!("Writer func can only be set once"); } unsafe extern "C" fn writer_trampoline( log_level: ffi::GLogLevelFlags, fields: *const ffi::GLogField, n_fields: libc::size_t, _user_data: ffi::gpointer, ) -> ffi::GLogWriterOutput { let writer_func = WRITER_FUNC.get().unwrap(); let fields = std::slice::from_raw_parts(fields as *const LogField<'_>, n_fields); writer_func(from_glib(log_level), fields).into_glib() } unsafe { ffi::g_log_set_writer_func(Some(writer_trampoline), std::ptr::null_mut(), None); } } #[macro_export] #[doc(hidden)] macro_rules! g_log_inner { ($log_domain:expr, $log_level:expr, $format:literal $(,$arg:expr)* $(,)?) => {{ let mut w = $crate::GStringBuilder::default(); // Can't really happen but better safe than sorry if !std::fmt::Write::write_fmt(&mut w, std::format_args!($format, $($arg),*)).is_err() { unsafe { $crate::ffi::g_log( $crate::translate::ToGlibPtr::to_glib_none(&$log_domain).0, <$crate::LogLevel as $crate::translate::IntoGlib>::into_glib( $log_level ), b"%s\0".as_ptr() as *const _, $crate::translate::ToGlibPtr::<*const std::os::raw::c_char>::to_glib_none( &w.into_string() ).0, ); } } }}; } // rustdoc-stripper-ignore-next /// Macro used to log using GLib logging system. It uses [g_log]. /// /// [g_log]: https://docs.gtk.org/glib/func.log.html /// /// Example: /// /// ```no_run /// use glib::{LogLevel, g_log}; /// /// g_log!("test", LogLevel::Debug, "test"); /// g_log!("test", LogLevel::Message, "test"); /// // trailing commas work as well: /// g_log!("test", LogLevel::Message, "test",); /// /// // You can also pass arguments like in format! or println!: /// let x = 12; /// g_log!("test", LogLevel::Error, "test: {}", x); /// g_log!("test", LogLevel::Critical, "test: {}", x); /// g_log!("test", LogLevel::Warning, "test: {} {}", x, "a"); /// // trailing commas work as well: /// g_log!("test", LogLevel::Warning, "test: {} {}", x, "a",); /// ``` /// /// To be noted that the log domain is optional: /// /// ```no_run /// use glib::{LogLevel, g_log}; /// /// // As you can see: no log domain: /// g_log!(LogLevel::Message, "test"); /// // For the rest, it's just like when you have the log domain: /// // trailing commas: /// g_log!(LogLevel::Message, "test",); /// /// // formatting: /// let x = 12; /// g_log!(LogLevel::Warning, "test: {} {}", x, "a"); /// g_log!(LogLevel::Warning, "test: {} {}", x, "a",); /// ``` #[macro_export] macro_rules! g_log { ($log_level:expr, $format:literal $(,$arg:expr)* $(,)?) => {{ $crate::g_log_inner!(None::<&str>, $log_level, $format, $($arg),*); }}; ($log_domain:expr, $log_level:expr, $format:literal $(,$arg:expr)* $(,)?) => {{ let log_domain = as std::convert::From<_>>::from($log_domain); $crate::g_log_inner!(log_domain, $log_level, $format, $($arg),*); }}; } // rustdoc-stripper-ignore-next /// Macro used to log using GLib logging system. It uses [g_log]. /// /// [g_log]: https://docs.gtk.org/glib/func.log.html /// /// It is the same as calling the [`g_log!`](crate::g_log!) macro with [`LogLevel::Error`]. /// /// Example: /// /// ```no_run /// use glib::g_error; /// /// g_error!("test", "test"); /// // Equivalent to: /// use glib::{g_log, LogLevel}; /// g_log!("test", LogLevel::Error, "test"); /// /// // trailing commas work as well: /// g_error!("test", "test",); /// /// // You can also pass arguments like in format! or println!: /// let x = 12; /// g_error!("test", "test: {}", x); /// g_error!("test", "test: {} {}", x, "a"); /// // trailing commas work as well: /// g_error!("test", "test: {} {}", x, "a",); /// ``` #[macro_export] macro_rules! g_error { ($log_domain:expr, $format:literal, $($arg:expr),* $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Error, $format, $($arg),*); }}; ($log_domain:expr, $format:literal $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Error, $format); }}; } // rustdoc-stripper-ignore-next /// Macro used to log using GLib logging system. It uses [g_log]. /// /// [g_log]: https://docs.gtk.org/glib/func.log.html /// /// It is the same as calling the [`g_log!`](crate::g_log!) macro with [`LogLevel::Critical`]. /// /// Example: /// /// ```no_run /// use glib::g_critical; /// /// g_critical!("test", "test"); /// // Equivalent to: /// use glib::{g_log, LogLevel}; /// g_log!("test", LogLevel::Critical, "test"); /// /// // trailing commas work as well: /// g_critical!("test", "test",); /// /// // You can also pass arguments like in format! or println!: /// let x = 12; /// g_critical!("test", "test: {}", x); /// g_critical!("test", "test: {} {}", x, "a"); /// // trailing commas work as well: /// g_critical!("test", "test: {} {}", x, "a",); /// ``` #[macro_export] macro_rules! g_critical { ($log_domain:expr, $format:literal, $($arg:expr),* $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Critical, $format, $($arg),*); }}; ($log_domain:expr, $format:literal $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Critical, $format); }}; } // rustdoc-stripper-ignore-next /// Macro used to log using GLib logging system. It uses [g_log]. /// /// [g_log]: https://docs.gtk.org/glib/func.log.html /// /// It is the same as calling the [`g_log!`](crate::g_log!) macro with [`LogLevel::Warning`]. /// /// Example: /// /// ```no_run /// use glib::g_warning; /// /// g_warning!("test", "test"); /// // Equivalent to: /// use glib::{g_log, LogLevel}; /// g_log!("test", LogLevel::Warning, "test"); /// /// // trailing commas work as well: /// g_warning!("test", "test",); /// /// // You can also pass arguments like in format! or println!: /// let x = 12; /// g_warning!("test", "test: {}", x); /// g_warning!("test", "test: {} {}", x, "a"); /// // trailing commas work as well: /// g_warning!("test", "test: {} {}", x, "a",); /// ``` #[macro_export] macro_rules! g_warning { ($log_domain:expr, $format:literal, $($arg:expr),* $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Warning, $format, $($arg),*); }}; ($log_domain:expr, $format:literal $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Warning, $format); }}; } // rustdoc-stripper-ignore-next /// Macro used to log using GLib logging system. It uses [g_log]. /// /// [g_log]: https://docs.gtk.org/glib/func.log.html /// /// It is the same as calling the [`g_log!`](crate::g_log!) macro with [`LogLevel::Message`]. /// /// Example: /// /// ```no_run /// use glib::g_message; /// /// g_message!("test", "test"); /// // Equivalent to: /// use glib::{g_log, LogLevel}; /// g_log!("test", LogLevel::Message, "test"); /// /// // trailing commas work as well: /// g_message!("test", "test",); /// /// // You can also pass arguments like in format! or println!: /// let x = 12; /// g_message!("test", "test: {}", x); /// g_message!("test", "test: {} {}", x, "a"); /// // trailing commas work as well: /// g_message!("test", "test: {} {}", x, "a",); /// ``` #[macro_export] macro_rules! g_message { ($log_domain:expr, $format:literal, $($arg:expr),* $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Message, $format, $($arg),*); }}; ($log_domain:expr, $format:literal $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Message, $format); }}; } // rustdoc-stripper-ignore-next /// Macro used to log using GLib logging system. It uses [g_log]. /// /// [g_log]: https://docs.gtk.org/glib/func.log.html /// /// It is the same as calling the [`g_log!`](crate::g_log!) macro with [`LogLevel::Info`]. /// /// Example: /// /// ```no_run /// use glib::g_info; /// /// g_info!("test", "test"); /// // Equivalent to: /// use glib::{g_log, LogLevel}; /// g_log!("test", LogLevel::Info, "test"); /// /// // trailing commas work as well: /// g_info!("test", "test",); /// /// // You can also pass arguments like in format! or println!: /// let x = 12; /// g_info!("test", "test: {}", x); /// g_info!("test", "test: {} {}", x, "a"); /// // trailing commas work as well: /// g_info!("test", "test: {} {}", x, "a",); /// ``` #[macro_export] macro_rules! g_info { ($log_domain:expr, $format:literal, $($arg:expr),* $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Info, $format, $($arg),*); }}; ($log_domain:expr, $format:literal $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Info, $format); }}; } // rustdoc-stripper-ignore-next /// Macro used to log using GLib logging system. It uses [g_log]. /// /// [g_log]: https://docs.gtk.org/glib/func.log.html /// /// It is the same as calling the [`g_log!`](crate::g_log!) macro with [`LogLevel::Debug`]. /// /// Example: /// /// ```no_run /// use glib::g_debug; /// /// g_debug!("test", "test"); /// // Equivalent to: /// use glib::{g_log, LogLevel}; /// g_log!("test", LogLevel::Debug, "test"); /// /// // trailing commas work as well: /// g_debug!("test", "test",); /// /// // You can also pass arguments like in format! or println!: /// let x = 12; /// g_debug!("test", "test: {}", x); /// g_debug!("test", "test: {} {}", x, "a"); /// // trailing commas work as well: /// g_debug!("test", "test: {} {}", x, "a",); /// ``` #[macro_export] macro_rules! g_debug { ($log_domain:expr, $format:literal, $($arg:expr),* $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Debug, $format, $($arg),*); }}; ($log_domain:expr, $format:literal $(,)?) => {{ $crate::g_log!($log_domain, $crate::LogLevel::Debug, $format); }}; } #[doc(hidden)] #[macro_export] macro_rules! g_print_inner { ($func:ident, $format:expr $(, $arg:expr)* $(,)?) => {{ let mut w = $crate::GStringBuilder::default(); // Can't really happen but better safe than sorry if !std::fmt::Write::write_fmt(&mut w, std::format_args!($format, $($arg),*)).is_err() { unsafe { $crate::ffi::$func( b"%s\0".as_ptr() as *const _, $crate::translate::ToGlibPtr::<*const std::os::raw::c_char>::to_glib_none( &w.into_string() ).0, ); } } }}; } // rustdoc-stripper-ignore-next /// Macro used to print messages. It uses [g_print]. /// /// [g_print]: https://docs.gtk.org/glib/func.print.html /// /// Example: /// /// ```no_run /// use glib::g_print; /// /// g_print!("test"); /// // trailing commas work as well: /// g_print!("test",); /// /// let x = 12; /// g_print!("test: {}", x); /// g_print!("test: {} {}", x, "a"); /// // trailing commas work as well: /// g_print!("test: {} {}", x, "a",); /// ``` #[macro_export] macro_rules! g_print { ($format:expr $(,$arg:expr)* $(,)?) => {{ $crate::g_print_inner!(g_print, $format, $($arg),*); }}; } // rustdoc-stripper-ignore-next /// Macro used to print error messages. It uses [g_printerr]. /// /// [g_printerr]: https://docs.gtk.org/glib/func.printerr.html /// /// Example: /// /// ```no_run /// use glib::g_printerr; /// /// g_printerr!("test"); /// // trailing commas work as well: /// g_printerr!("test",); /// /// let x = 12; /// g_printerr!("test: {}", x); /// g_printerr!("test: {} {}", x, "a"); /// // trailing commas work as well: /// g_printerr!("test: {} {}", x, "a",); /// ``` #[macro_export] macro_rules! g_printerr { ($format:expr $(, $arg:expr)* $(,)?) => {{ $crate::g_print_inner!(g_printerr, $format, $($arg),*); }}; } // rustdoc-stripper-ignore-next /// Macro used to log using GLib structured logging system. /// /// The structured data is provided inside braces as key-value pairs using the `=>` token and /// separated by semicolons. The key can be a string literal or an expression that satisfies /// [`AsRef`]. The value can be a format string with arguments, or a single expression that /// satisfies `AsRef<[u8]>`. /// /// See [`g_log_structured`][gls] for more details. /// /// [gls]: https://docs.gtk.org/glib/func.log_structured.html /// [`AsRef`]: crate::GStr /// /// Example: /// /// ```no_run /// use glib::{GString, LogLevel, log_structured}; /// use std::ffi::CString; /// /// log_structured!( /// "test", /// LogLevel::Debug, /// { /// // a normal string field /// "MY_FIELD" => "123"; /// // fields can also take format arguments /// "MY_FIELD2" => "abc {}", "def"; /// // single argument can be a &str or a &[u8] or anything else satsfying AsRef<[u8]> /// "MY_FIELD3" => CString::new("my string").unwrap().to_bytes(); /// // field names can also be dynamic /// GString::from("MY_FIELD4") => b"a binary string".to_owned(); /// // the main log message goes in the MESSAGE field /// "MESSAGE" => "test: {} {}", 1, 2, ; /// } /// ); /// ``` #[macro_export] macro_rules! log_structured { ($log_domain:expr, $log_level:expr, {$($key:expr => $format:expr $(,$arg:expr)* $(,)?);+ $(;)?} $(,)?) => {{ let log_domain = as std::convert::From<_>>::from($log_domain); let log_domain_str = log_domain.unwrap_or_default(); let level: $crate::LogLevel = $log_level; let field_count = <[()]>::len(&[$($crate::log_structured_inner!(@clear $key)),+]) + log_domain.map(|_| 2usize).unwrap_or(1usize) + 3; let mut line = [0u8; 32]; // 32 decimal digits of line numbers should be enough! let line = { use std::io::Write; let mut cursor = std::io::Cursor::new(&mut line[..]); std::write!(&mut cursor, "{}", line!()).unwrap(); let pos = cursor.position() as usize; &line[..pos] }; $crate::log_structured_array( level, &[ $crate::LogField::new( $crate::gstr!("PRIORITY"), level.priority().as_bytes(), ), $crate::LogField::new( $crate::gstr!("CODE_FILE"), file!().as_bytes(), ), $crate::LogField::new( $crate::gstr!("CODE_LINE"), line, ), $crate::LogField::new( $crate::gstr!("CODE_FUNC"), $crate::function_name!().as_bytes(), ), $( $crate::LogField::new( $crate::log_structured_inner!(@key $key), $crate::log_structured_inner!(@value $format $(,$arg)*), ), )+ $crate::LogField::new( $crate::gstr!("GLIB_DOMAIN"), log_domain_str.as_bytes(), ), ][0..field_count], ) }}; } #[doc(hidden)] #[macro_export] macro_rules! log_structured_inner { (@clear $($_:tt)*) => { () }; (@key $key:literal) => { $crate::gstr!($key) }; (@key $key:expr) => { std::convert::AsRef::<$crate::GStr>::as_ref(&$key) }; (@value $value:expr) => { std::convert::AsRef::<[u8]>::as_ref(&$value) }; (@value $format:expr $(,$arg:expr)+) => { { let mut builder = $crate::GStringBuilder::default(); if std::fmt::Write::write_fmt(&mut builder, format_args!($format, $($arg),+)).is_err() { return; } builder.into_string() }.as_str().as_bytes() }; } #[doc(alias = "g_log_structured_array")] #[inline] pub fn log_structured_array(log_level: LogLevel, fields: &[LogField<'_>]) { unsafe { ffi::g_log_structured_array( log_level.into_glib(), fields.as_ptr() as *const ffi::GLogField, fields.len(), ) } } #[doc(alias = "g_log_variant")] #[inline] pub fn log_variant(log_domain: Option<&str>, log_level: LogLevel, fields: &crate::Variant) { unsafe { ffi::g_log_variant( log_domain.to_glib_none().0, log_level.into_glib(), fields.to_glib_none().0, ); } } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] #[doc(alias = "g_log_writer_supports_color")] #[inline] pub fn log_writer_supports_color(output_fd: T) -> bool { unsafe { from_glib(ffi::g_log_writer_supports_color(output_fd.as_raw_fd())) } } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] #[doc(alias = "g_log_writer_is_journald")] #[inline] pub fn log_writer_is_journald(output_fd: T) -> bool { unsafe { from_glib(ffi::g_log_writer_is_journald(output_fd.as_raw_fd())) } } #[doc(alias = "g_log_writer_format_fields")] #[inline] pub fn log_writer_format_fields( log_level: LogLevel, fields: &[LogField<'_>], use_color: bool, ) -> GString { unsafe { from_glib_full(ffi::g_log_writer_format_fields( log_level.into_glib(), fields.as_ptr() as *const ffi::GLogField, fields.len(), use_color.into_glib(), )) } } #[doc(alias = "g_log_writer_journald")] #[inline] pub fn log_writer_journald(log_level: LogLevel, fields: &[LogField<'_>]) -> LogWriterOutput { unsafe { from_glib(ffi::g_log_writer_journald( log_level.into_glib(), fields.as_ptr() as *const ffi::GLogField, fields.len(), std::ptr::null_mut(), )) } } #[doc(alias = "g_log_writer_standard_streams")] #[inline] pub fn log_writer_standard_streams( log_level: LogLevel, fields: &[LogField<'_>], ) -> LogWriterOutput { unsafe { from_glib(ffi::g_log_writer_standard_streams( log_level.into_glib(), fields.as_ptr() as *const ffi::GLogField, fields.len(), std::ptr::null_mut(), )) } } #[doc(alias = "g_log_writer_default")] #[inline] pub fn log_writer_default(log_level: LogLevel, fields: &[LogField<'_>]) -> LogWriterOutput { unsafe { from_glib(ffi::g_log_writer_default( log_level.into_glib(), fields.as_ptr() as *const ffi::GLogField, fields.len(), std::ptr::null_mut(), )) } } // rustdoc-stripper-ignore-next /// Sets whether GLib log functions output to stderr or stdout. /// /// By default, log messages of level [`LogLevel::Info`] and [`LogLevel::Debug`] are sent to stdout, /// and other log messages are sent to stderr. Passing `true` will send all messages to stderr. /// /// # Safety /// /// This function sets global state and is not thread-aware, as such it should be called before any /// threads may try to use GLib logging. #[cfg(feature = "v2_68")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_68")))] #[doc(alias = "g_log_writer_default_set_use_stderr")] #[inline] pub unsafe fn log_writer_default_set_use_stderr(use_stderr: bool) { ffi::g_log_writer_default_set_use_stderr(use_stderr.into_glib()); } #[cfg(feature = "v2_68")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_68")))] #[doc(alias = "g_log_writer_default_would_drop")] #[inline] pub fn log_writer_default_would_drop(log_level: LogLevel, log_domain: Option<&str>) -> bool { unsafe { from_glib(ffi::g_log_writer_default_would_drop( log_level.into_glib(), log_domain.to_glib_none().0, )) } } glib-0.20.9/src/main_context.rs000064400000000000000000000225331046102023000144630ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::mem; use crate::ffi::{self, gboolean, gpointer}; use crate::{source::Priority, translate::*, MainContext, Source, SourceId}; impl MainContext { #[doc(alias = "g_main_context_prepare")] pub fn prepare(&self) -> (bool, i32) { unsafe { let mut priority = mem::MaybeUninit::uninit(); let res = from_glib(ffi::g_main_context_prepare( self.to_glib_none().0, priority.as_mut_ptr(), )); let priority = priority.assume_init(); (res, priority) } } #[doc(alias = "g_main_context_find_source_by_id")] pub fn find_source_by_id(&self, source_id: &SourceId) -> Option { unsafe { from_glib_none(ffi::g_main_context_find_source_by_id( self.to_glib_none().0, source_id.as_raw(), )) } } // rustdoc-stripper-ignore-next /// Invokes `func` on the main context. /// /// If the current thread is the owner of the main context or the main context currently has no /// owner then `func` will be called directly from inside this function. If this behaviour is /// not desired and `func` should always be called asynchronously then use [`MainContext::spawn`] /// [`glib::idle_add`](crate::idle_add) instead. #[doc(alias = "g_main_context_invoke")] pub fn invoke(&self, func: F) where F: FnOnce() + Send + 'static, { self.invoke_with_priority(crate::Priority::DEFAULT_IDLE, func); } // rustdoc-stripper-ignore-next /// Invokes `func` on the main context with the given priority. /// /// If the current thread is the owner of the main context or the main context currently has no /// owner then `func` will be called directly from inside this function. If this behaviour is /// not desired and `func` should always be called asynchronously then use [`MainContext::spawn`] /// [`glib::idle_add`](crate::idle_add) instead. #[doc(alias = "g_main_context_invoke_full")] pub fn invoke_with_priority(&self, priority: Priority, func: F) where F: FnOnce() + Send + 'static, { unsafe { self.invoke_unsafe(priority, func); } } // rustdoc-stripper-ignore-next /// 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. /// /// Note that this effectively means that `func` is called directly from inside this function /// or otherwise panics immediately. If this behaviour is not desired and `func` should always /// be called asynchronously then use [`MainContext::spawn_local`] /// [`glib::idle_add_local`](crate::idle_add_local) instead. pub fn invoke_local(&self, func: F) where F: FnOnce() + 'static, { self.invoke_local_with_priority(crate::Priority::DEFAULT_IDLE, func); } // rustdoc-stripper-ignore-next /// 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. /// /// Note that this effectively means that `func` is called directly from inside this function /// or otherwise panics immediately. If this behaviour is not desired and `func` should always /// be called asynchronously then use [`MainContext::spawn_local`] /// [`glib::idle_add_local`](crate::idle_add_local) instead. #[allow(clippy::if_same_then_else)] pub fn invoke_local_with_priority(&self, _priority: Priority, func: F) where F: FnOnce() + 'static, { // Checks from `g_main_context_invoke_full()` // FIXME: Combine the first two cases somehow if self.is_owner() { func(); } else if let Ok(_acquire) = self.acquire() { func(); } else { panic!("Must be called from a thread that owns the main context"); } } unsafe fn invoke_unsafe(&self, priority: Priority, func: F) where F: FnOnce() + 'static, { unsafe extern "C" fn trampoline(func: gpointer) -> gboolean { let func: &mut Option = &mut *(func as *mut Option); let func = func .take() .expect("MainContext::invoke() closure called multiple times"); func(); ffi::G_SOURCE_REMOVE } unsafe extern "C" fn destroy_closure(ptr: gpointer) { let _ = Box::>::from_raw(ptr as *mut _); } let func = Box::into_raw(Box::new(Some(func))); ffi::g_main_context_invoke_full( self.to_glib_none().0, priority.into_glib(), Some(trampoline::), func as gpointer, Some(destroy_closure::), ) } // rustdoc-stripper-ignore-next /// Call closure with the main context configured as the thread default one. /// /// The thread default main context is changed in a panic-safe manner before calling `func` and /// released again afterwards regardless of whether closure panicked or not. /// /// This will fail if the main context is owned already by another thread. #[doc(alias = "g_main_context_push_thread_default")] pub fn with_thread_default R + Sized>( &self, func: F, ) -> Result { let _acquire = self.acquire()?; let _thread_default = ThreadDefaultContext::new(self); Ok(func()) } // rustdoc-stripper-ignore-next /// Acquire ownership of the main context. /// /// Ownership will automatically be released again once the returned acquire guard is dropped. /// /// This will fail if the main context is owned already by another thread. #[doc(alias = "g_main_context_acquire")] pub fn acquire(&self) -> Result { unsafe { let ret: bool = from_glib(ffi::g_main_context_acquire(self.to_glib_none().0)); if ret { Ok(MainContextAcquireGuard(self)) } else { Err(bool_error!("Failed to acquire ownership of main context, already acquired by another thread")) } } } } #[must_use = "if unused the main context will be released immediately"] pub struct MainContextAcquireGuard<'a>(&'a MainContext); impl Drop for MainContextAcquireGuard<'_> { #[doc(alias = "g_main_context_release")] #[inline] fn drop(&mut self) { unsafe { ffi::g_main_context_release(self.0.to_glib_none().0); } } } struct ThreadDefaultContext<'a>(&'a MainContext); impl ThreadDefaultContext<'_> { fn new(ctx: &MainContext) -> ThreadDefaultContext { unsafe { ffi::g_main_context_push_thread_default(ctx.to_glib_none().0); } ThreadDefaultContext(ctx) } } impl Drop for ThreadDefaultContext<'_> { #[inline] fn drop(&mut self) { unsafe { ffi::g_main_context_pop_thread_default(self.0.to_glib_none().0); } } } #[cfg(test)] mod tests { use std::{panic, ptr, thread}; use super::*; #[test] fn test_invoke() { let c = MainContext::new(); let l = crate::MainLoop::new(Some(&c), false); let l_clone = l.clone(); let join_handle = thread::spawn(move || { c.invoke(move || l_clone.quit()); }); l.run(); join_handle.join().unwrap(); } fn is_same_context(a: &MainContext, b: &MainContext) -> bool { ptr::eq(a.to_glib_none().0, b.to_glib_none().0) } #[test] fn test_with_thread_default() { let a = MainContext::new(); let b = MainContext::new(); assert!(!is_same_context(&a, &b)); a.with_thread_default(|| { let t = MainContext::thread_default().unwrap(); assert!(is_same_context(&a, &t)); b.with_thread_default(|| { let t = MainContext::thread_default().unwrap(); assert!(is_same_context(&b, &t)); }) .unwrap(); let t = MainContext::thread_default().unwrap(); assert!(is_same_context(&a, &t)); }) .unwrap(); } #[test] fn test_with_thread_default_is_panic_safe() { let a = MainContext::new(); let b = MainContext::new(); assert!(!is_same_context(&a, &b)); a.with_thread_default(|| { let t = MainContext::thread_default().unwrap(); assert!(is_same_context(&a, &t)); let result = panic::catch_unwind(|| { b.with_thread_default(|| { panic!(); }) .unwrap(); }); assert!(result.is_err()); let t = MainContext::thread_default().unwrap(); assert!(is_same_context(&a, &t)); }) .unwrap(); } } glib-0.20.9/src/main_context_futures.rs000064400000000000000000000665371046102023000162540ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ any::Any, cell::Cell, fmt, marker::PhantomData, mem, num::NonZeroU32, panic, pin::Pin, ptr, thread, }; use futures_channel::oneshot; use futures_core::{ future::Future, task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, }; use futures_task::{FutureObj, LocalFutureObj, LocalSpawn, Spawn, SpawnError}; use futures_util::FutureExt; use crate::{ ffi, thread_guard::ThreadGuard, translate::*, MainContext, MainLoop, Priority, Source, SourceId, }; // Wrapper around Send Futures and non-Send Futures that will panic // if the non-Send Future is polled/dropped from a different thread // than where this was created. enum FutureWrapper { Send(FutureObj<'static, Box>), NonSend(ThreadGuard>>), } unsafe impl Send for FutureWrapper {} unsafe impl Sync for FutureWrapper {} impl Future for FutureWrapper { type Output = Box; fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { match self.get_mut() { FutureWrapper::Send(fut) => { Pin::new(fut).poll(ctx).map(|b| b as Box) } FutureWrapper::NonSend(fut) => Pin::new(fut.get_mut()).poll(ctx), } } } // The TaskSource and WakerSource are split up as the TaskSource // must only be finalized on the thread that owns the main context, // but the WakerSource is passed around to arbitrary threads for // being able to wake up the TaskSource. // // The WakerSource is set up as a child source of the TaskSource, i.e. // whenever it is ready also the TaskSource is ready. #[repr(C)] struct TaskSource { source: ffi::GSource, future: FutureWrapper, waker: Waker, return_tx: Option>>>, } #[repr(C)] struct WakerSource { source: ffi::GSource, } impl TaskSource { unsafe extern "C" fn dispatch( source: *mut ffi::GSource, callback: ffi::GSourceFunc, _user_data: ffi::gpointer, ) -> ffi::gboolean { let source = &mut *(source as *mut Self); debug_assert!(callback.is_none()); // Poll the TaskSource and ensure we're never called again if the // contained Future resolved now. if let Poll::Ready(()) = source.poll() { ffi::G_SOURCE_REMOVE } else { ffi::G_SOURCE_CONTINUE } } unsafe extern "C" fn finalize(source: *mut ffi::GSource) { let source = source as *mut Self; // This will panic if the future was a local future and is dropped from a different thread // than where it was created so try to drop it from the main context if we're on another // thread and the main context still exists. // // This can only really happen if the `Source` was manually retrieve from the context, but // better safe than sorry. match (*source).future { FutureWrapper::Send(_) => { ptr::drop_in_place(&mut (*source).future); } FutureWrapper::NonSend(ref mut future) if future.is_owner() => { ptr::drop_in_place(&mut (*source).future); } FutureWrapper::NonSend(ref mut future) => { let context = ffi::g_source_get_context(source as *mut ffi::GSource); if !context.is_null() { let future = ptr::read(future); let context = MainContext::from_glib_none(context); context.invoke(move || { drop(future); }); } else { // This will panic ptr::drop_in_place(&mut (*source).future); } } } ptr::drop_in_place(&mut (*source).return_tx); // Drop the waker to unref the underlying GSource ptr::drop_in_place(&mut (*source).waker); } } impl WakerSource { unsafe fn clone_raw(waker: *const ()) -> RawWaker { static VTABLE: RawWakerVTable = RawWakerVTable::new( WakerSource::clone_raw, WakerSource::wake_raw, WakerSource::wake_by_ref_raw, WakerSource::drop_raw, ); let waker = waker as *const ffi::GSource; ffi::g_source_ref(mut_override(waker)); RawWaker::new(waker as *const (), &VTABLE) } unsafe fn wake_raw(waker: *const ()) { Self::wake_by_ref_raw(waker); Self::drop_raw(waker); } unsafe fn wake_by_ref_raw(waker: *const ()) { let waker = waker as *const ffi::GSource; ffi::g_source_set_ready_time(mut_override(waker), 0); } unsafe fn drop_raw(waker: *const ()) { let waker = waker as *const ffi::GSource; ffi::g_source_unref(mut_override(waker)); } unsafe extern "C" fn dispatch( source: *mut ffi::GSource, _callback: ffi::GSourceFunc, _user_data: ffi::gpointer, ) -> ffi::gboolean { // Set ready-time to -1 so that we're not called again before // being woken up another time. ffi::g_source_set_ready_time(mut_override(source), -1); ffi::G_SOURCE_CONTINUE } } unsafe impl Send for TaskSource {} unsafe impl Sync for TaskSource {} unsafe impl Send for WakerSource {} unsafe impl Sync for WakerSource {} impl TaskSource { #[allow(clippy::new_ret_no_self)] // checker-ignore-item fn new( priority: Priority, future: FutureWrapper, return_tx: Option>>>, ) -> Source { unsafe { static TASK_SOURCE_FUNCS: ffi::GSourceFuncs = ffi::GSourceFuncs { check: None, prepare: None, dispatch: Some(TaskSource::dispatch), finalize: Some(TaskSource::finalize), closure_callback: None, closure_marshal: None, }; static WAKER_SOURCE_FUNCS: ffi::GSourceFuncs = ffi::GSourceFuncs { check: None, prepare: None, dispatch: Some(WakerSource::dispatch), finalize: None, closure_callback: None, closure_marshal: None, }; let source = ffi::g_source_new( mut_override(&TASK_SOURCE_FUNCS), mem::size_of::() as u32, ); let waker_source = ffi::g_source_new( mut_override(&WAKER_SOURCE_FUNCS), mem::size_of::() as u32, ); ffi::g_source_set_priority(source, priority.into_glib()); ffi::g_source_add_child_source(source, waker_source); { let source = &mut *(source as *mut Self); ptr::write(&mut source.future, future); ptr::write(&mut source.return_tx, return_tx); // This creates a new reference to the waker source. let waker = Waker::from_raw(WakerSource::clone_raw(waker_source as *const ())); ptr::write(&mut source.waker, waker); } // Set ready time to 0 so that the source is immediately dispatched // for doing the initial polling. This will then either resolve the // future or register the waker wherever necessary. ffi::g_source_set_ready_time(waker_source, 0); // Unref the waker source, a strong reference to it is stored inside // the task source directly and inside the task source as child source. ffi::g_source_unref(waker_source); from_glib_full(source) } } fn poll(&mut self) -> Poll<()> { let source = &self.source as *const _; let executor: Borrowed = unsafe { from_glib_borrow(ffi::g_source_get_context(mut_override(source))) }; assert!( executor.is_owner(), "Polling futures only allowed if the thread is owning the MainContext" ); executor .with_thread_default(|| { let _enter = futures_executor::enter().unwrap(); let mut context = Context::from_waker(&self.waker); // This will panic if the future was a local future and is called from // a different thread than where it was created. if let Some(tx) = self.return_tx.take() { let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { Pin::new(&mut self.future).poll(&mut context) })); match res { Ok(Poll::Ready(res)) => { let _ = tx.send(Ok(res)); Poll::Ready(()) } Ok(Poll::Pending) => { self.return_tx.replace(tx); Poll::Pending } Err(e) => { let _ = tx.send(Err(e)); Poll::Ready(()) } } } else { Pin::new(&mut self.future).poll(&mut context).map(|_| ()) } }) .expect("current thread is not owner of the main context") } } // rustdoc-stripper-ignore-next /// A handle to a task running on a [`MainContext`]. /// /// Like [`std::thread::JoinHandle`] for a task rather than a thread. The return value from the /// task can be retrieved by awaiting on this object. Dropping the handle "detaches" the task, /// allowing it to complete but discarding the return value. #[derive(Debug)] pub struct JoinHandle { rx: oneshot::Receiver>>, source: Source, id: Cell>, phantom: PhantomData>>, } impl JoinHandle { #[inline] fn new( ctx: &MainContext, source: Source, rx: oneshot::Receiver>>, ) -> Self { let id = source.attach(Some(ctx)); let id = Cell::new(Some(unsafe { NonZeroU32::new_unchecked(id.as_raw()) })); Self { rx, source, id, phantom: PhantomData, } } // rustdoc-stripper-ignore-next /// Returns the internal source ID. /// /// Returns `None` if the handle was aborted already. #[inline] pub fn as_raw_source_id(&self) -> Option { self.id.get().map(|i| i.get()) } // rustdoc-stripper-ignore-next /// Aborts the task associated with the handle. #[inline] pub fn abort(&self) { self.source.destroy(); self.id.replace(None); } // rustdoc-stripper-ignore-next /// Returns the [`Source`] associated with this handle. #[inline] pub fn source(&self) -> &Source { &self.source } // rustdoc-stripper-ignore-next /// Safely converts the handle into a [`SourceId`]. /// /// Can be used to discard the return value while still retaining the ability to abort the /// underlying task. Returns `Err(self)` if the handle was aborted already. pub fn into_source_id(self) -> Result { if let Some(id) = self.id.take() { Ok(unsafe { SourceId::from_glib(id.get()) }) } else { Err(self) } } } impl Future for JoinHandle { type Output = Result; #[inline] fn poll( mut self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>, ) -> std::task::Poll { std::pin::Pin::new(&mut self.rx).poll(cx).map(|r| match r { Err(_) => Err(JoinErrorInner::Cancelled.into()), Ok(Err(e)) => Err(JoinErrorInner::Panic(e).into()), Ok(Ok(r)) => Ok(*r.downcast().unwrap()), }) } } impl futures_core::FusedFuture for JoinHandle { #[inline] fn is_terminated(&self) -> bool { self.rx.is_terminated() } } // Safety: We can't rely on the auto implementation because we are retrieving // the result as a `Box` from the [`Source`]. We need to // rely on type erasure here, so we have to manually assert the Send bound too. unsafe impl Send for JoinHandle {} // rustdoc-stripper-ignore-next /// Variant of [`JoinHandle`] that is returned from [`MainContext::spawn_from_within`]. #[derive(Debug)] pub struct SpawnWithinJoinHandle { rx: Option>>, join_handle: Option>, } impl SpawnWithinJoinHandle { // rustdoc-stripper-ignore-next /// Waits until the task is spawned and returns the [`JoinHandle`]. pub async fn into_inner(self) -> Result, JoinError> { if let Some(join_handle) = self.join_handle { return Ok(join_handle); } if let Some(rx) = self.rx { match rx.await { Ok(join_handle) => return Ok(join_handle), Err(_) => return Err(JoinErrorInner::Cancelled.into()), } } Err(JoinErrorInner::Cancelled.into()) } } impl Future for SpawnWithinJoinHandle { type Output = Result; #[inline] fn poll( mut self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>, ) -> std::task::Poll { if let Some(ref mut rx) = self.rx { match std::pin::Pin::new(rx).poll(cx) { std::task::Poll::Pending => return std::task::Poll::Pending, std::task::Poll::Ready(Err(_)) => { self.rx = None; return std::task::Poll::Ready(Err(JoinErrorInner::Cancelled.into())); } std::task::Poll::Ready(Ok(join_handle)) => { self.rx = None; self.join_handle = Some(join_handle); } } } if let Some(ref mut join_handle) = self.join_handle { match std::pin::Pin::new(join_handle).poll(cx) { std::task::Poll::Pending => return std::task::Poll::Pending, std::task::Poll::Ready(Err(e)) => { self.join_handle = None; return std::task::Poll::Ready(Err(e)); } std::task::Poll::Ready(Ok(r)) => { self.join_handle = None; return std::task::Poll::Ready(Ok(r)); } } } std::task::Poll::Ready(Err(JoinErrorInner::Cancelled.into())) } } impl futures_core::FusedFuture for SpawnWithinJoinHandle { #[inline] fn is_terminated(&self) -> bool { if let Some(ref rx) = self.rx { rx.is_terminated() } else if let Some(ref join_handle) = self.join_handle { join_handle.is_terminated() } else { true } } } // rustdoc-stripper-ignore-next /// Task failure from awaiting a [`JoinHandle`]. #[derive(Debug)] pub struct JoinError(JoinErrorInner); impl JoinError { // rustdoc-stripper-ignore-next /// Returns `true` if the handle was cancelled. #[inline] pub fn is_cancelled(&self) -> bool { matches!(self.0, JoinErrorInner::Cancelled) } // rustdoc-stripper-ignore-next /// Returns `true` if the task terminated with a panic. #[inline] pub fn is_panic(&self) -> bool { matches!(self.0, JoinErrorInner::Panic(_)) } // rustdoc-stripper-ignore-next /// Converts the error into a panic result. /// /// # Panics /// /// Panics if the error is not a panic error. Use [`is_panic`](Self::is_panic) to check first /// if the error represents a panic. #[inline] pub fn into_panic(self) -> Box { self.try_into_panic() .expect("`JoinError` is not a panic error") } // rustdoc-stripper-ignore-next /// Attempts to convert the error into a panic result. /// /// Returns `Err(self)` if the error is not a panic result. #[inline] pub fn try_into_panic(self) -> Result, Self> { match self.0 { JoinErrorInner::Panic(e) => Ok(e), e => Err(Self(e)), } } } impl std::error::Error for JoinError {} impl std::fmt::Display for JoinError { #[inline] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) } } #[derive(Debug)] enum JoinErrorInner { Cancelled, Panic(Box), } impl From for JoinError { #[inline] fn from(e: JoinErrorInner) -> Self { Self(e) } } impl std::error::Error for JoinErrorInner {} impl fmt::Display for JoinErrorInner { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { Self::Cancelled => fmt.write_str("task cancelled"), Self::Panic(_) => fmt.write_str("task panicked"), } } } impl MainContext { // rustdoc-stripper-ignore-next /// 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, ) -> JoinHandle { self.spawn_with_priority(crate::Priority::default(), f) } // rustdoc-stripper-ignore-next /// 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 /// `with_thread_default` or `acquire` on the main context. pub fn spawn_local + 'static>(&self, f: F) -> JoinHandle { self.spawn_local_with_priority(crate::Priority::default(), f) } // rustdoc-stripper-ignore-next /// 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, ) -> JoinHandle { let f = FutureObj::new(Box::new(async move { Box::new(f.await) as Box })); let (tx, rx) = oneshot::channel(); let source = TaskSource::new(priority, FutureWrapper::Send(f), Some(tx)); JoinHandle::new(self, source, rx) } // rustdoc-stripper-ignore-next /// 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 /// `with_thread_default` or `acquire` on the main context. pub fn spawn_local_with_priority + 'static>( &self, priority: Priority, f: F, ) -> JoinHandle { let _acquire = self .acquire() .expect("Spawning local futures only allowed on the thread owning the MainContext"); let f = LocalFutureObj::new(Box::new(async move { Box::new(f.await) as Box })); let (tx, rx) = oneshot::channel(); let source = TaskSource::new( priority, FutureWrapper::NonSend(ThreadGuard::new(f)), Some(tx), ); JoinHandle::new(self, source, rx) } // rustdoc-stripper-ignore-next /// Spawn a new infallible `Future` on the main context from inside the main context. /// /// The given `Future` does not have to be `Send` but the closure to spawn it has to be. /// /// This can be called only from any thread. pub fn spawn_from_within + 'static>( &self, func: impl FnOnce() -> F + Send + 'static, ) -> SpawnWithinJoinHandle { self.spawn_from_within_with_priority(crate::Priority::default(), func) } // rustdoc-stripper-ignore-next /// Spawn a new infallible `Future` on the main context from inside the main context. /// /// The given `Future` does not have to be `Send` but the closure to spawn it has to be. /// /// This can be called only from any thread. pub fn spawn_from_within_with_priority + 'static>( &self, priority: Priority, func: impl FnOnce() -> F + Send + 'static, ) -> SpawnWithinJoinHandle { let ctx = self.clone(); let (tx, rx) = oneshot::channel(); self.invoke_with_priority(priority, move || { let _ = tx.send(ctx.spawn_local(func())); }); SpawnWithinJoinHandle { rx: Some(rx), join_handle: None, } } // rustdoc-stripper-ignore-next /// 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 f = async { res = Some(panic::AssertUnwindSafe(f).catch_unwind().await); l.quit(); }; let f = unsafe { // Super-unsafe: We transmute here to get rid of the 'static lifetime let f = LocalFutureObj::new(Box::new(async move { f.await; Box::new(()) as Box })); let f: LocalFutureObj<'static, Box> = mem::transmute(f); f }; let source = TaskSource::new( crate::Priority::default(), FutureWrapper::NonSend(ThreadGuard::new(f)), None, ); source.attach(Some(self)); l.run(); match res.unwrap() { Ok(v) => v, Err(e) => panic::resume_unwind(e), } } } impl Spawn for MainContext { fn spawn_obj(&self, f: FutureObj<'static, ()>) -> Result<(), SpawnError> { let (tx, _) = oneshot::channel(); let source = TaskSource::new( crate::Priority::default(), FutureWrapper::Send(FutureObj::new(Box::new(async move { f.await; Box::new(()) as Box }))), Some(tx), ); source.attach(Some(self)); Ok(()) } } impl LocalSpawn for MainContext { fn spawn_local_obj(&self, f: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> { let (tx, _) = oneshot::channel(); let source = TaskSource::new( crate::Priority::default(), FutureWrapper::NonSend(ThreadGuard::new(LocalFutureObj::new(Box::new( async move { f.await; Box::new(()) as Box }, )))), Some(tx), ); source.attach(Some(self)); Ok(()) } } #[cfg(test)] mod tests { use std::{sync::mpsc, thread}; use futures_channel::oneshot; use futures_util::future::{FutureExt, TryFutureExt}; use super::*; #[test] fn test_spawn() { let c = MainContext::new(); let l = crate::MainLoop::new(Some(&c), false); let (sender, receiver) = mpsc::channel(); let (o_sender, o_receiver) = oneshot::channel(); let l_clone = l.clone(); c.spawn( o_receiver .and_then(move |()| { sender.send(()).unwrap(); l_clone.quit(); futures_util::future::ok(()) }) .then(|res| { assert!(res.is_ok()); futures_util::future::ready(()) }), ); let join_handle = thread::spawn(move || { l.run(); }); o_sender.send(()).unwrap(); receiver.recv().unwrap(); join_handle.join().unwrap(); } #[test] fn test_spawn_local() { let c = MainContext::new(); let l = crate::MainLoop::new(Some(&c), false); c.with_thread_default(|| { let l_clone = l.clone(); c.spawn_local(futures_util::future::lazy(move |_ctx| { l_clone.quit(); })); l.run(); }) .unwrap(); } #[test] fn test_spawn_from_within() { let c = MainContext::new(); let l = crate::MainLoop::new(Some(&c), false); let join_handle = std::thread::spawn({ let l_clone = l.clone(); move || { c.spawn_from_within(move || async move { let rc = std::rc::Rc::new(123); futures_util::future::ready(()).await; assert_eq!(std::rc::Rc::strong_count(&rc), 1); l_clone.quit(); }); } }); l.run(); join_handle.join().unwrap(); } #[test] fn test_block_on() { let c = MainContext::new(); let mut v = None; { let v = &mut v; let future = futures_util::future::lazy(|_ctx| { *v = Some(123); Ok::(123) }); let res = c.block_on(future); assert_eq!(res, Ok(123)); } assert_eq!(v, Some(123)); } #[test] fn test_spawn_return() { let c = MainContext::new(); c.block_on(async { let val = 1; let ret = c .spawn(async move { futures_util::future::ready(2).await + val }) .await; assert_eq!(ret.unwrap(), 3); }); } #[test] fn test_spawn_panic() { let c = MainContext::new(); c.block_on(async { let ret = c .spawn(async { panic!("failed"); }) .await; assert_eq!( *ret.unwrap_err().into_panic().downcast::<&str>().unwrap(), "failed" ); }); } #[test] fn test_spawn_abort() { let c = MainContext::new(); let v = std::sync::Arc::new(1); let v_clone = v.clone(); let c_ref = &c; c.block_on(async move { let handle = c_ref.spawn(async move { let _v = v_clone; let test: u128 = std::future::pending().await; println!("{test}"); unreachable!(); }); handle.abort(); }); drop(c); // Make sure the inner future is actually freed. assert_eq!(std::sync::Arc::strong_count(&v), 1); } } glib-0.20.9/src/match_info.rs000064400000000000000000000276651046102023000141150ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::{ffi, prelude::*, translate::*, GStr, Regex}; use std::{marker::PhantomData, mem, ptr}; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] pub struct MatchInfo<'input> { inner: std::ptr::NonNull, _phantom: PhantomData<&'input GStr>, } impl Clone for MatchInfo<'_> { fn clone(&self) -> Self { unsafe { ffi::g_match_info_ref(self.inner.as_ptr()); } Self { inner: self.inner, _phantom: PhantomData, } } } impl Drop for MatchInfo<'_> { fn drop(&mut self) { unsafe { ffi::g_match_info_unref(self.inner.as_ptr()); } } } impl MatchInfo<'_> { #[doc = "Return the inner pointer to the underlying C value."] #[inline] pub fn as_ptr(&self) -> *mut ffi::GMatchInfo { self.inner.as_ptr() } #[doc = "Borrows the underlying C value."] #[inline] pub unsafe fn from_glib_ptr_borrow(ptr: &*mut ffi::GMatchInfo) -> &Self { debug_assert_eq!( std::mem::size_of::(), std::mem::size_of::() ); debug_assert!(!ptr.is_null()); &*(ptr as *const *mut ffi::GMatchInfo as *const Self) } } #[doc(hidden)] impl GlibPtrDefault for MatchInfo<'_> { type GlibType = *mut ffi::GMatchInfo; } #[doc(hidden)] unsafe impl TransparentPtrType for MatchInfo<'_> {} #[doc(hidden)] impl<'a, 'input> ToGlibPtr<'a, *mut ffi::GMatchInfo> for MatchInfo<'input> where 'input: 'a, { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GMatchInfo, Self> { Stash(self.inner.as_ptr(), PhantomData) } #[inline] fn to_glib_full(&self) -> *mut ffi::GMatchInfo { let ptr = self.inner.as_ptr(); unsafe { ffi::g_match_info_ref(ptr); } ptr } } #[doc(hidden)] impl<'a, 'input> ToGlibPtr<'a, *const ffi::GMatchInfo> for MatchInfo<'input> where 'input: 'a, { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GMatchInfo, Self> { Stash(self.inner.as_ptr(), PhantomData) } #[inline] fn to_glib_full(&self) -> *const ffi::GMatchInfo { let ptr = self.inner.as_ptr(); unsafe { ffi::g_match_info_ref(ptr); } ptr } } #[doc(hidden)] impl FromGlibPtrNone<*mut ffi::GMatchInfo> for MatchInfo<'_> { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::GMatchInfo) -> Self { debug_assert!(!ptr.is_null()); unsafe { ffi::g_match_info_ref(ptr); Self { inner: ptr::NonNull::new_unchecked(ptr), _phantom: PhantomData, } } } } #[doc(hidden)] impl FromGlibPtrNone<*const ffi::GMatchInfo> for MatchInfo<'_> { #[inline] unsafe fn from_glib_none(ptr: *const ffi::GMatchInfo) -> Self { Self::from_glib_none(ptr.cast_mut()) } } #[doc(hidden)] impl FromGlibPtrFull<*mut ffi::GMatchInfo> for MatchInfo<'_> { #[inline] unsafe fn from_glib_full(ptr: *mut ffi::GMatchInfo) -> Self { debug_assert!(!ptr.is_null()); unsafe { Self { inner: ptr::NonNull::new_unchecked(ptr), _phantom: PhantomData, } } } } #[doc(hidden)] impl FromGlibPtrBorrow<*mut ffi::GMatchInfo> for MatchInfo<'_> { #[inline] unsafe fn from_glib_borrow(ptr: *mut ffi::GMatchInfo) -> Borrowed { debug_assert!(!ptr.is_null()); unsafe { Borrowed::new(Self { inner: ptr::NonNull::new_unchecked(ptr), _phantom: PhantomData, }) } } } #[doc(hidden)] impl FromGlibPtrBorrow<*const ffi::GMatchInfo> for MatchInfo<'_> { #[inline] unsafe fn from_glib_borrow(ptr: *const ffi::GMatchInfo) -> Borrowed { from_glib_borrow::<_, Self>(ptr.cast_mut()) } } #[doc(hidden)] impl IntoGlibPtr<*mut ffi::GMatchInfo> for MatchInfo<'_> { #[inline] unsafe fn into_glib_ptr(self) -> *mut ffi::GMatchInfo { let s = std::mem::ManuallyDrop::new(self); ToGlibPtr::<*const ffi::GMatchInfo>::to_glib_none(&*s).0 as *mut _ } } #[doc(hidden)] impl IntoGlibPtr<*const ffi::GMatchInfo> for MatchInfo<'_> { #[inline] unsafe fn into_glib_ptr(self) -> *const ffi::GMatchInfo { let s = std::mem::ManuallyDrop::new(self); ToGlibPtr::<*const ffi::GMatchInfo>::to_glib_none(&*s).0 as *const _ } } impl StaticType for MatchInfo<'_> { #[inline] fn static_type() -> crate::types::Type { unsafe { from_glib(ffi::g_match_info_get_type()) } } } #[doc(hidden)] impl ValueType for MatchInfo<'static> { type Type = Self; } #[doc(hidden)] impl crate::value::ValueTypeOptional for MatchInfo<'static> {} unsafe impl<'a, 'input: 'a> crate::value::FromValue<'a> for MatchInfo<'input> { type Checker = crate::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a crate::Value) -> Self { let ptr = crate::gobject_ffi::g_value_dup_boxed( crate::translate::ToGlibPtr::to_glib_none(value).0, ); debug_assert!(!ptr.is_null()); >::from_glib_full( ptr as *mut ffi::GMatchInfo, ) } } #[doc(hidden)] unsafe impl<'a, 'input: 'a> crate::value::FromValue<'a> for &'a MatchInfo<'input> { type Checker = crate::value::GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a crate::Value) -> Self { let value = &*(value as *const crate::Value as *const crate::gobject_ffi::GValue); >::from_glib_ptr_borrow( &*(&value.data[0].v_pointer as *const crate::ffi::gpointer as *const *mut ffi::GMatchInfo), ) } } impl ToValue for MatchInfo<'static> { #[inline] fn to_value(&self) -> crate::Value { unsafe { let mut value = crate::Value::from_type_unchecked(::static_type()); crate::gobject_ffi::g_value_take_boxed( crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, crate::translate::ToGlibPtr::<*mut ffi::GMatchInfo>::to_glib_full(self) as *mut _, ); value } } #[inline] fn value_type(&self) -> crate::Type { ::static_type() } } impl From> for crate::Value { #[inline] fn from(s: MatchInfo<'static>) -> Self { unsafe { let mut value = crate::Value::from_type_unchecked( as StaticType>::static_type(), ); crate::gobject_ffi::g_value_take_boxed( crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, crate::translate::IntoGlibPtr::<*mut ffi::GMatchInfo>::into_glib_ptr(s) as *mut _, ); value } } } #[doc(hidden)] impl crate::value::ToValueOptional for MatchInfo<'static> { #[inline] fn to_value_optional(s: Option<&Self>) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { crate::gobject_ffi::g_value_take_boxed( crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, crate::translate::ToGlibPtr::<*mut ffi::GMatchInfo>::to_glib_full(&s) as *mut _, ); } value } } impl HasParamSpec for MatchInfo<'static> { type ParamSpec = crate::ParamSpecBoxed; type SetValue = Self; type BuilderFn = fn(&str) -> crate::ParamSpecBoxedBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl<'input> MatchInfo<'input> { #[doc(alias = "g_match_info_fetch")] pub fn fetch(&self, match_num: i32) -> Option { unsafe { from_glib_full(ffi::g_match_info_fetch(self.to_glib_none().0, match_num)) } } #[doc(alias = "g_match_info_fetch_all")] pub fn fetch_all(&self) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::g_match_info_fetch_all(self.to_glib_none().0)) } } #[doc(alias = "g_match_info_fetch_pos")] pub fn fetch_pos(&self, match_num: i32) -> Option<(i32, i32)> { unsafe { let mut start_pos = std::mem::MaybeUninit::uninit(); let mut end_pos = std::mem::MaybeUninit::uninit(); let ret = from_glib(ffi::g_match_info_fetch_pos( self.to_glib_none().0, match_num, start_pos.as_mut_ptr(), end_pos.as_mut_ptr(), )); if ret { Some((start_pos.assume_init(), end_pos.assume_init())) } else { None } } } #[doc(alias = "g_match_info_get_match_count")] #[doc(alias = "get_match_count")] pub fn match_count(&self) -> i32 { unsafe { ffi::g_match_info_get_match_count(self.to_glib_none().0) } } #[doc(alias = "g_match_info_get_regex")] #[doc(alias = "get_regex")] pub fn regex(&self) -> Regex { unsafe { from_glib_none(ffi::g_match_info_get_regex(self.to_glib_none().0)) } } #[doc(alias = "g_match_info_get_string")] #[doc(alias = "get_string")] pub fn string(&self) -> &'input crate::GStr { unsafe { from_glib_none(ffi::g_match_info_get_string(self.to_glib_none().0)) } } #[doc(alias = "g_match_info_is_partial_match")] pub fn is_partial_match(&self) -> bool { unsafe { from_glib(ffi::g_match_info_is_partial_match(self.to_glib_none().0)) } } #[doc(alias = "g_match_info_matches")] pub fn matches(&self) -> bool { unsafe { from_glib(ffi::g_match_info_matches(self.to_glib_none().0)) } } #[doc(alias = "g_match_info_next")] pub fn next(&self) -> Result { unsafe { let mut error = std::ptr::null_mut(); let is_ok = ffi::g_match_info_next(self.to_glib_none().0, &mut error); if !error.is_null() { Err(from_glib_full(error)) } else { Ok(from_glib(is_ok)) } } } #[doc(alias = "g_match_info_expand_references")] pub fn expand_references( &self, string_to_expand: impl IntoGStr, ) -> Result, crate::Error> { string_to_expand.run_with_gstr(|string_to_expand| unsafe { let mut error = ptr::null_mut(); let ret = ffi::g_match_info_expand_references( self.to_glib_none().0, string_to_expand.to_glib_none().0, &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } }) } #[doc(alias = "g_match_info_fetch_named")] pub fn fetch_named(&self, name: impl IntoGStr) -> Option { name.run_with_gstr(|name| unsafe { from_glib_full(ffi::g_match_info_fetch_named( self.to_glib_none().0, name.to_glib_none().0, )) }) } #[doc(alias = "g_match_info_fetch_named_pos")] pub fn fetch_named_pos(&self, name: impl IntoGStr) -> Option<(i32, i32)> { name.run_with_gstr(|name| unsafe { let mut start_pos = mem::MaybeUninit::uninit(); let mut end_pos = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::g_match_info_fetch_named_pos( self.to_glib_none().0, name.to_glib_none().0, start_pos.as_mut_ptr(), end_pos.as_mut_ptr(), )); if ret { Some((start_pos.assume_init(), end_pos.assume_init())) } else { None } }) } } glib-0.20.9/src/object.rs000064400000000000000000005006051046102023000132420ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! `IMPL` Object wrapper implementation and `Object` binding. use std::{cmp, fmt, hash, marker::PhantomData, mem, mem::ManuallyDrop, ops, pin::Pin, ptr}; use crate::{ closure::TryFromClosureReturnValue, ffi, gobject_ffi, prelude::*, quark::Quark, subclass::{prelude::*, SignalId, SignalQuery}, thread_guard::thread_id, translate::*, value::FromValue, Closure, PtrSlice, RustClosure, SignalHandlerId, Type, Value, }; // rustdoc-stripper-ignore-next /// Implemented by types representing `glib::Object` and subclasses of it. pub unsafe trait ObjectType: UnsafeFrom + Into + StaticType + fmt::Debug + Clone + PartialEq + Eq + PartialOrd + Ord + hash::Hash + crate::value::ValueType + ToValue + crate::value::ToValueOptional + crate::value::FromValueOptional<'static> + for<'a> ToGlibPtr<'a, *mut ::GlibType> + IntoGlibPtr<*mut ::GlibType> + 'static { // rustdoc-stripper-ignore-next /// type of the FFI Instance structure. type GlibType: 'static; // rustdoc-stripper-ignore-next /// type of the FFI Class structure. type GlibClassType: 'static; fn as_object_ref(&self) -> &ObjectRef; fn as_ptr(&self) -> *mut Self::GlibType; unsafe fn from_glib_ptr_borrow(ptr: &*mut Self::GlibType) -> &Self; } // rustdoc-stripper-ignore-next /// 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 + Into + AsRef + std::borrow::Borrow { } // rustdoc-stripper-ignore-next /// Upcasting and downcasting support. /// /// Provides conversions up and down the class hierarchy tree. pub trait Cast: ObjectType { // rustdoc-stripper-ignore-next /// 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() } } // rustdoc-stripper-ignore-next /// 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() } } // rustdoc-stripper-ignore-next /// 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 will check at compile-time if `T` is lower down the /// inheritance tree of `Self`, but also check at runtime if downcasting /// is indeed possible. /// /// # Example /// /// ```ignore /// let button = gtk::Button::new(); /// let widget = button.upcast::(); /// assert!(widget.downcast::().is_ok()); /// ``` #[inline] fn downcast(self) -> Result where Self: MayDowncastTo, { if self.is::() { Ok(unsafe { self.unsafe_cast() }) } else { Err(self) } } // rustdoc-stripper-ignore-next /// 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 will check at compile-time if `T` is lower down the /// inheritance tree of `Self`, but also check at runtime if downcasting /// is indeed possible. /// /// # 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: MayDowncastTo, { if self.is::() { Some(unsafe { self.unsafe_cast_ref() }) } else { None } } // rustdoc-stripper-ignore-next /// 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 `upcast` will do many checks at compile-time already. `downcast` will /// perform the same checks at runtime as `dynamic_cast`, but will also ensure some amount of /// compile-time safety. /// /// It is not always known at compile-time, whether a specific object implements an interface or /// not, and checking has 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() }) } } // rustdoc-stripper-ignore-next /// 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 has to be performed at runtime. /// /// Returns `Some(T)` if the object is an instance of `T` and `None` /// otherwise. /// /// # Example /// /// ```ignore /// let button = gtk::Button::new(); /// let widget = button.dynamic_cast_ref::(); /// assert!(widget.is_some()); /// let widget = widget.unwrap(); /// assert!(widget.dynamic_cast_ref::().is_some()); /// ``` #[inline] fn dynamic_cast_ref(&self) -> Option<&T> { if !self.is::() { None } else { // This cast is safe because all our wrapper types have the // same representation except for the name and the phantom data // type. IsA<> is an unsafe trait that must only be implemented // if this is a valid wrapper type Some(unsafe { self.unsafe_cast_ref() }) } } // rustdoc-stripper-ignore-next /// Casts to `T` unconditionally. /// /// # Panics /// /// Panics if compiled with `debug_assertions` and the instance doesn't implement `T`. /// /// # Safety /// /// If not running with `debug_assertions` enabled, the caller is responsible /// for ensuring that the instance implements `T` #[track_caller] #[inline] unsafe fn unsafe_cast(self) -> T { debug_assert!(self.is::()); T::unsafe_from(self.into()) } // rustdoc-stripper-ignore-next /// Casts to `&T` unconditionally. /// /// # Panics /// /// Panics if compiled with `debug_assertions` and the instance doesn't implement `T`. /// /// # Safety /// /// If not running with `debug_assertions` enabled, the caller is responsible /// for ensuring that the instance implements `T` #[track_caller] #[inline] unsafe fn unsafe_cast_ref(&self) -> &T { debug_assert!(self.is::()); // This cast is safe because all our wrapper types have the // same representation except for the name and the phantom data // type. IsA<> is an unsafe trait that must only be implemented // if this is a valid wrapper type &*(self as *const Self as *const T) } } impl Cast for T {} // rustdoc-stripper-ignore-next /// Convenience trait mirroring `Cast`, implemented on `Option` types. /// /// # Warning /// Inevitably this trait will discard information about a downcast failure: /// you don't know if the object was not of the expected type, or if it was `None`. /// If you need to handle the downcast error, use `Cast` over a `glib::Object`. /// /// # Example /// ```ignore /// let widget: Option = list_item.child(); /// /// // Without using `CastNone` /// let label = widget.unwrap().downcast::().unwrap(); /// /// // Using `CastNone` we can avoid the first `unwrap()` call /// let label = widget.and_downcast::().unwrap(); /// ```` pub trait CastNone: Sized { type Inner; fn and_downcast(self) -> Option where Self::Inner: MayDowncastTo; fn and_downcast_ref(&self) -> Option<&T> where Self::Inner: MayDowncastTo; fn and_upcast(self) -> Option where Self::Inner: IsA; fn and_upcast_ref(&self) -> Option<&T> where Self::Inner: IsA; fn and_dynamic_cast(self) -> Result; fn and_dynamic_cast_ref(&self) -> Option<&T>; } impl CastNone for Option { type Inner = I; #[inline] fn and_downcast(self) -> Option where Self::Inner: MayDowncastTo, { self.and_then(|i| i.downcast().ok()) } #[inline] fn and_downcast_ref(&self) -> Option<&T> where Self::Inner: MayDowncastTo, { self.as_ref().and_then(|i| i.downcast_ref()) } #[inline] fn and_upcast(self) -> Option where Self::Inner: IsA, { self.map(|i| i.upcast()) } #[inline] fn and_upcast_ref(&self) -> Option<&T> where Self::Inner: IsA, { self.as_ref().map(|i| i.upcast_ref()) } #[inline] fn and_dynamic_cast(self) -> Result { self.ok_or(None) .and_then(|i| i.dynamic_cast().map_err(|e| Some(e))) } #[inline] fn and_dynamic_cast_ref(&self) -> Option<&T> { self.as_ref().and_then(|i| i.dynamic_cast_ref()) } } // rustdoc-stripper-ignore-next /// Marker trait for the statically known possibility of downcasting from `Self` to `T`. pub trait MayDowncastTo {} impl, Sub: IsA> MayDowncastTo for Super {} // Manual implementation of glib_shared_wrapper! because of special cases #[repr(transparent)] pub struct ObjectRef { inner: ptr::NonNull, } impl Clone for ObjectRef { #[inline] fn clone(&self) -> Self { unsafe { Self { inner: ptr::NonNull::new_unchecked(gobject_ffi::g_object_ref(self.inner.as_ptr())), } } } } impl Drop for ObjectRef { #[inline] fn drop(&mut self) { unsafe { gobject_ffi::g_object_unref(self.inner.as_ptr()); } } } impl fmt::Debug for ObjectRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let type_ = unsafe { let klass = (*self.inner.as_ptr()).g_type_instance.g_class as *const ObjectClass; (*klass).type_() }; f.debug_struct("ObjectRef") .field("inner", &self.inner) .field("type", &type_) .finish() } } impl PartialOrd for ObjectRef { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for ObjectRef { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { self.inner.cmp(&other.inner) } } impl PartialEq for ObjectRef { #[inline] fn eq(&self, other: &Self) -> bool { self.inner == other.inner } } impl Eq for ObjectRef {} impl hash::Hash for ObjectRef { #[inline] fn hash(&self, state: &mut H) where H: hash::Hasher, { self.inner.hash(state) } } #[doc(hidden)] impl GlibPtrDefault for ObjectRef { type GlibType = *mut gobject_ffi::GObject; } #[doc(hidden)] impl<'a> ToGlibPtr<'a, *mut gobject_ffi::GObject> for ObjectRef { type Storage = PhantomData<&'a ObjectRef>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut gobject_ffi::GObject, Self> { Stash(self.inner.as_ptr(), PhantomData) } #[inline] fn to_glib_full(&self) -> *mut gobject_ffi::GObject { unsafe { gobject_ffi::g_object_ref(self.inner.as_ptr()) } } } #[doc(hidden)] impl FromGlibPtrNone<*mut gobject_ffi::GObject> for ObjectRef { #[inline] unsafe fn from_glib_none(ptr: *mut gobject_ffi::GObject) -> Self { debug_assert!(!ptr.is_null()); debug_assert_ne!((*ptr).ref_count, 0); // Attention: This takes ownership of floating references! Self { inner: ptr::NonNull::new_unchecked(gobject_ffi::g_object_ref_sink(ptr)), } } } #[doc(hidden)] impl FromGlibPtrNone<*const gobject_ffi::GObject> for ObjectRef { #[inline] unsafe fn from_glib_none(ptr: *const gobject_ffi::GObject) -> Self { // Attention: This takes ownership of floating references! from_glib_none(ptr as *mut gobject_ffi::GObject) } } #[doc(hidden)] impl FromGlibPtrFull<*mut gobject_ffi::GObject> for ObjectRef { #[inline] unsafe fn from_glib_full(ptr: *mut gobject_ffi::GObject) -> Self { debug_assert!(!ptr.is_null()); debug_assert_ne!((*ptr).ref_count, 0); Self { inner: ptr::NonNull::new_unchecked(ptr), } } } #[doc(hidden)] impl FromGlibPtrBorrow<*mut gobject_ffi::GObject> for ObjectRef { #[inline] unsafe fn from_glib_borrow(ptr: *mut gobject_ffi::GObject) -> Borrowed { debug_assert!(!ptr.is_null()); debug_assert_ne!((*ptr).ref_count, 0); Borrowed::new(Self { inner: ptr::NonNull::new_unchecked(ptr), }) } } #[doc(hidden)] impl FromGlibPtrBorrow<*const gobject_ffi::GObject> for ObjectRef { #[inline] unsafe fn from_glib_borrow(ptr: *const gobject_ffi::GObject) -> Borrowed { from_glib_borrow(ptr as *mut gobject_ffi::GObject) } } #[repr(transparent)] pub struct TypedObjectRef { inner: ObjectRef, imp: PhantomData, parent: PhantomData

, } impl TypedObjectRef { #[inline] pub unsafe fn new(obj: ObjectRef) -> Self { Self { inner: obj, imp: PhantomData, parent: PhantomData, } } #[inline] pub fn into_inner(self) -> ObjectRef { self.inner } } impl Clone for TypedObjectRef { #[inline] fn clone(&self) -> Self { Self { inner: self.inner.clone(), imp: PhantomData, parent: PhantomData, } } } impl ops::Deref for TypedObjectRef { type Target = ObjectRef; #[inline] fn deref(&self) -> &Self::Target { &self.inner } } impl fmt::Debug for TypedObjectRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let type_ = unsafe { let klass = (*self.inner.inner.as_ptr()).g_type_instance.g_class as *const ObjectClass; (*klass).type_() }; f.debug_struct("TypedObjectRef") .field("inner", &self.inner.inner) .field("type", &type_) .finish() } } impl PartialOrd for TypedObjectRef { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for TypedObjectRef { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { self.inner.cmp(&other.inner) } } impl PartialEq for TypedObjectRef { #[inline] fn eq(&self, other: &Self) -> bool { self.inner == other.inner } } impl Eq for TypedObjectRef {} impl hash::Hash for TypedObjectRef { #[inline] fn hash(&self, state: &mut H) where H: hash::Hasher, { self.inner.hash(state) } } unsafe impl Send for TypedObjectRef {} unsafe impl Sync for TypedObjectRef {} // rustdoc-stripper-ignore-next /// ObjectType implementations for Object types. See `wrapper!`. #[macro_export] macro_rules! glib_object_wrapper { (@generic_impl [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $impl_type:ty, $parent_type:ty, $ffi_name:ty, $ffi_class_name:ty, @type_ $get_type_expr:expr) => { $(#[$attr])* #[doc = "\n\nGLib type: GObject with reference counted clone semantics."] #[repr(transparent)] $visibility struct $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? { inner: $crate::object::TypedObjectRef<$impl_type, $parent_type>, phantom: std::marker::PhantomData<($($($generic),+)?)>, } // Always implement Clone, Hash, PartialEq, Eq, PartialOrd, Ord, and Debug for object types. // Due to inheritance and up/downcasting we must implement these by pointer or otherwise they // would potentially give different results for the same object depending on the type we // currently know for it. // Implement them manually rather than generating #[derive] macros since so that when generics // are specified, these traits are not required. impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::clone::Clone for $name $(<$($generic),+>)? { #[doc = "Makes a clone of this shared reference.\n\nThis increments the strong reference count of the object. Dropping the object will decrement it again."] #[inline] fn clone(&self) -> Self { Self { inner: std::clone::Clone::clone(&self.inner), phantom: std::marker::PhantomData, } } } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::hash::Hash for $name $(<$($generic),+>)? { #[doc = "Hashes the memory address of this object."] #[inline] fn hash(&self, state: &mut H) where H: std::hash::Hasher { std::hash::Hash::hash(&self.inner, state); } } impl std::cmp::PartialEq for $name $(<$($generic),+>)? { #[doc = "Equality for two GObjects.\n\nTwo GObjects are equal if their memory addresses are equal."] #[inline] fn eq(&self, other: &OT) -> bool { std::cmp::PartialEq::eq(&*self.inner, $crate::object::ObjectType::as_object_ref(other)) } } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::cmp::Eq for $name $(<$($generic),+>)? {} impl std::cmp::PartialOrd for $name $(<$($generic),+>)? { #[doc = "Partial comparison for two GObjects.\n\nCompares the memory addresses of the provided objects."] #[inline] fn partial_cmp(&self, other: &OT) -> Option { std::cmp::PartialOrd::partial_cmp(&*self.inner, $crate::object::ObjectType::as_object_ref(other)) } } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::cmp::Ord for $name $(<$($generic),+>)? { #[doc = "Comparison for two GObjects.\n\nCompares the memory addresses of the provided objects."] #[inline] fn cmp(&self, other: &Self) -> std::cmp::Ordering { std::cmp::Ord::cmp(&*self.inner, $crate::object::ObjectType::as_object_ref(other)) } } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::fmt::Debug for $name $(<$($generic),+>)? { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.debug_struct(stringify!($name)).field("inner", &self.inner).finish() } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? From<$name $(<$($generic),+>)?> for $crate::object::ObjectRef { #[inline] fn from(s: $name $(<$($generic),+>)?) -> $crate::object::ObjectRef { s.inner.into_inner() } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::UnsafeFrom<$crate::object::ObjectRef> for $name $(<$($generic),+>)? { #[inline] unsafe fn unsafe_from(t: $crate::object::ObjectRef) -> Self { $name { inner: $crate::object::TypedObjectRef::new(t), phantom: std::marker::PhantomData, } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::GlibPtrDefault for $name $(<$($generic),+>)? { type GlibType = *mut $ffi_name; } #[doc(hidden)] unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::TransparentPtrType for $name $(<$($generic),+>)? {} #[doc(hidden)] unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::object::ObjectType for $name $(<$($generic),+>)? { type GlibType = $ffi_name; type GlibClassType = $ffi_class_name; #[inline] fn as_object_ref(&self) -> &$crate::object::ObjectRef { &self.inner } #[inline] fn as_ptr(&self) -> *mut Self::GlibType { unsafe { *(self as *const Self as *const *const $ffi_name) as *mut $ffi_name } } #[inline] unsafe fn from_glib_ptr_borrow(ptr: &*mut Self::GlibType) -> &Self { debug_assert_eq!( std::mem::size_of::(), std::mem::size_of::<$crate::ffi::gpointer>() ); debug_assert!(!ptr.is_null()); debug_assert_ne!((*(*ptr as *const $crate::gobject_ffi::GObject)).ref_count, 0); &*(ptr as *const *mut $ffi_name as *const Self) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? AsRef<$crate::object::ObjectRef> for $name $(<$($generic),+>)? { #[inline] fn as_ref(&self) -> &$crate::object::ObjectRef { &self.inner } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? AsRef for $name $(<$($generic),+>)? { #[inline] fn as_ref(&self) -> &Self { self } } #[doc(hidden)] unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::prelude::IsA for $name $(<$($generic),+>)? { } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::subclass::types::FromObject for $name $(<$($generic),+>)? { type FromObjectType = Self; #[inline] fn from_object(obj: &Self::FromObjectType) -> &Self { obj } } #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibPtr<'a, *const $ffi_name> for $name $(<$($generic),+>)? { type Storage = <$crate::object::ObjectRef as $crate::translate::ToGlibPtr<'a, *mut $crate::gobject_ffi::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.inner); $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.inner) as *const _ } } #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibPtr<'a, *mut $ffi_name> for $name $(<$($generic),+>)? { type Storage = <$crate::object::ObjectRef as $crate::translate::ToGlibPtr<'a, *mut $crate::gobject_ffi::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.inner); $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.inner) as *mut _ } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::IntoGlibPtr<*mut $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn into_glib_ptr(self) -> *mut $ffi_name { let s = std::mem::ManuallyDrop::new(self); $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(&*s).0 as *mut _ } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::IntoGlibPtr<*const $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn into_glib_ptr(self) -> *const $ffi_name { let s = std::mem::ManuallyDrop::new(self); $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(&*s).0 as *const _ } } #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibContainerFromSlice<'a, *mut *mut $ffi_name> for $name $(<$($generic),+>)? { type Storage = (std::marker::PhantomData<&'a [Self]>, Option>); fn to_glib_none_from_slice(t: &'a [Self]) -> (*mut *mut $ffi_name, Self::Storage) { let mut v_ptr = Vec::with_capacity(t.len() + 1); unsafe { let ptr = v_ptr.as_mut_ptr(); std::ptr::copy_nonoverlapping(t.as_ptr() as *mut *mut $ffi_name, ptr, t.len()); std::ptr::write(ptr.add(t.len()), std::ptr::null_mut()); v_ptr.set_len(t.len() + 1); } (v_ptr.as_ptr() as *mut *mut $ffi_name, (std::marker::PhantomData, Some(v_ptr))) } fn to_glib_container_from_slice(t: &'a [Self]) -> (*mut *mut $ffi_name, Self::Storage) { let v_ptr = unsafe { let v_ptr = $crate::ffi::g_malloc(std::mem::size_of::<*mut $ffi_name>() * (t.len() + 1)) as *mut *mut $ffi_name; std::ptr::copy_nonoverlapping(t.as_ptr() as *mut *mut $ffi_name, v_ptr, t.len()); std::ptr::write(v_ptr.add(t.len()), std::ptr::null_mut()); v_ptr }; (v_ptr, (std::marker::PhantomData, None)) } fn to_glib_full_from_slice(t: &[Self]) -> *mut *mut $ffi_name { unsafe { let v_ptr = $crate::ffi::g_malloc(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)); } std::ptr::write(v_ptr.add(t.len()), std::ptr::null_mut()); v_ptr } } } #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibContainerFromSlice<'a, *const *mut $ffi_name> for $name $(<$($generic),+>)? { type Storage = (std::marker::PhantomData<&'a [Self]>, Option>); fn to_glib_none_from_slice(t: &'a [Self]) -> (*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 [Self]) -> (*const *mut $ffi_name, Self::Storage) { // Can't have consumer free a *const pointer unimplemented!() } fn to_glib_full_from_slice(_: &[Self]) -> *const *mut $ffi_name { // Can't have consumer free a *const pointer unimplemented!() } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrNone<*mut $ffi_name> for $name $(<$($generic),+>)? { #[inline] #[allow(clippy::cast_ptr_alignment)] unsafe fn from_glib_none(ptr: *mut $ffi_name) -> Self { debug_assert!(!ptr.is_null()); debug_assert!($crate::types::instance_of::(ptr as *const _)); $name { inner: $crate::object::TypedObjectRef::new($crate::translate::from_glib_none(ptr as *mut _)), phantom: std::marker::PhantomData, } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrNone<*const $ffi_name> for $name $(<$($generic),+>)? { #[inline] #[allow(clippy::cast_ptr_alignment)] unsafe fn from_glib_none(ptr: *const $ffi_name) -> Self { debug_assert!(!ptr.is_null()); debug_assert!($crate::types::instance_of::(ptr as *const _)); $name { inner: $crate::object::TypedObjectRef::new($crate::translate::from_glib_none(ptr as *mut _)), phantom: std::marker::PhantomData, } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrFull<*mut $ffi_name> for $name $(<$($generic),+>)? { #[inline] #[allow(clippy::cast_ptr_alignment)] unsafe fn from_glib_full(ptr: *mut $ffi_name) -> Self { debug_assert!(!ptr.is_null()); debug_assert!($crate::types::instance_of::(ptr as *const _)); $name { inner: $crate::object::TypedObjectRef::new($crate::translate::from_glib_full(ptr as *mut _)), phantom: std::marker::PhantomData, } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrBorrow<*mut $ffi_name> for $name $(<$($generic),+>)? { #[inline] #[allow(clippy::cast_ptr_alignment)] unsafe fn from_glib_borrow(ptr: *mut $ffi_name) -> $crate::translate::Borrowed { debug_assert!(!ptr.is_null()); debug_assert!($crate::types::instance_of::(ptr as *const _)); $crate::translate::Borrowed::new( $name { inner: $crate::object::TypedObjectRef::new($crate::translate::from_glib_borrow::<_, $crate::object::ObjectRef>(ptr as *mut _).into_inner()), phantom: std::marker::PhantomData, } ) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrBorrow<*const $ffi_name> for $name $(<$($generic),+>)? { #[inline] #[allow(clippy::cast_ptr_alignment)] unsafe fn from_glib_borrow(ptr: *const $ffi_name) -> $crate::translate::Borrowed { $crate::translate::from_glib_borrow::<_, Self>(ptr as *mut $ffi_name) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name $(<$($generic),+>)? { 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); let res_ptr = res.as_mut_ptr(); for i in 0..num { ::std::ptr::write(res_ptr.add(i), $crate::translate::from_glib_none(std::ptr::read(ptr.add(i)))); } res.set_len(num); res } unsafe fn from_glib_container_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { let res = $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); $crate::ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { if num == 0 || ptr.is_null() { $crate::ffi::g_free(ptr as *mut _); return Vec::new(); } let mut res = Vec::with_capacity(num); let res_ptr = res.as_mut_ptr(); ::std::ptr::copy_nonoverlapping(ptr as *mut Self, res_ptr, num); res.set_len(num); $crate::ffi::g_free(ptr as *mut _); res } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrArrayContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name $(<$($generic),+>)? { 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 $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibContainerAsVec<*mut $ffi_name, *const *mut $ffi_name> for $name $(<$($generic),+>)? { 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 $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrArrayContainerAsVec<*mut $ffi_name, *const *mut $ffi_name> for $name $(<$($generic),+>)? { 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 $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::prelude::StaticType for $name $(<$($generic),+>)? { #[inline] fn static_type() -> $crate::types::Type { #[allow(unused_unsafe)] #[allow(clippy::macro_metavars_in_unsafe)] unsafe { $crate::translate::from_glib($get_type_expr) } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::value::ValueType for $name $(<$($generic),+>)? { type Type = $name $(<$($generic),+>)?; } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::value::ValueTypeOptional for $name $(<$($generic),+>)? { } #[doc(hidden)] unsafe impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::value::FromValue<'a> for $name $(<$($generic),+>)? { type Checker = $crate::object::ObjectValueTypeChecker; #[inline] unsafe fn from_value(value: &'a $crate::Value) -> Self { let ptr = $crate::gobject_ffi::g_value_dup_object($crate::translate::ToGlibPtr::to_glib_none(value).0); debug_assert!(!ptr.is_null()); debug_assert_ne!((*ptr).ref_count, 0); >::from_glib_full(ptr as *mut $ffi_name) } } #[doc(hidden)] unsafe impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::value::FromValue<'a> for &'a $name $(<$($generic),+>)? { type Checker = $crate::object::ObjectValueTypeChecker; #[inline] unsafe fn from_value(value: &'a $crate::Value) -> Self { let value = &*(value as *const $crate::Value as *const $crate::gobject_ffi::GValue); <$name $(<$($generic),+>)? as $crate::object::ObjectType>::from_glib_ptr_borrow(&*(&value.data[0].v_pointer as *const $crate::ffi::gpointer as *const *mut $ffi_name)) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::value::ToValue for $name $(<$($generic),+>)? { #[inline] fn to_value(&self) -> $crate::Value { unsafe { let mut value = $crate::Value::from_type_unchecked(::static_type()); $crate::gobject_ffi::g_value_take_object( $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::translate::ToGlibPtr::<*mut $ffi_name>::to_glib_full(self) as *mut _, ); value } } #[inline] fn value_type(&self) -> $crate::Type { ::static_type() } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? ::std::convert::From<$name $(<$($generic),+>)?> for $crate::Value { #[inline] fn from(o: $name $(<$($generic),+>)?) -> Self { unsafe { let mut value = $crate::Value::from_type_unchecked(<$name $(<$($generic),+>)? as $crate::prelude::StaticType>::static_type()); $crate::gobject_ffi::g_value_take_object( $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::translate::IntoGlibPtr::<*mut $ffi_name>::into_glib_ptr(o) as *mut _, ); value } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::value::ToValueOptional for $name $(<$($generic),+>)? { #[inline] fn to_value_optional(s: Option<&Self>) -> $crate::Value { let mut value = $crate::Value::for_value_type::(); unsafe { $crate::gobject_ffi::g_value_take_object( $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::translate::ToGlibPtr::<*mut $ffi_name>::to_glib_full(&s) as *mut _, ); } value } } $crate::glib_object_wrapper!(@weak_impl $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?); impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::prelude::HasParamSpec for $name $(<$($generic),+>)? { type ParamSpec = $crate::ParamSpecObject; type SetValue = Self; type BuilderFn = fn(&str) -> $crate::ParamSpecObjectBuilder; fn param_spec_builder() -> Self::BuilderFn { |name| Self::ParamSpec::builder(name) } } }; (@weak_impl $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?) => { #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::clone::Downgrade for $name $(<$($generic),+>)? { type Weak = $crate::object::WeakRef; #[inline] fn downgrade(&self) -> Self::Weak { ::downgrade(&self) } } }; (@munch_impls $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, ) => { }; (@munch_impls $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $super_name:path) => { unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::prelude::IsA<$super_name> for $name $(<$($generic),+>)? { } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? From<$name $(<$($generic),+>)?> for $super_name { #[inline] fn from(v: $name $(<$($generic),+>)?) -> Self { <$name $(::<$($generic),+>)? as $crate::prelude::Cast>::upcast(v) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? AsRef<$super_name> for $name $(<$($generic),+>)? { #[inline] fn as_ref(&self) -> &$super_name { $crate::object::Cast::upcast_ref(self) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::borrow::Borrow<$super_name> for $name $(<$($generic),+>)? { #[inline] fn borrow(&self) -> &$super_name { $crate::object::Cast::upcast_ref(self) } } }; (@munch_impls $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $super_name:path, $($implements:tt)*) => { $crate::glib_object_wrapper!(@munch_impls $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $super_name); $crate::glib_object_wrapper!(@munch_impls $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $($implements)*); }; // If there is no parent class, i.e. only glib::Object (@munch_first_impl $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, ) => { $crate::glib_object_wrapper!(@munch_impls $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, ); unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::object::ParentClassIs for $name $(<$($generic),+>)? { type Parent = $crate::object::Object; } }; // If there is only one parent class (@munch_first_impl $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $super_name:path) => { $crate::glib_object_wrapper!(@munch_impls $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $super_name); unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::object::ParentClassIs for $name $(<$($generic),+>)? { type Parent = $super_name; } }; // If there is more than one parent class (@munch_first_impl $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $super_name:path, $($implements:tt)*) => { $crate::glib_object_wrapper!(@munch_impls $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $super_name); unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::object::ParentClassIs for $name $(<$($generic),+>)? { type Parent = $super_name; } $crate::glib_object_wrapper!(@munch_impls $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $($implements)*); }; // This case is only for glib::Object itself below. All other cases have glib::Object in its // parent class list (@object [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $impl_type:ty, $parent_type:ty, $ffi_name:ty, @ffi_class $ffi_class_name:ty, @type_ $get_type_expr:expr) => { $crate::glib_object_wrapper!( @generic_impl [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $impl_type, $parent_type, $ffi_name, $ffi_class_name, @type_ $get_type_expr); #[doc(hidden)] unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::object::IsClass for $name $(<$($generic),+>)? { } }; (@object [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $impl_type:ty, $parent_type:ty, $ffi_name:ty, @type_ $get_type_expr:expr, @extends [$($extends:tt)*], @implements [$($implements:tt)*]) => { $crate::glib_object_wrapper!( @object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $impl_type, $parent_type, $ffi_name, @ffi_class std::os::raw::c_void, @type_ $get_type_expr, @extends [$($extends)*], @implements [$($implements)*] ); }; (@object [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $impl_type:ty, $parent_type:ty, $ffi_name:ty, @ffi_class $ffi_class_name:ty, @type_ $get_type_expr:expr, @extends [$($extends:tt)*], @implements [$($implements:tt)*]) => { $crate::glib_object_wrapper!( @generic_impl [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $impl_type, $parent_type, $ffi_name, $ffi_class_name, @type_ $get_type_expr ); $crate::glib_object_wrapper!(@munch_first_impl $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $($extends)*); $crate::glib_object_wrapper!(@munch_impls $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $($implements)*); #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? AsRef<$crate::object::Object> for $name $(<$($generic),+>)? { #[inline] fn as_ref(&self) -> &$crate::object::Object { $crate::object::Cast::upcast_ref(self) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::borrow::Borrow<$crate::object::Object> for $name $(<$($generic),+>)? { #[inline] fn borrow(&self) -> &$crate::object::Object { $crate::object::Cast::upcast_ref(self) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? From<$name $(<$($generic),+>)?> for $crate::object::Object { #[inline] fn from(v: $name $(<$($generic),+>)?) -> Self { <$name $(::<$($generic),+>)? as $crate::prelude::Cast>::upcast(v) } } #[doc(hidden)] unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::prelude::IsA<$crate::object::Object> for $name $(<$($generic),+>)? { } #[doc(hidden)] unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::object::IsClass for $name $(<$($generic),+>)? { } }; // FIXME: Workaround for `glib::Object` not being `Send+Sync` but subclasses of it being both // if the impl struct is. (@object_subclass [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $subclass:ty, @extends [], @implements [$($implements:tt)*]) => { $crate::glib_object_wrapper!( @object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $subclass, (), <$subclass as $crate::subclass::types::ObjectSubclass>::Instance, @ffi_class <$subclass as $crate::subclass::types::ObjectSubclass>::Class, @type_ $crate::translate::IntoGlib::into_glib(<$subclass as $crate::subclass::types::ObjectSubclassType>::type_()), @extends [], @implements [$($implements)*] ); unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::object::ObjectSubclassIs for $name $(<$($generic),+>)? { type Subclass = $subclass; } }; (@object_subclass [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $subclass:ty, @extends [$($extends:tt)+], @implements [$($implements:tt)*]) => { $crate::glib_object_wrapper!( @object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $subclass, <$subclass as $crate::subclass::types::ObjectSubclass>::ParentType, <$subclass as $crate::subclass::types::ObjectSubclass>::Instance, @ffi_class <$subclass as $crate::subclass::types::ObjectSubclass>::Class, @type_ $crate::translate::IntoGlib::into_glib(<$subclass as $crate::subclass::types::ObjectSubclassType>::type_()), @extends [$($extends)*], @implements [$($implements)*] ); unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::object::ObjectSubclassIs for $name $(<$($generic),+>)? { type Subclass = $subclass; } }; (@interface [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $impl_type:ty, $ffi_name:ty, @type_ $get_type_expr:expr, @requires [$($requires:tt)*]) => { $crate::glib_object_wrapper!( @interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $impl_type, $ffi_name, @ffi_class std::os::raw::c_void, @type_ $get_type_expr, @requires [$($requires)*] ); }; (@object_interface [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $iface:ty, @type_ $get_type_expr:expr, @requires [$($requires:tt)*]) => { $crate::glib_object_wrapper!( @interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $iface, <$iface as $crate::subclass::interface::ObjectInterface>::Instance, @ffi_class <$iface as $crate::subclass::interface::ObjectInterface>::Interface, @type_ $get_type_expr, @requires [$($requires)*] ); }; (@interface [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $impl_type:ty, $ffi_name:ty, @ffi_class $ffi_class_name:ty, @type_ $get_type_expr:expr, @requires [$($requires:tt)*]) => { $crate::glib_object_wrapper!( @generic_impl [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $impl_type, (), $ffi_name, $ffi_class_name, @type_ $get_type_expr ); $crate::glib_object_wrapper!(@munch_impls $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $($requires)*); #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? AsRef<$crate::object::Object> for $name $(<$($generic),+>)? { #[inline] fn as_ref(&self) -> &$crate::object::Object { $crate::object::Cast::upcast_ref(self) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::borrow::Borrow<$crate::object::Object> for $name $(<$($generic),+>)? { #[inline] fn borrow(&self) -> &$crate::object::Object { $crate::object::Cast::upcast_ref(self) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? From<$name $(<$($generic),+>)?> for $crate::object::Object { #[inline] fn from(v: $name $(<$($generic),+>)?) -> Self { <$name $(::<$($generic),+>)? as $crate::prelude::Cast>::upcast(v) } } #[doc(hidden)] unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::prelude::IsA<$crate::object::Object> for $name $(<$($generic),+>)? { } #[doc(hidden)] unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::object::IsInterface for $name $(<$($generic),+>)? { } }; } glib_object_wrapper!(@object [doc = "The base class in the object hierarchy."] pub Object, *mut std::os::raw::c_void, (), gobject_ffi::GObject, @ffi_class gobject_ffi::GObjectClass, @type_ gobject_ffi::g_object_get_type() ); pub type ObjectClass = Class; impl Object { pub const NONE: Option<&'static Object> = None; // rustdoc-stripper-ignore-next /// Create a new instance of an object with the default property values. /// /// # Panics /// /// This panics if the object is not instantiable. #[track_caller] #[allow(clippy::new_ret_no_self)] pub fn new + IsClass>() -> T { let object = Object::with_type(T::static_type()); unsafe { object.unsafe_cast() } } // rustdoc-stripper-ignore-next /// Create a new instance of an object with the default property values. /// /// # Panics /// /// This panics if the object is not instantiable. #[track_caller] pub fn with_type(type_: Type) -> Object { Object::with_mut_values(type_, &mut []) } // rustdoc-stripper-ignore-next /// Create a new instance of an object of the given type with the given properties as mutable /// values. /// /// # Panics /// /// This panics if the object is not instantiable, doesn't have all the given properties or /// property values of the wrong type are provided. #[track_caller] pub fn with_mut_values(type_: Type, properties: &mut [(&str, Value)]) -> Object { #[cfg(feature = "gio")] unsafe { let iface_type = from_glib(gio_sys::g_initable_get_type()); if type_.is_a(iface_type) { panic!("Can't instantiate type '{type_}' implementing `gio::Initable`. Use `gio::Initable::new()`"); } let iface_type = from_glib(gio_sys::g_async_initable_get_type()); if type_.is_a(iface_type) { panic!("Can't instantiate type '{type_}' implementing `gio::AsyncInitable`. Use `gio::AsyncInitable::new()`"); } } unsafe { Object::new_internal(type_, properties) } } // rustdoc-stripper-ignore-next /// Create a new instance of an object of the given type with the given properties. /// /// # Panics /// /// This panics if the object is not instantiable, doesn't have all the given properties or /// property values of the wrong type are provided. /// /// Unlike the other constructors this does not panic if the object is implementing /// `gio::Initable` or `gio::AsyncInitable` and it might be unsafe to use the returned object /// without using the API of those interfaces first. #[track_caller] pub unsafe fn new_internal(type_: Type, properties: &mut [(&str, Value)]) -> Object { if !type_.is_a(Object::static_type()) { panic!("Can't instantiate non-GObject type '{type_}'"); } if gobject_ffi::g_type_test_flags( type_.into_glib(), gobject_ffi::G_TYPE_FLAG_INSTANTIATABLE, ) == ffi::GFALSE { panic!("Can't instantiate type '{type_}'"); } if gobject_ffi::g_type_test_flags(type_.into_glib(), gobject_ffi::G_TYPE_FLAG_ABSTRACT) != ffi::GFALSE { panic!("Can't instantiate abstract type '{type_}'"); } let mut property_names = smallvec::SmallVec::<[_; 16]>::with_capacity(properties.len()); let mut property_values = smallvec::SmallVec::<[_; 16]>::with_capacity(properties.len()); if !properties.is_empty() { let klass = ObjectClass::from_type(type_) .unwrap_or_else(|| panic!("Can't retrieve class for type '{type_}'")); for (idx, (name, value)) in properties.iter_mut().enumerate() { let pspec = klass .find_property(name) .unwrap_or_else(|| panic!("Can't find property '{name}' for type '{type_}'")); if (pspec.flags().contains(crate::ParamFlags::CONSTRUCT) || pspec.flags().contains(crate::ParamFlags::CONSTRUCT_ONLY)) && property_names[0..idx] .iter() .any(|other_name| pspec.name().as_ptr() == *other_name) { panic!("Can't set construct property '{name}' for type '{type_}' twice"); } // FIXME: With GLib 2.74 and GParamSpecClass::value_is_valid() it is possible to // not require mutable values here except for when LAX_VALIDATION is provided and a // change is needed, or a GObject value needs it's GType changed. validate_property_type(type_, true, &pspec, value); property_names.push(pspec.name().as_ptr()); property_values.push(*value.to_glib_none().0); } } let ptr = gobject_ffi::g_object_new_with_properties( type_.into_glib(), properties.len() as u32, mut_override(property_names.as_ptr() as *const *const _), property_values.as_ptr(), ); if ptr.is_null() { panic!("Can't instantiate object for type '{type_}'"); } else if type_.is_a(InitiallyUnowned::static_type()) { // Attention: This takes ownership of the floating reference from_glib_none(ptr) } else { from_glib_full(ptr) } } // rustdoc-stripper-ignore-next /// Create a new object builder for a specific type. pub fn builder<'a, O: IsA + IsClass>() -> ObjectBuilder<'a, O> { ObjectBuilder::new(O::static_type()) } // rustdoc-stripper-ignore-next /// Create a new object builder for a specific type. pub fn builder_with_type<'a>(type_: Type) -> ObjectBuilder<'a, Object> { ObjectBuilder::new(type_) } } #[must_use = "builder doesn't do anything unless built"] pub struct ObjectBuilder<'a, O> { type_: Type, properties: smallvec::SmallVec<[(&'a str, Value); 16]>, phantom: PhantomData, } impl<'a, O: IsA + IsClass> ObjectBuilder<'a, O> { #[inline] fn new(type_: Type) -> Self { ObjectBuilder { type_, properties: smallvec::SmallVec::new(), phantom: PhantomData, } } // rustdoc-stripper-ignore-next /// Gets the type of this builder. #[inline] pub fn type_(&self) -> Type { self.type_ } // rustdoc-stripper-ignore-next /// Sets property `name` to the given value `value`. /// /// Overrides any default or previously defined value for `name`. pub fn property(self, name: &'a str, value: impl Into) -> Self { let ObjectBuilder { type_, mut properties, .. } = self; properties.push((name, value.into())); ObjectBuilder { type_, properties, phantom: PhantomData, } } // rustdoc-stripper-ignore-next /// Sets property `name` to the given inner value if the `predicate` evaluates to `true`. /// /// This has no effect if the `predicate` evaluates to `false`, /// i.e. default or previous value for `name` is kept. #[inline] pub fn property_if(self, name: &'a str, value: impl Into, predicate: bool) -> Self { if predicate { self.property(name, value) } else { self } } // rustdoc-stripper-ignore-next /// Sets property `name` to the given inner value if `value` is `Some`. /// /// This has no effect if the value is `None`, i.e. default or previous value for `name` is kept. #[inline] pub fn property_if_some(self, name: &'a str, value: Option>) -> Self { if let Some(value) = value { self.property(name, value) } else { self } } // rustdoc-stripper-ignore-next /// Sets property `name` using the given `ValueType` `V` built from `iter`'s the `Item`s. /// /// Overrides any default or previously defined value for `name`. #[inline] pub fn property_from_iter + FromIterator>( self, name: &'a str, iter: impl IntoIterator>, ) -> Self { let iter = iter.into_iter().map(|item| item.into()); self.property(name, V::from_iter(iter)) } // rustdoc-stripper-ignore-next /// Sets property `name` using the given `ValueType` `V` built from `iter`'s Item`s, /// if `iter` is not empty. /// /// This has no effect if `iter` is empty, i.e. previous property value for `name` is unchanged. #[inline] pub fn property_if_not_empty + FromIterator>( self, name: &'a str, iter: impl IntoIterator>, ) -> Self { let mut iter = iter.into_iter().peekable(); if iter.peek().is_some() { let iter = iter.map(|item| item.into()); self.property(name, V::from_iter(iter)) } else { self } } // rustdoc-stripper-ignore-next /// Build the object with the provided properties. /// /// # Panics /// /// This panics if the object is not instantiable, doesn't have all the given properties or /// property values of the wrong type are provided. #[track_caller] #[inline] pub fn build(mut self) -> O { let object = Object::with_mut_values(self.type_, &mut self.properties); unsafe { object.unsafe_cast::() } } } #[must_use = "if unused the property notifications will immediately be thawed"] pub struct PropertyNotificationFreezeGuard(ObjectRef); impl Drop for PropertyNotificationFreezeGuard { #[doc(alias = "g_object_thaw_notify")] #[inline] fn drop(&mut self) { unsafe { gobject_ffi::g_object_thaw_notify(self.0.to_glib_none().0) } } } pub trait ObjectExt: ObjectType { // rustdoc-stripper-ignore-next /// Returns `true` if the object is an instance of (can be cast to) `T`. fn is(&self) -> bool; // rustdoc-stripper-ignore-next /// Returns the type of the object. #[doc(alias = "get_type")] fn type_(&self) -> Type; // rustdoc-stripper-ignore-next /// Returns the [`ObjectClass`] of the object. /// /// This is equivalent to calling `obj.class().upcast_ref::()`. #[doc(alias = "get_object_class")] fn object_class(&self) -> &ObjectClass; /// Returns the class of the object. #[doc(alias = "get_class")] fn class(&self) -> &Class where Self: IsClass; // rustdoc-stripper-ignore-next /// Returns the class of the object in the given type `T`. /// /// `None` is returned if the object is not a subclass of `T`. #[doc(alias = "get_class_of")] fn class_of(&self) -> Option<&Class>; // rustdoc-stripper-ignore-next /// Returns the interface `T` of the object. /// /// `None` is returned if the object does not implement the interface `T`. #[doc(alias = "get_interface")] fn interface(&self) -> Option>; // rustdoc-stripper-ignore-next /// Sets the property `property_name` of the object to value `value`. /// /// # Panics /// /// If the property does not exist, if the type of the property is different than /// the provided value, or if the property is not writable. #[doc(alias = "g_object_set_property")] fn set_property(&self, property_name: &str, value: impl Into); // rustdoc-stripper-ignore-next /// Sets the property `property_name` of the object to value `value`. /// /// # Panics /// /// If the property does not exist, the type of the property is different than the /// provided value, or if the property is not writable. #[doc(alias = "g_object_set_property")] fn set_property_from_value(&self, property_name: &str, value: &Value); // rustdoc-stripper-ignore-next /// Sets multiple properties of the object at once. /// /// # Panics /// /// This does not set any properties if one or more properties don't exist, values of the wrong /// type are provided, or if any of the properties is not writable. #[doc(alias = "g_object_set")] fn set_properties(&self, property_values: &[(&str, &dyn ToValue)]); // rustdoc-stripper-ignore-next /// Sets multiple properties of the object at once. /// /// # Panics /// /// This does not set any properties if one or more properties don't exist, values of the wrong /// type are provided, or if any of the properties is not writable. #[doc(alias = "g_object_set")] fn set_properties_from_value(&self, property_values: &[(&str, Value)]); // rustdoc-stripper-ignore-next /// Gets the property `property_name` of the object and cast it to the type V. /// /// # Panics /// /// If the property doesn't exist or is not readable or of a different type than V. #[doc(alias = "get_property")] #[doc(alias = "g_object_get_property")] fn property FromValue<'b> + 'static>(&self, property_name: &str) -> V; // rustdoc-stripper-ignore-next /// Gets the property `property_name` of the object. /// /// # Panics /// /// If the property does not exist or is not writable. #[doc(alias = "get_property")] #[doc(alias = "g_object_get_property")] fn property_value(&self, property_name: &str) -> Value; // rustdoc-stripper-ignore-next /// Check if the object has a property `property_name` of the given `type_`. /// /// If no type is provided then only the existence of the property is checked. fn has_property(&self, property_name: &str, type_: Option) -> bool; // rustdoc-stripper-ignore-next /// Get the type of the property `property_name` of this object. /// /// This returns `None` if the property does not exist. #[doc(alias = "get_property_type")] fn property_type(&self, property_name: &str) -> Option; // rustdoc-stripper-ignore-next /// Get the [`ParamSpec`](crate::ParamSpec) of the property `property_name` of this object. fn find_property(&self, property_name: &str) -> Option; // rustdoc-stripper-ignore-next /// Return all [`ParamSpec`](crate::ParamSpec) of the properties of this object. fn list_properties(&self) -> PtrSlice; // rustdoc-stripper-ignore-next /// Freeze all property notifications until the return guard object is dropped. /// /// This prevents the `notify` signal for all properties of this object to be emitted. #[doc(alias = "g_object_freeze_notify")] fn freeze_notify(&self) -> PropertyNotificationFreezeGuard; // rustdoc-stripper-ignore-next /// Set arbitrary data on this object with the given `key`. /// /// # Safety /// /// This function doesn't store type information unsafe fn set_qdata(&self, key: Quark, value: QD); // rustdoc-stripper-ignore-next /// Return previously set arbitrary data of this object with the given `key`. /// /// # Safety /// /// The returned pointer can become invalid by a call to /// `set_qdata`, `steal_qdata`, `set_data` or `steal_data`. /// /// The caller is responsible for ensuring the returned value is of a suitable type #[doc(alias = "get_qdata")] unsafe fn qdata(&self, key: Quark) -> Option>; // rustdoc-stripper-ignore-next /// Retrieve previously set arbitrary data of this object with the given `key`. /// /// The data is not set on the object anymore afterwards. /// /// # Safety /// /// The caller is responsible for ensuring the returned value is of a suitable type unsafe fn steal_qdata(&self, key: Quark) -> Option; // rustdoc-stripper-ignore-next /// Set arbitrary data on this object with the given `key`. /// /// # Safety /// /// This function doesn't store type information unsafe fn set_data(&self, key: &str, value: QD); // rustdoc-stripper-ignore-next /// Return previously set arbitrary data of this object with the given `key`. /// /// # Safety /// /// The returned pointer can become invalid by a call to /// `set_qdata`, `steal_qdata`, `set_data` or `steal_data`. /// /// The caller is responsible for ensuring the returned value is of a suitable type #[doc(alias = "get_data")] unsafe fn data(&self, key: &str) -> Option>; // rustdoc-stripper-ignore-next /// Retrieve previously set arbitrary data of this object with the given `key`. /// /// The data is not set on the object anymore afterwards. /// /// # Safety /// /// The caller is responsible for ensuring the returned value is of a suitable type unsafe fn steal_data(&self, key: &str) -> Option; // rustdoc-stripper-ignore-next /// Block a given signal handler. /// /// It will not be called again during signal emissions until it is unblocked. #[doc(alias = "g_signal_handler_block")] fn block_signal(&self, handler_id: &SignalHandlerId); // rustdoc-stripper-ignore-next /// Unblock a given signal handler. #[doc(alias = "g_signal_handler_unblock")] fn unblock_signal(&self, handler_id: &SignalHandlerId); // rustdoc-stripper-ignore-next /// Stop emission of the currently emitted signal. #[doc(alias = "g_signal_stop_emission")] fn stop_signal_emission(&self, signal_id: SignalId, detail: Option); // rustdoc-stripper-ignore-next /// Stop emission of the currently emitted signal by the (possibly detailed) signal name. #[doc(alias = "g_signal_stop_emission_by_name")] fn stop_signal_emission_by_name(&self, signal_name: &str); // rustdoc-stripper-ignore-next /// Connect to the signal `signal_name` on this object. /// /// If `after` is set to `true` then the callback will be called after the default class /// handler of the signal is emitted, otherwise before. /// /// # Panics /// /// If the signal does not exist. fn connect(&self, signal_name: &str, after: bool, callback: F) -> SignalHandlerId where F: Fn(&[Value]) -> Option + Send + Sync + 'static; // rustdoc-stripper-ignore-next /// Connect to the signal `signal_id` on this object. /// /// If `after` is set to `true` then the callback will be called after the default class /// handler of the signal is emitted, otherwise before. /// /// Same as [`Self::connect`] but takes a `SignalId` instead of a signal name. /// /// # Panics /// /// If the signal does not exist. fn connect_id( &self, signal_id: SignalId, details: Option, after: bool, callback: F, ) -> SignalHandlerId where F: Fn(&[Value]) -> Option + Send + Sync + 'static; // rustdoc-stripper-ignore-next /// Connect to the signal `signal_name` on this object. /// /// If `after` is set to `true` then the callback will be called after the default class /// handler of the signal is emitted, otherwise before. /// /// Same as [`Self::connect`] but takes a non-`Send+Sync` closure. If the signal is emitted from a /// different thread than it was connected to then the signal emission will panic. /// /// # Panics /// /// If the signal does not exist. fn connect_local(&self, signal_name: &str, after: bool, callback: F) -> SignalHandlerId where F: Fn(&[Value]) -> Option + 'static; // rustdoc-stripper-ignore-next /// Connect to the signal `signal_id` on this object. /// /// If `after` is set to `true` then the callback will be called after the default class /// handler of the signal is emitted, otherwise before. /// /// Same as [`Self::connect_id`] but takes a non-`Send+Sync` closure. If the signal is emitted from a /// different thread than it was connected to then the signal emission will panic. /// /// # Panics /// /// This panics if the signal does not exist. fn connect_local_id( &self, signal_id: SignalId, details: Option, after: bool, callback: F, ) -> SignalHandlerId where F: Fn(&[Value]) -> Option + 'static; // rustdoc-stripper-ignore-next /// Connect to the signal `signal_name` on this object. /// /// If `after` is set to `true` then the callback will be called after the default class /// handler of the signal is emitted, otherwise before. /// /// Same as [`Self::connect`] but takes a non-`Send+Sync` and non-`'static'` closure. No runtime checks /// are performed for ensuring that the closure is called correctly. /// /// # Safety /// /// The provided closure must be valid until the signal handler is disconnected, and it must /// be allowed to call the closure from the threads the signal is emitted from. /// /// # Panics /// /// If the signal does not exist. unsafe fn connect_unsafe( &self, signal_name: &str, after: bool, callback: F, ) -> SignalHandlerId where F: Fn(&[Value]) -> Option; // rustdoc-stripper-ignore-next /// Connect to the signal `signal_id` on this object. /// /// If `after` is set to `true` then the callback will be called after the default class /// handler of the signal is emitted, otherwise before. /// /// /// Same as [`Self::connect_id`] but takes a non-`Send+Sync` and non-`'static'` closure. No runtime checks /// are performed for ensuring that the closure is called correctly. /// /// # Safety /// /// The provided closure must be valid until the signal handler is disconnected, and it must /// be allowed to call the closure from the threads the signal is emitted from. /// /// # Panics /// /// If the signal does not exist. unsafe fn connect_unsafe_id( &self, signal_id: SignalId, details: Option, after: bool, callback: F, ) -> SignalHandlerId where F: Fn(&[Value]) -> Option; // rustdoc-stripper-ignore-next /// Connect a closure to the signal `signal_name` on this object. /// /// If `after` is set to `true` then the callback will be called after the default class /// handler of the signal is emitted, otherwise before. /// /// This panics if the signal does not exist. /// /// A recurring case is connecting a handler which will be automatically disconnected /// when an object it refers to is destroyed, as it happens with `g_signal_connect_object` /// in C. This can be achieved with a closure that watches an object: see the documentation /// of the [`closure!`](crate::closure!) macro for more details. /// /// Same as [`Self::connect`] but takes a [`Closure`] instead of a `Fn`. #[doc(alias = "g_signal_connect_closure")] #[doc(alias = "g_signal_connect_object")] fn connect_closure( &self, signal_name: &str, after: bool, closure: RustClosure, ) -> SignalHandlerId; // rustdoc-stripper-ignore-next /// Connect a closure to the signal `signal_id` on this object. /// /// If `after` is set to `true` then the callback will be called after the default class /// handler of the signal is emitted, otherwise before. /// /// This panics if the signal does not exist. /// /// Same as [`Self::connect_closure`] but takes a /// [`SignalId`] instead of a signal name. #[doc(alias = "g_signal_connect_closure_by_id")] fn connect_closure_id( &self, signal_id: SignalId, details: Option, after: bool, closure: RustClosure, ) -> SignalHandlerId; // rustdoc-stripper-ignore-next /// Limits the lifetime of `closure` to the lifetime of the object. When /// the object's reference count drops to zero, the closure will be /// invalidated. An invalidated closure will ignore any calls to /// [`invoke_with_values`](crate::closure::Closure::invoke_with_values), or /// [`invoke`](crate::closure::RustClosure::invoke) when using Rust closures. #[doc(alias = "g_object_watch_closure")] fn watch_closure(&self, closure: &impl AsRef); // rustdoc-stripper-ignore-next /// Emit signal by signal id. /// /// If the signal has a return value then this is returned here. /// /// # Panics /// /// If the wrong number of arguments is provided, or arguments of the wrong types /// were provided. #[doc(alias = "g_signal_emitv")] fn emit(&self, signal_id: SignalId, args: &[&dyn ToValue]) -> R; // rustdoc-stripper-ignore-next /// Same as [`Self::emit`] but takes `Value` for the arguments. fn emit_with_values(&self, signal_id: SignalId, args: &[Value]) -> Option; // rustdoc-stripper-ignore-next /// Emit signal by its name. /// /// If the signal has a return value then this is returned here. /// /// # Panics /// /// If the signal does not exist, the wrong number of arguments is provided, or /// arguments of the wrong types were provided. #[doc(alias = "g_signal_emit_by_name")] fn emit_by_name( &self, signal_name: &str, args: &[&dyn ToValue], ) -> R; // rustdoc-stripper-ignore-next /// Emit signal by its name. /// /// If the signal has a return value then this is returned here. /// /// # Panics /// /// If the signal does not exist, the wrong number of arguments is provided, or /// arguments of the wrong types were provided. fn emit_by_name_with_values(&self, signal_name: &str, args: &[Value]) -> Option; // rustdoc-stripper-ignore-next /// Emit signal by its name with details. /// /// If the signal has a return value then this is returned here. /// /// # Panics /// /// If the wrong number of arguments is provided, or arguments of the wrong types /// were provided. fn emit_by_name_with_details( &self, signal_name: &str, details: Quark, args: &[&dyn ToValue], ) -> R; // rustdoc-stripper-ignore-next /// Emit signal by its name with details. /// /// If the signal has a return value then this is returned here. /// /// # Panics /// /// If the wrong number of arguments is provided, or arguments of the wrong types /// were provided. fn emit_by_name_with_details_and_values( &self, signal_name: &str, details: Quark, args: &[Value], ) -> Option; // rustdoc-stripper-ignore-next /// Emit signal by signal id with details. /// /// If the signal has a return value then this is returned here. /// /// # Panics /// /// If the wrong number of arguments is provided, or arguments of the wrong types /// were provided. fn emit_with_details( &self, signal_id: SignalId, details: Quark, args: &[&dyn ToValue], ) -> R; // rustdoc-stripper-ignore-next /// Emit signal by signal id with details. /// /// If the signal has a return value then this is returned here. /// /// # Panics /// /// If the wrong number of arguments is provided, or arguments of the wrong types /// were provided. fn emit_with_details_and_values( &self, signal_id: SignalId, details: Quark, args: &[Value], ) -> Option; // rustdoc-stripper-ignore-next /// Disconnect a previously connected signal handler. #[doc(alias = "g_signal_handler_disconnect")] fn disconnect(&self, handler_id: SignalHandlerId); // rustdoc-stripper-ignore-next /// Connect to the `notify` signal of the object. /// /// This is emitted whenever a property is changed. If `name` is provided then the signal /// handler is only called for this specific property. fn connect_notify( &self, name: Option<&str>, f: F, ) -> SignalHandlerId; // rustdoc-stripper-ignore-next /// Connect to the `notify` signal of the object. /// /// This is emitted whenever a property is changed. If `name` is provided then the signal /// handler is only called for this specific property. /// /// This is like `connect_notify` but doesn't require a `Send+Sync` closure. Signal emission /// will panic if the signal is emitted from the wrong thread. fn connect_notify_local( &self, name: Option<&str>, f: F, ) -> SignalHandlerId; // rustdoc-stripper-ignore-next /// Connect to the `notify` signal of the object. /// /// This is emitted whenever a property is changed. If `name` is provided then the signal /// handler is only called for this specific property. /// /// This is like `connect_notify` but doesn't require a `Send+Sync` or `'static` closure. No /// runtime checks for wrongly calling the closure are performed. /// /// # Safety /// /// The provided closure must be valid until the signal handler is disconnected, and it must /// be allowed to call the closure from the threads the signal is emitted from. unsafe fn connect_notify_unsafe( &self, name: Option<&str>, f: F, ) -> SignalHandlerId; // rustdoc-stripper-ignore-next /// Notify that the given property has changed its value. /// /// This emits the `notify` signal. #[doc(alias = "g_object_notify")] fn notify(&self, property_name: &str); // rustdoc-stripper-ignore-next /// Notify that the given property has changed its value. /// /// This emits the `notify` signal. #[doc(alias = "g_object_notify_by_pspec")] fn notify_by_pspec(&self, pspec: &crate::ParamSpec); // rustdoc-stripper-ignore-next /// Downgrade this object to a weak reference. fn downgrade(&self) -> WeakRef; // rustdoc-stripper-ignore-next /// Add a callback to be notified when the Object is disposed. #[doc(alias = "g_object_weak_ref")] #[doc(alias = "connect_drop")] fn add_weak_ref_notify(&self, f: F) -> WeakRefNotify; // rustdoc-stripper-ignore-next /// Add a callback to be notified when the Object is disposed. /// /// This is like [`add_weak_ref_notify`][`ObjectExt::add_weak_ref_notify`] but doesn't require the closure to be [`Send`]. /// Object dispose will panic if the object is disposed from the wrong thread. #[doc(alias = "g_object_weak_ref")] #[doc(alias = "connect_drop")] fn add_weak_ref_notify_local(&self, f: F) -> WeakRefNotify; // rustdoc-stripper-ignore-next /// Bind property `source_property` on this object to the `target_property` on the `target` object. /// /// This allows keeping the properties of both objects in sync. /// /// The binding can be unidirectional or bidirectional and optionally it is possible to /// transform the property values before they're passed to the other object. fn bind_property<'a, 'f, 't, O: ObjectType>( &'a self, source_property: &'a str, target: &'a O, target_property: &'a str, ) -> BindingBuilder<'a, 'f, 't>; // rustdoc-stripper-ignore-next /// Returns the strong reference count of this object. fn ref_count(&self) -> u32; // rustdoc-stripper-ignore-next /// Runs the dispose mechanism of the object. /// /// This will dispose of any references the object has to other objects, and among other things /// will disconnect all signal handlers. /// /// # Safety /// /// Theoretically this is safe to run and afterwards the object is simply in a non-functional /// state, however many object implementations in C end up with memory safety issues if the /// object is used after disposal. #[doc(alias = "g_object_run_dispose")] unsafe fn run_dispose(&self); } impl ObjectExt for T { #[inline] fn is(&self) -> bool { self.type_().is_a(U::static_type()) } #[inline] fn type_(&self) -> Type { self.object_class().type_() } #[inline] fn object_class(&self) -> &ObjectClass { unsafe { let obj: *mut gobject_ffi::GObject = self.as_object_ref().to_glib_none().0; let klass = (*obj).g_type_instance.g_class as *const ObjectClass; &*klass } } #[inline] fn class(&self) -> &Class where Self: IsClass, { unsafe { let obj: *mut gobject_ffi::GObject = self.as_object_ref().to_glib_none().0; let klass = (*obj).g_type_instance.g_class as *const Class; &*klass } } #[inline] fn class_of(&self) -> Option<&Class> { if !self.is::() { return None; } unsafe { let obj: *mut gobject_ffi::GObject = self.as_object_ref().to_glib_none().0; let klass = (*obj).g_type_instance.g_class as *const Class; Some(&*klass) } } #[inline] fn interface(&self) -> Option> { Interface::from_class(self.object_class()) } #[track_caller] fn set_property(&self, property_name: &str, value: impl Into) { let pspec = self.find_property(property_name).unwrap_or_else(|| { panic!( "property '{property_name}' of type '{}' not found", self.type_() ) }); let mut property_value = value.into(); validate_property_type(self.type_(), false, &pspec, &mut property_value); unsafe { gobject_ffi::g_object_set_property( self.as_object_ref().to_glib_none().0, pspec.name().as_ptr() as *const _, property_value.to_glib_none().0, ); } } #[track_caller] fn set_property_from_value(&self, property_name: &str, value: &Value) { let pspec = match self.find_property(property_name) { Some(pspec) => pspec, None => { panic!( "property '{property_name}' of type '{}' not found", self.type_() ); } }; // FIXME: With GLib 2.74 and GParamSpecClass::value_is_valid() it is possible to // not require mutable values here except for when LAX_VALIDATION is provided and a // change is needed, or a GObject value needs it's GType changed. let mut property_value = value.clone(); validate_property_type(self.type_(), false, &pspec, &mut property_value); unsafe { gobject_ffi::g_object_set_property( self.as_object_ref().to_glib_none().0, pspec.name().as_ptr() as *const _, property_value.to_glib_none().0, ); } } #[track_caller] fn set_properties(&self, property_values: &[(&str, &dyn ToValue)]) { let params = property_values .iter() .map(|&(name, value)| { let pspec = self.find_property(name).unwrap_or_else(|| { panic!("Can't find property '{name}' for type '{}'", self.type_()); }); let mut value = value.to_value(); validate_property_type(self.type_(), false, &pspec, &mut value); (pspec.name().as_ptr(), value) }) .collect::>(); let _guard = self.freeze_notify(); for (name, value) in params { unsafe { gobject_ffi::g_object_set_property( self.as_object_ref().to_glib_none().0, name as *const _, value.to_glib_none().0, ); } } } #[track_caller] fn set_properties_from_value(&self, property_values: &[(&str, Value)]) { let params = property_values .iter() .map(|(name, value)| { let pspec = self.find_property(name).unwrap_or_else(|| { panic!("Can't find property '{name}' for type '{}'", self.type_()); }); let mut value = value.clone(); validate_property_type(self.type_(), false, &pspec, &mut value); (pspec.name().as_ptr(), value) }) .collect::>(); let _guard = self.freeze_notify(); for (name, value) in params { unsafe { gobject_ffi::g_object_set_property( self.as_object_ref().to_glib_none().0, name as *const _, value.to_glib_none().0, ); } } } #[track_caller] fn property FromValue<'b> + 'static>(&self, property_name: &str) -> V { let prop = self.property_value(property_name); let v = prop .get_owned::() .unwrap_or_else(|e| panic!("Failed to get cast value to a different type {e}")); v } #[track_caller] fn property_value(&self, property_name: &str) -> Value { let pspec = self.find_property(property_name).unwrap_or_else(|| { panic!( "property '{property_name}' of type '{}' not found", self.type_() ) }); if !pspec.flags().contains(crate::ParamFlags::READABLE) { panic!( "property '{property_name}' of type '{}' is not readable", self.type_() ); } unsafe { let mut value = Value::from_type_unchecked(pspec.value_type()); gobject_ffi::g_object_get_property( self.as_object_ref().to_glib_none().0, pspec.name().as_ptr() as *const _, value.to_glib_none_mut().0, ); // This can't really happen unless something goes wrong inside GObject if !value.type_().is_valid() { panic!( "Failed to get property value for property '{property_name}' of type '{}'", self.type_() ) } value } } fn has_property(&self, property_name: &str, type_: Option) -> bool { self.object_class().has_property(property_name, type_) } fn property_type(&self, property_name: &str) -> Option { self.object_class().property_type(property_name) } fn find_property(&self, property_name: &str) -> Option { self.object_class().find_property(property_name) } fn list_properties(&self) -> PtrSlice { self.object_class().list_properties() } #[inline] fn freeze_notify(&self) -> PropertyNotificationFreezeGuard { unsafe { gobject_ffi::g_object_freeze_notify(self.as_object_ref().to_glib_none().0) }; PropertyNotificationFreezeGuard(self.as_object_ref().clone()) } unsafe fn set_qdata(&self, key: Quark, value: QD) { unsafe extern "C" fn drop_value(ptr: ffi::gpointer) { debug_assert!(!ptr.is_null()); let value: Box = Box::from_raw(ptr as *mut QD); drop(value) } let ptr = Box::into_raw(Box::new(value)) as ffi::gpointer; gobject_ffi::g_object_set_qdata_full( self.as_object_ref().to_glib_none().0, key.into_glib(), ptr, Some(drop_value::), ); } unsafe fn qdata(&self, key: Quark) -> Option> { ptr::NonNull::new(gobject_ffi::g_object_get_qdata( self.as_object_ref().to_glib_none().0, key.into_glib(), ) as *mut QD) } unsafe fn steal_qdata(&self, key: Quark) -> Option { let ptr = gobject_ffi::g_object_steal_qdata( self.as_object_ref().to_glib_none().0, key.into_glib(), ); if ptr.is_null() { None } else { let value: Box = Box::from_raw(ptr as *mut QD); Some(*value) } } unsafe fn set_data(&self, key: &str, value: QD) { self.set_qdata::(Quark::from_str(key), value) } unsafe fn data(&self, key: &str) -> Option> { self.qdata::(Quark::from_str(key)) } unsafe fn steal_data(&self, key: &str) -> Option { self.steal_qdata::(Quark::from_str(key)) } fn block_signal(&self, handler_id: &SignalHandlerId) { unsafe { gobject_ffi::g_signal_handler_block( self.as_object_ref().to_glib_none().0, handler_id.as_raw(), ); } } fn unblock_signal(&self, handler_id: &SignalHandlerId) { unsafe { gobject_ffi::g_signal_handler_unblock( self.as_object_ref().to_glib_none().0, handler_id.as_raw(), ); } } fn stop_signal_emission(&self, signal_id: SignalId, detail: Option) { unsafe { gobject_ffi::g_signal_stop_emission( self.as_object_ref().to_glib_none().0, signal_id.into_glib(), detail.into_glib(), ); } } fn stop_signal_emission_by_name(&self, signal_name: &str) { unsafe { signal_name.run_with_gstr(|signal_name| { gobject_ffi::g_signal_stop_emission_by_name( self.as_object_ref().to_glib_none().0, signal_name.as_ptr(), ) }); } } #[track_caller] fn connect(&self, signal_name: &str, after: bool, callback: F) -> SignalHandlerId where F: Fn(&[Value]) -> Option + Send + Sync + 'static, { unsafe { self.connect_unsafe(signal_name, after, callback) } } #[track_caller] fn connect_id( &self, signal_id: SignalId, details: Option, after: bool, callback: F, ) -> SignalHandlerId where F: Fn(&[Value]) -> Option + Send + Sync + 'static, { unsafe { self.connect_unsafe_id(signal_id, details, after, callback) } } #[track_caller] fn connect_local(&self, signal_name: &str, after: bool, callback: F) -> SignalHandlerId where F: Fn(&[Value]) -> Option + 'static, { let callback = crate::thread_guard::ThreadGuard::new(callback); unsafe { self.connect_unsafe(signal_name, after, move |values| { (callback.get_ref())(values) }) } } #[track_caller] fn connect_local_id( &self, signal_id: SignalId, details: Option, after: bool, callback: F, ) -> SignalHandlerId where F: Fn(&[Value]) -> Option + 'static, { let callback = crate::thread_guard::ThreadGuard::new(callback); unsafe { self.connect_unsafe_id(signal_id, details, after, move |values| { (callback.get_ref())(values) }) } } #[track_caller] unsafe fn connect_unsafe( &self, signal_name: &str, after: bool, callback: F, ) -> SignalHandlerId where F: Fn(&[Value]) -> Option, { let type_ = self.type_(); let (signal_id, details) = SignalId::parse_name(signal_name, type_, true) .unwrap_or_else(|| panic!("Signal '{signal_name}' of type '{type_}' not found")); self.connect_unsafe_id(signal_id, details, after, callback) } #[track_caller] unsafe fn connect_unsafe_id( &self, signal_id: SignalId, details: Option, after: bool, callback: F, ) -> SignalHandlerId where F: Fn(&[Value]) -> Option, { let signal_query = signal_id.query(); let type_ = self.type_(); let return_type: Type = signal_query.return_type().into(); let signal_name = signal_id.name(); let signal_query_type = signal_query.type_(); let closure = if return_type == Type::UNIT { Closure::new_unsafe(move |values| { let ret = callback(values); if let Some(ret) = ret { panic!( "Signal '{signal_name}' of type '{type_}' required no return value but got value of type '{}'", ret.type_() ); } None }) } else { Closure::new_unsafe(move |values| { let mut ret = callback(values).unwrap_or_else(|| { panic!( "Signal '{signal_name}' of type '{type_}' required return value of type '{}' but got None", return_type.name() ); }); let valid_type: bool = from_glib(gobject_ffi::g_type_check_value_holds( mut_override(ret.to_glib_none().0), return_type.into_glib(), )); if valid_type { return Some(ret); } if let Err(got) = coerce_object_type(&mut ret, return_type) { panic!( "Signal '{signal_name}' of type '{type_}' required return value of type '{return_type}' but got '{got}'", ); }; Some(ret) }) }; assert!( type_.is_a(signal_query_type), "Signal '{signal_name}' of type '{type_}' but got type '{signal_query_type}'", ); let handler = gobject_ffi::g_signal_connect_closure_by_id( self.as_object_ref().to_glib_none().0, signal_id.into_glib(), details.into_glib(), closure.as_ref().to_glib_none().0, after.into_glib(), ); if handler == 0 { panic!("Failed to connect to signal '{signal_name}' of type '{type_}'",); } from_glib(handler) } #[track_caller] fn connect_closure( &self, signal_name: &str, after: bool, closure: RustClosure, ) -> SignalHandlerId { let type_ = self.type_(); let (signal_id, details) = SignalId::parse_name(signal_name, type_, true) .unwrap_or_else(|| panic!("Signal '{signal_name}' of type '{type_}' not found")); self.connect_closure_id(signal_id, details, after, closure) } #[track_caller] fn connect_closure_id( &self, signal_id: SignalId, details: Option, after: bool, closure: RustClosure, ) -> SignalHandlerId { let signal_query = signal_id.query(); let type_ = self.type_(); let signal_name = signal_id.name(); let signal_query_type = signal_query.type_(); assert!( type_.is_a(signal_query_type), "Signal '{signal_name}' of type '{type_}' but got type '{signal_query_type}'", ); unsafe { let handler = gobject_ffi::g_signal_connect_closure_by_id( self.as_object_ref().to_glib_none().0, signal_id.into_glib(), details.into_glib(), closure.as_ref().to_glib_none().0, after.into_glib(), ); if handler == 0 { panic!("Failed to connect to signal '{signal_name}' of type '{type_}'",); } from_glib(handler) } } #[inline] fn watch_closure(&self, closure: &impl AsRef) { let closure = closure.as_ref(); unsafe { gobject_ffi::g_object_watch_closure( self.as_object_ref().to_glib_none().0, closure.to_glib_none().0, ); } } #[track_caller] fn emit(&self, signal_id: SignalId, args: &[&dyn ToValue]) -> R { let signal_query = signal_id.query(); unsafe { let type_ = self.type_(); let self_v = { let mut v = Value::uninitialized(); gobject_ffi::g_value_init(v.to_glib_none_mut().0, self.type_().into_glib()); gobject_ffi::g_value_set_object( v.to_glib_none_mut().0, self.as_object_ref().to_glib_none().0, ); v }; let mut args = Iterator::chain( std::iter::once(self_v), args.iter().copied().map(ToValue::to_value), ) .collect::>(); validate_signal_arguments(type_, &signal_query, &mut args[1..]); let mut return_value = if signal_query.return_type() != Type::UNIT { Value::from_type_unchecked(signal_query.return_type().into()) } else { Value::uninitialized() }; let return_value_ptr = if signal_query.return_type() != Type::UNIT { return_value.to_glib_none_mut().0 } else { ptr::null_mut() }; gobject_ffi::g_signal_emitv( mut_override(args.as_ptr()) as *mut gobject_ffi::GValue, signal_id.into_glib(), 0, return_value_ptr, ); R::try_from_closure_return_value( Some(return_value).filter(|r| r.type_().is_valid() && r.type_() != Type::UNIT), ) .unwrap() } } #[track_caller] fn emit_with_values(&self, signal_id: SignalId, args: &[Value]) -> Option { unsafe { let type_ = self.type_(); let signal_query = signal_id.query(); let self_v = { let mut v = Value::uninitialized(); gobject_ffi::g_value_init(v.to_glib_none_mut().0, self.type_().into_glib()); gobject_ffi::g_value_set_object( v.to_glib_none_mut().0, self.as_object_ref().to_glib_none().0, ); v }; let mut args = Iterator::chain(std::iter::once(self_v), args.iter().cloned()) .collect::>(); validate_signal_arguments(type_, &signal_query, &mut args[1..]); let mut return_value = if signal_query.return_type() != Type::UNIT { Value::from_type_unchecked(signal_query.return_type().into()) } else { Value::uninitialized() }; let return_value_ptr = if signal_query.return_type() != Type::UNIT { return_value.to_glib_none_mut().0 } else { ptr::null_mut() }; gobject_ffi::g_signal_emitv( mut_override(args.as_ptr()) as *mut gobject_ffi::GValue, signal_id.into_glib(), 0, return_value_ptr, ); Some(return_value).filter(|r| r.type_().is_valid() && r.type_() != Type::UNIT) } } #[track_caller] fn emit_by_name( &self, signal_name: &str, args: &[&dyn ToValue], ) -> R { let type_ = self.type_(); let signal_id = SignalId::lookup(signal_name, type_).unwrap_or_else(|| { panic!("Signal '{signal_name}' of type '{type_}' not found"); }); self.emit(signal_id, args) } #[track_caller] fn emit_by_name_with_values(&self, signal_name: &str, args: &[Value]) -> Option { let type_ = self.type_(); let signal_id = SignalId::lookup(signal_name, type_).unwrap_or_else(|| { panic!("Signal '{signal_name}' of type '{type_}' not found"); }); self.emit_with_values(signal_id, args) } #[track_caller] fn emit_by_name_with_details( &self, signal_name: &str, details: Quark, args: &[&dyn ToValue], ) -> R { let type_ = self.type_(); let signal_id = SignalId::lookup(signal_name, type_) .unwrap_or_else(|| panic!("Signal '{signal_name}' of type '{type_}' not found")); self.emit_with_details(signal_id, details, args) } #[track_caller] fn emit_by_name_with_details_and_values( &self, signal_name: &str, details: Quark, args: &[Value], ) -> Option { let type_ = self.type_(); let signal_id = SignalId::lookup(signal_name, type_) .unwrap_or_else(|| panic!("Signal '{signal_name}' of type '{type_}' not found")); self.emit_with_details_and_values(signal_id, details, args) } #[track_caller] fn emit_with_details( &self, signal_id: SignalId, details: Quark, args: &[&dyn ToValue], ) -> R { let signal_query = signal_id.query(); assert!(signal_query.flags().contains(crate::SignalFlags::DETAILED)); unsafe { let type_ = self.type_(); let self_v = { let mut v = Value::uninitialized(); gobject_ffi::g_value_init(v.to_glib_none_mut().0, self.type_().into_glib()); gobject_ffi::g_value_set_object( v.to_glib_none_mut().0, self.as_object_ref().to_glib_none().0, ); v }; let mut args = Iterator::chain( std::iter::once(self_v), args.iter().copied().map(ToValue::to_value), ) .collect::>(); validate_signal_arguments(type_, &signal_query, &mut args[1..]); let mut return_value = if signal_query.return_type() != Type::UNIT { Value::from_type_unchecked(signal_query.return_type().into()) } else { Value::uninitialized() }; let return_value_ptr = if signal_query.return_type() != Type::UNIT { return_value.to_glib_none_mut().0 } else { ptr::null_mut() }; gobject_ffi::g_signal_emitv( mut_override(args.as_ptr()) as *mut gobject_ffi::GValue, signal_id.into_glib(), details.into_glib(), return_value_ptr, ); R::try_from_closure_return_value( Some(return_value).filter(|r| r.type_().is_valid() && r.type_() != Type::UNIT), ) .unwrap() } } #[track_caller] fn emit_with_details_and_values( &self, signal_id: SignalId, details: Quark, args: &[Value], ) -> Option { let signal_query = signal_id.query(); assert!(signal_query.flags().contains(crate::SignalFlags::DETAILED)); unsafe { let type_ = self.type_(); let self_v = { let mut v = Value::uninitialized(); gobject_ffi::g_value_init(v.to_glib_none_mut().0, self.type_().into_glib()); gobject_ffi::g_value_set_object( v.to_glib_none_mut().0, self.as_object_ref().to_glib_none().0, ); v }; let mut args = Iterator::chain(std::iter::once(self_v), args.iter().cloned()) .collect::>(); validate_signal_arguments(type_, &signal_query, &mut args[1..]); let mut return_value = if signal_query.return_type() != Type::UNIT { Value::from_type_unchecked(signal_query.return_type().into()) } else { Value::uninitialized() }; let return_value_ptr = if signal_query.return_type() != Type::UNIT { return_value.to_glib_none_mut().0 } else { ptr::null_mut() }; gobject_ffi::g_signal_emitv( mut_override(args.as_ptr()) as *mut gobject_ffi::GValue, signal_id.into_glib(), details.into_glib(), return_value_ptr, ); Some(return_value).filter(|r| r.type_().is_valid() && r.type_() != Type::UNIT) } } #[inline] fn disconnect(&self, handler_id: SignalHandlerId) { unsafe { gobject_ffi::g_signal_handler_disconnect( self.as_object_ref().to_glib_none().0, handler_id.as_raw(), ); } } fn connect_notify( &self, name: Option<&str>, f: F, ) -> SignalHandlerId { unsafe { self.connect_notify_unsafe(name, f) } } fn connect_notify_local( &self, name: Option<&str>, f: F, ) -> SignalHandlerId { let f = crate::thread_guard::ThreadGuard::new(f); unsafe { self.connect_notify_unsafe(name, move |s, pspec| { (f.get_ref())(s, pspec); }) } } unsafe fn connect_notify_unsafe( &self, name: Option<&str>, f: F, ) -> SignalHandlerId { unsafe extern "C" fn notify_trampoline( this: *mut gobject_ffi::GObject, param_spec: *mut gobject_ffi::GParamSpec, f: ffi::gpointer, ) where P: ObjectType, { let f: &F = &*(f as *const F); f( Object::from_glib_borrow(this).unsafe_cast_ref(), &from_glib_borrow(param_spec), ) } let signal_name = if let Some(name) = name { format!("notify::{name}\0") } else { "notify\0".into() }; let f: Box = Box::new(f); crate::signal::connect_raw( self.as_object_ref().to_glib_none().0, signal_name.as_ptr() as *const _, Some(mem::transmute::<*const (), unsafe extern "C" fn()>( notify_trampoline:: as *const (), )), Box::into_raw(f), ) } #[inline] fn notify(&self, property_name: &str) { unsafe { property_name.run_with_gstr(|property_name| { gobject_ffi::g_object_notify( self.as_object_ref().to_glib_none().0, property_name.as_ptr(), ) }); } } #[inline] fn notify_by_pspec(&self, pspec: &crate::ParamSpec) { unsafe { gobject_ffi::g_object_notify_by_pspec( self.as_object_ref().to_glib_none().0, pspec.to_glib_none().0, ); } } #[inline] fn downgrade(&self) -> WeakRef { unsafe { let w = WeakRef(Box::pin(mem::zeroed()), PhantomData); gobject_ffi::g_weak_ref_init( mut_override(&*w.0), self.as_object_ref().to_glib_none().0, ); w } } fn add_weak_ref_notify(&self, f: F) -> WeakRefNotify { WeakRefNotify::new(self, f) } fn add_weak_ref_notify_local(&self, f: F) -> WeakRefNotify { let callback = crate::thread_guard::ThreadGuard::new(f); WeakRefNotify::new(self, move || callback.into_inner()()) } fn bind_property<'a, 'f, 't, O: ObjectType>( &'a self, source_property: &'a str, target: &'a O, target_property: &'a str, ) -> BindingBuilder<'a, 'f, 't> { BindingBuilder::new(self, source_property, target, target_property) } #[inline] fn ref_count(&self) -> u32 { let stash = self.as_object_ref().to_glib_none(); let ptr: *mut gobject_ffi::GObject = stash.0; unsafe { ffi::g_atomic_int_get(&(*ptr).ref_count as *const u32 as *const i32) as u32 } } #[inline] unsafe fn run_dispose(&self) { gobject_ffi::g_object_run_dispose(self.as_ptr() as *mut _); } } // Helper struct to avoid creating an extra ref on objects inside closure watches. This is safe // because `watch_closure` ensures the object has a ref when the closure is called. #[doc(hidden)] pub struct WatchedObject(ptr::NonNull); #[doc(hidden)] unsafe impl Send for WatchedObject {} #[doc(hidden)] unsafe impl Sync for WatchedObject {} #[doc(hidden)] impl WatchedObject { pub fn new(obj: &T) -> Self { Self(unsafe { ptr::NonNull::new_unchecked(obj.as_ptr()) }) } // rustdoc-stripper-ignore-next /// # Safety /// /// This should only be called from within a closure that was previously attached to `T` using /// `Watchable::watch_closure`. #[inline] pub unsafe fn borrow(&self) -> Borrowed where T: FromGlibPtrBorrow<*mut ::GlibType>, { from_glib_borrow(self.0.as_ptr()) } } #[doc(hidden)] pub trait Watchable { fn watched_object(&self) -> WatchedObject; fn watch_closure(&self, closure: &impl AsRef); } #[doc(hidden)] impl Watchable for T { fn watched_object(&self) -> WatchedObject { WatchedObject::new(self) } fn watch_closure(&self, closure: &impl AsRef) { ObjectExt::watch_closure(self, closure) } } #[doc(hidden)] impl Watchable for BorrowedObject<'_, T> { fn watched_object(&self) -> WatchedObject { WatchedObject::new(self) } fn watch_closure(&self, closure: &impl AsRef) { ObjectExt::watch_closure(&**self, closure) } } #[doc(hidden)] impl Watchable for &T { fn watched_object(&self) -> WatchedObject { WatchedObject::new(*self) } fn watch_closure(&self, closure: &impl AsRef) { ObjectExt::watch_closure(*self, closure) } } // Validate that the given property value has an acceptable type for the given property pspec // and if necessary update the value #[track_caller] fn validate_property_type( type_: Type, allow_construct_only: bool, pspec: &crate::ParamSpec, property_value: &mut Value, ) { if !pspec.flags().contains(crate::ParamFlags::WRITABLE) || (!allow_construct_only && pspec.flags().contains(crate::ParamFlags::CONSTRUCT_ONLY)) { panic!( "property '{}' of type '{type_}' is not writable", pspec.name(), ); } unsafe { // While GLib actually allows all types that can somehow be transformed // into the property type, we're more restrictive here to be consistent // with Rust's type rules. We only allow the exact same type, or if the // value type is a subtype of the property type let valid_type: bool = from_glib(gobject_ffi::g_type_check_value_holds( mut_override(property_value.to_glib_none().0), pspec.value_type().into_glib(), )); if !valid_type { if let Err(got) = coerce_object_type(property_value, pspec.value_type()) { panic!( "property '{}' of type '{type_}' can't be set from the given type (expected: '{}', got: '{got}')", pspec.name(), pspec.value_type(), ); } } let changed: bool = from_glib(gobject_ffi::g_param_value_validate( pspec.to_glib_none().0, property_value.to_glib_none_mut().0, )); let change_allowed = pspec.flags().contains(crate::ParamFlags::LAX_VALIDATION); if changed && !change_allowed { panic!( "property '{}' of type '{type_}' can't be set from given value, it is invalid or out of range", pspec.name(), ); } } } // If it's not directly a valid type but an object type, we check if the // actual type of the contained object is compatible and if so create // a properly typed Value (by mutating the existing Value). // This can happen if the type field in the Value is set to a more // generic type than the contained value. fn coerce_object_type(property_value: &mut Value, type_: Type) -> Result<(), Type> { // return early if type coercion is not possible match property_value.get::>() { Ok(Some(obj)) if !(obj.type_().is_a(type_)) => Err(obj.type_()), Ok(_) => { property_value.inner.g_type = type_.into_glib(); Ok(()) } Err(_) => Err(property_value.type_()), } } #[track_caller] fn validate_signal_arguments(type_: Type, signal_query: &SignalQuery, args: &mut [Value]) { let signal_name = signal_query.signal_name(); if signal_query.n_params() != args.len() as u32 { panic!( "Incompatible number of arguments for signal '{signal_name}' of type '{type_}' (expected {}, got {})", signal_query.n_params(), args.len(), ); } let param_types = Iterator::zip(args.iter_mut(), signal_query.param_types()); for (i, (arg, param_type)) in param_types.enumerate() { let param_type: Type = (*param_type).into(); if param_type != arg.type_() { coerce_object_type(arg, param_type).unwrap_or_else(|got| panic!( "Incompatible argument type in argument {i} for signal '{signal_name}' of type '{type_}' (expected {param_type}, got {got})", ) ); } } } /// Trait for class methods on `Object` and subclasses of it. pub unsafe trait ObjectClassExt { // rustdoc-stripper-ignore-next /// Check if the object class has a property `property_name` of the given `type_`. /// /// If no type is provided then only the existence of the property is checked. fn has_property(&self, property_name: &str, type_: Option) -> bool { let ptype = self.property_type(property_name); match (ptype, type_) { (None, _) => false, (Some(_), None) => true, (Some(ptype), Some(type_)) => ptype == type_, } } // rustdoc-stripper-ignore-next /// Get the type of the property `property_name` of this object class. /// /// This returns `None` if the property does not exist. #[doc(alias = "get_property_type")] fn property_type(&self, property_name: &str) -> Option { self.find_property(property_name) .map(|pspec| pspec.value_type()) } // rustdoc-stripper-ignore-next /// Get the [`ParamSpec`](crate::ParamSpec) of the property `property_name` of this object class. #[doc(alias = "g_object_class_find_property")] fn find_property(&self, property_name: &str) -> Option { unsafe { let klass = self as *const _ as *const gobject_ffi::GObjectClass; property_name.run_with_gstr(|property_name| { from_glib_none(gobject_ffi::g_object_class_find_property( klass as *mut _, property_name.as_ptr(), )) }) } } // rustdoc-stripper-ignore-next /// Return all [`ParamSpec`](crate::ParamSpec) of the properties of this object class. #[doc(alias = "g_object_class_list_properties")] fn list_properties(&self) -> PtrSlice { unsafe { let klass = self as *const _ as *const gobject_ffi::GObjectClass; let mut n_properties = 0; let props = gobject_ffi::g_object_class_list_properties(klass as *mut _, &mut n_properties); PtrSlice::from_glib_container_num(props, n_properties as usize, true) } } } unsafe impl ObjectClassExt for Class {} wrapper! { #[doc(alias = "GInitiallyUnowned")] pub struct InitiallyUnowned(Object); match fn { type_ => || gobject_ffi::g_initially_unowned_get_type(), } } // ManuallyDrop -> The lifetime of the data isn't bound to a Rust value but a GObject. Drop could free data too early. // Pin -> Make sure the pointer Box(1) passed to FFI is always valid and never reallocates. // Box(1) -> Pointer to Box(2), 64 bits large and compatible with FFI. // Box(2) -> Pointer to dyn FnOnce(), 128 bits large and incompatible with FFI (so Box(1) is passed instead). type WeakRefNotifyData = ManuallyDrop>>>; // rustdoc-stripper-ignore-next /// A handle to disconnect a weak ref notify closure. pub struct WeakRefNotify { object: WeakRef, data: WeakRefNotifyData, } unsafe extern "C" fn notify_func(data: ffi::gpointer, _obj: *mut gobject_ffi::GObject) { // SAFETY: Call to FFI with pointers that must be valid due to Pin and lifetimes. // ManuallyDrop and Pin are elided because the pointer only points to Box>. let callback: Box> = Box::from_raw(data as *mut _); // SAFETY: Function must have type FnOnce() due type checks in WeakRefNotify::new. // This callback can only be called once when the object is disposed, to the data can be dropped. (*callback)() } impl WeakRefNotify { fn new(obj: &T, f: F) -> WeakRefNotify { let data: WeakRefNotifyData = ManuallyDrop::new(Box::pin(Box::new(f))); let data_ptr: *const Box = Pin::as_ref(&data).get_ref(); unsafe { // SAFETY: Call to FFI with pointers that must be valid due to Pin and lifetimes. gobject_ffi::g_object_weak_ref( obj.as_ptr() as *mut gobject_ffi::GObject, Some(notify_func), data_ptr as *mut _, ); } let object = obj.downgrade(); WeakRefNotify { object, data } } // rustdoc-stripper-ignore-next /// Try to upgrade this weak reference to a strong reference. /// /// If the stored object was already destroyed then `None` is returned. pub fn upgrade(&self) -> Option { self.object.upgrade() } #[doc(alias = "g_object_weak_unref")] pub fn disconnect(mut self) { // Upgrade the object to make sure it's alive and the callback can't be called while it's disconnected. if let Some(obj) = self.object.upgrade() { let data_ptr: *const Box = Pin::as_ref(&self.data).get_ref(); unsafe { // SAFETY: Call to FFI with pointers that must be valid due to Pin and lifetimes. gobject_ffi::g_object_weak_unref( obj.as_ptr() as *mut gobject_ffi::GObject, Some(notify_func), data_ptr as *mut _, ); // SAFETY: The data can be dropped because references to GObject have been dropped too. // The callback can't be called before or after because it's disconnected and the object is still alive. // This function can't be called anymore either because it consumes self. ManuallyDrop::drop(&mut self.data); } } } } // rustdoc-stripper-ignore-next /// A weak reference to an object. #[derive(Debug)] #[doc(alias = "GWeakRef")] pub struct WeakRef(Pin>, PhantomData<*mut T>); impl WeakRef { // rustdoc-stripper-ignore-next /// Create a new empty weak reference. /// /// `upgrade` will always return `None` until an object is set on it. #[inline] pub fn new() -> WeakRef { unsafe { let mut w = WeakRef(Box::pin(mem::zeroed()), PhantomData); gobject_ffi::g_weak_ref_init( Pin::as_mut(&mut w.0).get_unchecked_mut(), ptr::null_mut(), ); w } } // rustdoc-stripper-ignore-next /// Set this weak reference to the given object. #[doc(alias = "g_weak_ref_set")] #[inline] pub fn set(&self, obj: Option<&T>) { unsafe { gobject_ffi::g_weak_ref_set( mut_override(Pin::as_ref(&self.0).get_ref()), obj.map_or(std::ptr::null_mut(), |obj| { obj.as_object_ref().to_glib_none().0 }), ); } } // rustdoc-stripper-ignore-next /// Try to upgrade this weak reference to a strong reference. /// /// If the stored object was already destroyed or no object was set in this weak reference then /// `None` is returned. #[inline] pub fn upgrade(&self) -> Option { unsafe { let ptr = gobject_ffi::g_weak_ref_get(mut_override(Pin::as_ref(&self.0).get_ref())); if ptr.is_null() { None } else { let obj: Object = from_glib_full(ptr); Some(T::unsafe_from(obj.into())) } } } } impl Drop for WeakRef { #[inline] fn drop(&mut self) { unsafe { gobject_ffi::g_weak_ref_clear(Pin::as_mut(&mut self.0).get_unchecked_mut()); } } } impl Clone for WeakRef { #[inline] fn clone(&self) -> Self { unsafe { let o = self.upgrade(); let mut c = WeakRef(Box::pin(mem::zeroed()), PhantomData); gobject_ffi::g_weak_ref_init( Pin::as_mut(&mut c.0).get_unchecked_mut(), o.to_glib_none().0 as *mut gobject_ffi::GObject, ); c } } } impl Default for WeakRef { #[inline] fn default() -> Self { Self::new() } } unsafe impl Sync for WeakRef {} unsafe impl Send for WeakRef {} impl PartialEq for WeakRef { #[inline] fn eq(&self, other: &Self) -> bool { unsafe { self.0.priv_.p == other.0.priv_.p } } } impl PartialEq for WeakRef { #[inline] fn eq(&self, other: &T) -> bool { unsafe { self.0.priv_.p == other.as_ptr() as *mut std::os::raw::c_void } } } impl PartialOrd for WeakRef { #[inline] fn partial_cmp(&self, other: &Self) -> Option { unsafe { self.0.priv_.p.partial_cmp(&other.0.priv_.p) } } } // rustdoc-stripper-ignore-next /// A weak reference to the object it was created for that can be sent to /// different threads even for object types that don't implement `Send`. /// /// Trying to upgrade the weak reference from another thread than the one /// where it was created on will panic but dropping or cloning can be done /// safely from any thread. #[derive(Debug)] pub struct SendWeakRef(WeakRef, Option); impl SendWeakRef { #[inline] #[deprecated = "Use from() instead. See https://github.com/gtk-rs/gtk-rs-core/issues/1617"] pub fn new() -> SendWeakRef { SendWeakRef(WeakRef::new(), None) } #[inline] pub fn into_weak_ref(self) -> WeakRef { assert!( self.1.is_none() || self.1 == Some(thread_id()), "SendWeakRef dereferenced on a different thread", ); self.0 } } impl ops::Deref for SendWeakRef { type Target = WeakRef; #[inline] fn deref(&self) -> &WeakRef { assert!( self.1.is_none() || self.1 == Some(thread_id()), "SendWeakRef dereferenced on a different thread" ); &self.0 } } // Deriving this gives the wrong trait bounds impl Clone for SendWeakRef { #[inline] fn clone(&self) -> Self { Self(self.0.clone(), self.1) } } impl Default for SendWeakRef { #[inline] fn default() -> Self { #[allow(deprecated)] Self::new() } } impl From> for SendWeakRef { #[inline] fn from(v: WeakRef) -> SendWeakRef { SendWeakRef(v, Some(thread_id())) } } unsafe impl Sync for SendWeakRef {} unsafe impl Send for SendWeakRef {} type TransformFn<'b> = Option Option + Send + Sync + 'static>>; // rustdoc-stripper-ignore-next /// Builder for object property bindings. #[must_use = "The builder must be built to be used"] pub struct BindingBuilder<'a, 'f, 't> { source: &'a ObjectRef, source_property: &'a str, target: &'a ObjectRef, target_property: &'a str, flags: crate::BindingFlags, transform_from: TransformFn<'f>, transform_to: TransformFn<'t>, } impl fmt::Debug for BindingBuilder<'_, '_, '_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("BindingBuilder") .field("source", &self.source) .field("source_property", &self.source_property) .field("target", &self.target) .field("target_property", &self.target_property) .field("flags", &self.flags) .finish() } } impl<'a, 'f, 't> BindingBuilder<'a, 'f, 't> { fn new( source: &'a impl ObjectType, source_property: &'a str, target: &'a impl ObjectType, target_property: &'a str, ) -> Self { Self { source: source.as_object_ref(), source_property, target: target.as_object_ref(), target_property, flags: crate::BindingFlags::DEFAULT, transform_to: None, transform_from: None, } } // rustdoc-stripper-ignore-next /// Transform changed property values from the target object to the source object with the given closure. /// /// This function operates on `glib::Value`s. /// See [`Self::transform_from`] for a version which operates on concrete argument and return types. pub fn transform_from_with_values< F: Fn(&crate::Binding, &Value) -> Option + Send + Sync + 'static, >( self, func: F, ) -> Self { Self { transform_from: Some(Box::new(func)), ..self } } // rustdoc-stripper-ignore-next /// Transform changed property values from the target object to the source object with the given closure. /// /// This function operates on concrete argument and return types. /// See [`Self::transform_from_with_values`] for a version which operates on `glib::Value`s. pub fn transform_from< S: FromValue<'f>, T: Into, F: Fn(&'f crate::Binding, S) -> Option + Send + Sync + 'static, >( self, func: F, ) -> Self { Self { transform_from: Some(Box::new(move |binding, from_value| { let from_value = from_value.get().expect("Wrong value type"); func(binding, from_value).map(|r| r.into()) })), ..self } } // rustdoc-stripper-ignore-next /// Transform changed property values from the source object to the target object with the given closure. /// /// This function operates on `glib::Value`s. /// See [`Self::transform_to`] for a version which operates on concrete argument and return types. pub fn transform_to_with_values< F: Fn(&crate::Binding, &Value) -> Option + Send + Sync + 'static, >( self, func: F, ) -> Self { Self { transform_to: Some(Box::new(func)), ..self } } // rustdoc-stripper-ignore-next /// Transform changed property values from the source object to the target object with the given closure. /// /// This function operates on concrete argument and return types. /// See [`Self::transform_to_with_values`] for a version which operates on `glib::Value`s. pub fn transform_to< S: FromValue<'t>, T: Into, F: Fn(&'t crate::Binding, S) -> Option + Send + Sync + 'static, >( self, func: F, ) -> Self { Self { transform_to: Some(Box::new(move |binding, from_value| { let from_value = from_value.get().expect("Wrong value type"); func(binding, from_value).map(|r| r.into()) })), ..self } } // rustdoc-stripper-ignore-next /// Bind the properties with the given flags. pub fn flags(self, flags: crate::BindingFlags) -> Self { Self { flags, ..self } } // rustdoc-stripper-ignore-next /// Set the binding flags to [`BIDIRECTIONAL`][crate::BindingFlags::BIDIRECTIONAL]. pub fn bidirectional(mut self) -> Self { self.flags |= crate::BindingFlags::BIDIRECTIONAL; self } // rustdoc-stripper-ignore-next /// Set the binding flags to [`SYNC_CREATE`][crate::BindingFlags::SYNC_CREATE]. pub fn sync_create(mut self) -> Self { self.flags |= crate::BindingFlags::SYNC_CREATE; self } // rustdoc-stripper-ignore-next /// Set the binding flags to [`INVERT_BOOLEAN`][crate::BindingFlags::INVERT_BOOLEAN]. pub fn invert_boolean(mut self) -> Self { self.flags |= crate::BindingFlags::INVERT_BOOLEAN; self } // rustdoc-stripper-ignore-next /// Establish the property binding. /// /// # Panics /// This panics if the provided properties do not exist. #[track_caller] pub fn build(self) -> crate::Binding { unsafe extern "C" fn transform_to_trampoline( binding: *mut gobject_ffi::GBinding, from_value: *const gobject_ffi::GValue, to_value: *mut gobject_ffi::GValue, user_data: ffi::gpointer, ) -> ffi::gboolean { let transform_data = &*(user_data as *const (TransformFn, TransformFn, crate::ParamSpec, crate::ParamSpec)); match (transform_data.0.as_ref().unwrap())( &from_glib_borrow(binding), &*(from_value as *const Value), ) { None => false, Some(res) => { assert!( res.type_().is_a(transform_data.3.value_type()), "Target property {} expected type {} but transform_to function returned {}", transform_data.3.name(), transform_data.3.value_type(), res.type_() ); *to_value = res.into_raw(); true } } .into_glib() } unsafe extern "C" fn transform_from_trampoline( binding: *mut gobject_ffi::GBinding, from_value: *const gobject_ffi::GValue, to_value: *mut gobject_ffi::GValue, user_data: ffi::gpointer, ) -> ffi::gboolean { let transform_data = &*(user_data as *const (TransformFn, TransformFn, crate::ParamSpec, crate::ParamSpec)); match (transform_data.1.as_ref().unwrap())( &from_glib_borrow(binding), &*(from_value as *const Value), ) { None => false, Some(res) => { assert!( res.type_().is_a(transform_data.2.value_type()), "Source property {} expected type {} but transform_from function returned {}", transform_data.2.name(), transform_data.2.value_type(), res.type_() ); *to_value = res.into_raw(); true } } .into_glib() } unsafe extern "C" fn free_transform_data(data: ffi::gpointer) { let _ = Box::from_raw( data as *mut (TransformFn, TransformFn, crate::ParamSpec, crate::ParamSpec), ); } unsafe { let source = Object { inner: TypedObjectRef::new(self.source.clone()), phantom: std::marker::PhantomData, }; let target = Object { inner: TypedObjectRef::new(self.target.clone()), phantom: std::marker::PhantomData, }; let source_property = source .find_property(self.source_property) .unwrap_or_else(|| { panic!( "Source property {} on type {} not found", self.source_property, source.type_() ); }); let target_property = target .find_property(self.target_property) .unwrap_or_else(|| { panic!( "Target property {} on type {} not found", self.target_property, target.type_() ); }); let source_property_name = source_property.name().as_ptr(); let target_property_name = target_property.name().as_ptr(); let have_transform_to = self.transform_to.is_some(); let have_transform_from = self.transform_from.is_some(); let transform_data = if have_transform_to || have_transform_from { Box::into_raw(Box::new(( self.transform_to, self.transform_from, source_property, target_property, ))) } else { ptr::null_mut() }; from_glib_none(gobject_ffi::g_object_bind_property_full( source.to_glib_none().0, source_property_name as *const _, target.to_glib_none().0, target_property_name as *const _, self.flags.into_glib(), if have_transform_to { Some(transform_to_trampoline) } else { None }, if have_transform_from { Some(transform_from_trampoline) } else { None }, transform_data as ffi::gpointer, if transform_data.is_null() { None } else { Some(free_transform_data) }, )) } } } // rustdoc-stripper-ignore-next /// Class struct of type `T`. #[repr(transparent)] pub struct Class(T::GlibClassType); impl Class { // rustdoc-stripper-ignore-next /// Get the type id for this class. /// /// This is not equivalent to `T::static_type()` but is the type of the subclass of `T` where /// this class belongs to. #[doc(alias = "get_type")] #[inline] pub fn type_(&self) -> Type { unsafe { // This also works for interfaces because they also have the type // as the first struct field. let klass = self as *const _ as *const gobject_ffi::GTypeClass; from_glib((*klass).g_type) } } // rustdoc-stripper-ignore-next /// Casts this class to a reference to a parent type's class. #[inline] pub fn upcast_ref(&self) -> &Class where T: IsA, { unsafe { let klass = self as *const _ as *const Class; &*klass } } // rustdoc-stripper-ignore-next /// Casts this class to a mutable reference to a parent type's class. #[inline] pub fn upcast_ref_mut(&mut self) -> &mut Class where T: IsA, { unsafe { let klass = self as *mut _ as *mut Class; &mut *klass } } // rustdoc-stripper-ignore-next /// Casts this class to a reference to a child type's class or /// fails if this class is not implementing the child class. #[inline] pub fn downcast_ref>(&self) -> Option<&Class> { if !self.type_().is_a(U::static_type()) { return None; } unsafe { let klass = self as *const _ as *const Class; Some(&*klass) } } // rustdoc-stripper-ignore-next /// Casts this class to a mutable reference to a child type's class or /// fails if this class is not implementing the child class. #[inline] pub fn downcast_ref_mut>(&mut self) -> Option<&mut Class> { if !self.type_().is_a(U::static_type()) { return None; } unsafe { let klass = self as *mut _ as *mut Class; Some(&mut *klass) } } // rustdoc-stripper-ignore-next /// Gets the class struct for `Self` of `type_`. /// /// This will return `None` if `type_` is not a subclass of `Self`. #[doc(alias = "g_type_class_ref")] #[inline] pub fn from_type(type_: Type) -> Option> { if !type_.is_a(T::static_type()) { return None; } unsafe { let ptr = gobject_ffi::g_type_class_ref(type_.into_glib()); if ptr.is_null() { None } else { Some(ClassRef( ptr::NonNull::new_unchecked(ptr as *mut Self), true, PhantomData, )) } } } // rustdoc-stripper-ignore-next /// Gets the parent class struct, if any. #[doc(alias = "g_type_class_peek_parent")] #[inline] pub fn parent(&self) -> Option> { unsafe { let ptr = gobject_ffi::g_type_class_peek_parent(&self.0 as *const _ as *mut _); if ptr.is_null() { None } else { Some(ClassRef( ptr::NonNull::new_unchecked(ptr as *mut Self), false, PhantomData, )) } } } } unsafe impl Send for Class {} unsafe impl Sync for Class {} impl AsRef for Class { #[inline] fn as_ref(&self) -> &T::GlibClassType { &self.0 } } impl AsMut for Class { #[inline] fn as_mut(&mut self) -> &mut T::GlibClassType { &mut self.0 } } // rustdoc-stripper-ignore-next /// Reference to the class struct of type `T`. #[derive(Debug)] pub struct ClassRef<'a, T: IsClass>(ptr::NonNull>, bool, PhantomData<&'a ()>); impl ops::Deref for ClassRef<'_, T> { type Target = Class; #[inline] fn deref(&self) -> &Class { unsafe { self.0.as_ref() } } } impl Drop for ClassRef<'_, T> { #[inline] fn drop(&mut self) { if self.1 { unsafe { gobject_ffi::g_type_class_unref(self.0.as_ptr() as *mut _); } } } } unsafe impl Send for ClassRef<'_, T> {} unsafe impl Sync for ClassRef<'_, T> {} // This should require Self: IsA, but that seems to cause a cycle error pub unsafe trait ParentClassIs: IsClass { type Parent: IsClass; } // rustdoc-stripper-ignore-next /// Automatically implemented by `ObjectSubclass` variants of /// [`wrapper!`][crate::wrapper!] pub unsafe trait ObjectSubclassIs: IsClass { type Subclass: ObjectSubclass; } impl ops::Deref for Class { type Target = Class; #[inline] fn deref(&self) -> &Self::Target { unsafe { let klass = self as *const _ as *const Self::Target; &*klass } } } impl ops::DerefMut for Class { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { unsafe { let klass = self as *mut _ as *mut Self::Target; &mut *klass } } } // rustdoc-stripper-ignore-next /// Trait implemented by class types. pub unsafe trait IsClass: ObjectType {} // rustdoc-stripper-ignore-next /// Interface struct of type `T` for some type. #[repr(transparent)] pub struct Interface(T::GlibClassType); impl Interface { // rustdoc-stripper-ignore-next /// Get the type id for this interface. /// /// This is equivalent to `T::static_type()`. #[doc(alias = "get_type")] #[inline] pub fn type_(&self) -> Type { unsafe { let klass = self as *const _ as *const gobject_ffi::GTypeInterface; from_glib((*klass).g_type) } } // rustdoc-stripper-ignore-next /// Get the type id for the instance type of this interface. /// /// This is not equivalent to `T::static_type()` but is the type id of the type this specific /// interface belongs to. #[doc(alias = "get_instance_type")] #[inline] pub fn instance_type(&self) -> Type { unsafe { // This also works for interfaces because they also have the type // as the first struct field. let klass = self as *const _ as *const gobject_ffi::GTypeInterface; from_glib((*klass).g_instance_type) } } // rustdoc-stripper-ignore-next /// Gets the interface struct for `Self` of `klass`. /// /// This will return `None` if `klass` is not implementing `Self`. #[inline] pub fn from_class(klass: &Class) -> Option> { if !klass.type_().is_a(T::static_type()) { return None; } unsafe { let ptr = gobject_ffi::g_type_interface_peek( &klass.0 as *const _ as *mut _, T::static_type().into_glib(), ); if ptr.is_null() { None } else { Some(InterfaceRef( ptr::NonNull::new_unchecked(ptr as *mut Self), false, PhantomData, )) } } } // rustdoc-stripper-ignore-next /// Gets the default interface struct for `Self`. /// /// This will return `None` if `type_` is not an interface. #[inline] pub fn from_type(type_: Type) -> Option> { if !type_.is_a(Type::INTERFACE) { return None; } unsafe { let ptr = gobject_ffi::g_type_default_interface_ref(T::static_type().into_glib()); if ptr.is_null() { None } else { Some(InterfaceRef( ptr::NonNull::new_unchecked(ptr as *mut Self), true, PhantomData, )) } } } // rustdoc-stripper-ignore-next /// Gets the default interface struct for `Self`. #[doc(alias = "g_type_default_interface_ref")] #[allow(clippy::should_implement_trait)] #[inline] pub fn default() -> InterfaceRef<'static, T> { unsafe { let ptr = gobject_ffi::g_type_default_interface_ref(T::static_type().into_glib()); debug_assert!(!ptr.is_null()); InterfaceRef( ptr::NonNull::new_unchecked(ptr as *mut Self), true, PhantomData, ) } } // rustdoc-stripper-ignore-next /// Gets the parent interface struct, if any. /// /// This returns the parent interface if a parent type of the instance type also implements the /// interface. #[doc(alias = "g_type_interface_peek_parent")] #[inline] pub fn parent(&self) -> Option> { unsafe { let ptr = gobject_ffi::g_type_interface_peek_parent(&self.0 as *const _ as *mut _); if ptr.is_null() { None } else { Some(InterfaceRef( ptr::NonNull::new_unchecked(ptr as *mut Self), false, PhantomData, )) } } } } impl + IsInterface> Interface { // rustdoc-stripper-ignore-next /// Check if this interface has a property `property_name` of the given `type_`. /// /// If no type is provided then only the existence of the property is checked. pub fn has_property(&self, property_name: &str, type_: Option) -> bool { let ptype = self.property_type(property_name); match (ptype, type_) { (None, _) => false, (Some(_), None) => true, (Some(ptype), Some(type_)) => ptype == type_, } } // rustdoc-stripper-ignore-next /// Get the type of the property `property_name` of this interface. /// /// This returns `None` if the property does not exist. #[doc(alias = "get_property_type")] pub fn property_type(&self, property_name: &str) -> Option { self.find_property(property_name) .map(|pspec| pspec.value_type()) } // rustdoc-stripper-ignore-next /// Get the [`ParamSpec`](crate::ParamSpec) of the property `property_name` of this interface. #[doc(alias = "g_object_interface_find_property")] pub fn find_property(&self, property_name: &str) -> Option { unsafe { let interface = self as *const _ as *const gobject_ffi::GTypeInterface; from_glib_none(gobject_ffi::g_object_interface_find_property( interface as *mut _, property_name.to_glib_none().0, )) } } // rustdoc-stripper-ignore-next /// Return all [`ParamSpec`](crate::ParamSpec) of the properties of this interface. #[doc(alias = "g_object_interface_list_properties")] pub fn list_properties(&self) -> PtrSlice { unsafe { let interface = self as *const _ as *const gobject_ffi::GTypeInterface; let mut n_properties = 0; let props = gobject_ffi::g_object_interface_list_properties( interface as *mut _, &mut n_properties, ); PtrSlice::from_glib_container_num(props, n_properties as usize, true) } } } unsafe impl Send for Interface {} unsafe impl Sync for Interface {} impl AsRef for Interface { #[inline] fn as_ref(&self) -> &T::GlibClassType { &self.0 } } impl AsMut for Interface { #[inline] fn as_mut(&mut self) -> &mut T::GlibClassType { &mut self.0 } } // rustdoc-stripper-ignore-next /// Reference to a class struct of type `T`. #[derive(Debug)] pub struct InterfaceRef<'a, T: IsInterface>(ptr::NonNull>, bool, PhantomData<&'a ()>); impl Drop for InterfaceRef<'_, T> { #[inline] fn drop(&mut self) { if self.1 { unsafe { gobject_ffi::g_type_default_interface_unref(self.0.as_ptr() as *mut _); } } } } impl ops::Deref for InterfaceRef<'_, T> { type Target = Interface; #[inline] fn deref(&self) -> &Interface { unsafe { self.0.as_ref() } } } unsafe impl Send for InterfaceRef<'_, T> {} unsafe impl Sync for InterfaceRef<'_, T> {} // rustdoc-stripper-ignore-next /// Trait implemented by interface types. pub unsafe trait IsInterface: ObjectType {} // rustdoc-stripper-ignore-next /// `Value` type checker for object types. pub struct ObjectValueTypeChecker(std::marker::PhantomData); unsafe impl crate::value::ValueTypeChecker for ObjectValueTypeChecker { type Error = crate::value::ValueTypeMismatchOrNoneError; fn check(value: &Value) -> Result<(), Self::Error> { // g_type_check_value_holds() only checks for the GType of the GValue. This might be // initialized to a parent type of the expected type and would then fail while it's // still valid to retrieve the value. unsafe { let requested_type = T::static_type().into_glib(); let type_ = value.inner.g_type; // Direct match or value type is a subtype of the requested type. if gobject_ffi::g_type_is_a(type_, requested_type) != ffi::GFALSE { let obj = gobject_ffi::g_value_get_object(&value.inner); if obj.is_null() { return Err(Self::Error::UnexpectedNone); } else { return Ok(()); } } // If the value type is not a GObject or subtype of GObject then there's a mismatch. if gobject_ffi::g_type_is_a(type_, gobject_ffi::G_TYPE_OBJECT) == ffi::GFALSE { return Err(crate::value::ValueTypeMismatchError::new( Type::from_glib(type_), T::static_type(), ) .into()); } // Otherwise peek at the actual object and its concrete type. let obj = gobject_ffi::g_value_get_object(&value.inner); // Allow any types if the object is NULL. if obj.is_null() { return Err(Self::Error::UnexpectedNone); } let type_ = (*(*obj).g_type_instance.g_class).g_type; // Direct match or concrete type is a subtype of the requested type. if gobject_ffi::g_type_is_a(type_, requested_type) != ffi::GFALSE { Ok(()) } else { Err(crate::value::ValueTypeMismatchError::new( Type::from_glib(type_), T::static_type(), ) .into()) } } } } // rustdoc-stripper-ignore-next /// Borrowed reference to an object of type `T`. /// /// This dereferences into `&T`. #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] pub struct BorrowedObject<'a, T> { ptr: ptr::NonNull, phantom: PhantomData<&'a T>, } unsafe impl Send for BorrowedObject<'_, T> {} unsafe impl Sync for BorrowedObject<'_, T> {} impl<'a, T: ObjectType> BorrowedObject<'a, T> { // rustdoc-stripper-ignore-next /// Creates a new borrowed object reference. /// /// # SAFETY: /// /// The pointer needs to be valid for at least the lifetime `'a`. #[inline] pub unsafe fn new(ptr: *mut T::GlibType) -> BorrowedObject<'a, T> { BorrowedObject { ptr: ptr::NonNull::new_unchecked(ptr as *mut _), phantom: PhantomData, } } // rustdoc-stripper-ignore-next /// Downgrade to a weak reference. #[inline] pub fn downgrade(&self) -> ::Weak where T: crate::clone::Downgrade, { ::downgrade(self) } } impl ops::Deref for BorrowedObject<'_, T> { type Target = T; #[inline] fn deref(&self) -> &T { unsafe { &*(&self.ptr as *const _ as *const T) } } } impl AsRef for BorrowedObject<'_, T> { #[inline] fn as_ref(&self) -> &T { unsafe { &*(&self.ptr as *const _ as *const T) } } } impl PartialEq for BorrowedObject<'_, T> { #[inline] fn eq(&self, other: &T) -> bool { ::eq(self, other) } } impl PartialOrd for BorrowedObject<'_, T> { #[inline] fn partial_cmp(&self, other: &T) -> Option { ::partial_cmp(self, other) } } impl crate::clone::Downgrade for BorrowedObject<'_, T> { type Weak = ::Weak; #[inline] fn downgrade(&self) -> Self::Weak { ::downgrade(self) } } #[cfg(test)] mod tests { use std::{ cell::Cell, rc::Rc, sync::{ atomic::{AtomicBool, Ordering}, Arc, }, }; use super::*; #[test] fn new() { let obj: Object = Object::new(); drop(obj); } #[test] fn data() { let obj: Object = Object::new(); unsafe { obj.set_data::("foo", "hello".into()); let data = obj.data::("foo").unwrap(); assert_eq!(data.as_ref(), "hello"); let data2 = obj.steal_data::("foo").unwrap(); assert_eq!(data2, "hello"); } } #[test] fn weak_ref() { let obj: Object = Object::new(); let weakref: WeakRef = WeakRef::new(); weakref.set(Some(&obj)); assert!(weakref.upgrade().is_some()); weakref.set(None); assert!(weakref.upgrade().is_none()); let weakref = WeakRef::new(); weakref.set(Some(&obj)); assert!(weakref.upgrade().is_some()); drop(obj); assert!(weakref.upgrade().is_none()); } #[test] fn weak_ref_notify() { let obj: Object = Object::new(); let handle = obj.add_weak_ref_notify(|| { unreachable!(); }); handle.disconnect(); let called = Arc::new(AtomicBool::new(false)); let called_weak = Arc::downgrade(&called); let handle = obj.add_weak_ref_notify(move || { called_weak.upgrade().unwrap().store(true, Ordering::SeqCst); }); drop(obj); assert!(called.load(Ordering::SeqCst)); handle.disconnect(); let obj: Object = Object::new(); let called = Arc::new(AtomicBool::new(false)); let called_weak = Arc::downgrade(&called); obj.add_weak_ref_notify(move || { called_weak.upgrade().unwrap().store(true, Ordering::SeqCst); }); drop(obj); assert!(called.load(Ordering::SeqCst)); let obj: Object = Object::new(); let called = Rc::new(Cell::new(false)); let called_weak = Rc::downgrade(&called); obj.add_weak_ref_notify_local(move || { called_weak.upgrade().unwrap().set(true); }); drop(obj); assert!(called.get()); } #[test] fn test_value() { let obj1: Object = Object::new(); let v = obj1.to_value(); let obj2 = v.get::<&Object>().unwrap(); assert_eq!(obj1.as_ptr(), obj2.as_ptr()); } #[test] fn test_borrow_hashing() { let mut m = std::collections::HashSet::new(); let boxed_object = crate::BoxedAnyObject::new(""); m.insert(boxed_object.clone()); let object: &Object = std::borrow::Borrow::borrow(&boxed_object); assert_eq!(m.get(object), Some(&boxed_object)); } } glib-0.20.9/src/param_spec.rs000064400000000000000000002177311046102023000141130ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ char::CharTryFromError, ffi::CStr, num::{NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU32, NonZeroU64, NonZeroU8}, path::{Path, PathBuf}, }; use crate::{ ffi, gobject_ffi, object::{Interface, InterfaceRef, IsClass, IsInterface, ObjectClass}, prelude::*, translate::*, utils::is_canonical_pspec_name, Object, ParamFlags, Type, Value, }; // Can't use get_type here as this is not a boxed type but another fundamental type wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpec")] pub struct ParamSpec(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr), unref => |ptr| gobject_ffi::g_param_spec_unref(ptr), } } impl StaticType for ParamSpec { #[inline] fn static_type() -> Type { unsafe { from_glib(gobject_ffi::G_TYPE_PARAM) } } } #[doc(hidden)] impl crate::value::ValueType for ParamSpec { type Type = ParamSpec; } #[doc(hidden)] impl crate::value::ValueTypeOptional for ParamSpec {} #[doc(hidden)] unsafe impl<'a> crate::value::FromValue<'a> for ParamSpec { type Checker = crate::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a crate::Value) -> Self { let ptr = gobject_ffi::g_value_dup_param(value.to_glib_none().0); debug_assert!(!ptr.is_null()); from_glib_full(ptr) } } #[doc(hidden)] unsafe impl<'a> crate::value::FromValue<'a> for &'a ParamSpec { type Checker = crate::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a crate::Value) -> Self { debug_assert_eq!( std::mem::size_of::(), std::mem::size_of::() ); let value = &*(value as *const crate::Value as *const crate::gobject_ffi::GValue); let ptr = &value.data[0].v_pointer as *const crate::ffi::gpointer as *const *const gobject_ffi::GParamSpec; debug_assert!(!(*ptr).is_null()); &*(ptr as *const ParamSpec) } } #[doc(hidden)] impl crate::value::ToValue for ParamSpec { fn to_value(&self) -> crate::Value { unsafe { let mut value = crate::Value::from_type_unchecked(ParamSpec::static_type()); gobject_ffi::g_value_take_param(value.to_glib_none_mut().0, self.to_glib_full()); value } } fn value_type(&self) -> crate::Type { ParamSpec::static_type() } } #[doc(hidden)] impl From for crate::Value { #[inline] fn from(s: ParamSpec) -> Self { unsafe { let mut value = crate::Value::from_type_unchecked(ParamSpec::static_type()); gobject_ffi::g_value_take_param(value.to_glib_none_mut().0, s.into_glib_ptr()); value } } } #[doc(hidden)] impl crate::value::ToValueOptional for ParamSpec { fn to_value_optional(s: Option<&Self>) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { gobject_ffi::g_value_take_param(value.to_glib_none_mut().0, s.to_glib_full()); } value } } impl AsRef for ParamSpec { #[inline] fn as_ref(&self) -> &ParamSpec { self } } unsafe impl Send for ParamSpec {} unsafe impl Sync for ParamSpec {} impl ParamSpec { pub fn downcast(self) -> Result { unsafe { if self.type_() == T::static_type() { Ok(from_glib_full(self.into_glib_ptr())) } else { Err(self) } } } pub fn downcast_ref(&self) -> Option<&T> { unsafe { if self.type_() == T::static_type() { Some(&*(self as *const ParamSpec as *const T)) } else { None } } } #[doc(alias = "get_type")] #[inline] pub fn type_(&self) -> Type { unsafe { from_glib( (*(*(>::to_glib_none(self).0)) .g_type_instance .g_class) .g_type, ) } } #[inline] pub fn is(&self) -> bool { self.type_().is_a(T::static_type()) } #[doc(alias = "get_value_type")] #[inline] pub fn value_type(&self) -> crate::Type { unsafe { from_glib((*(>::to_glib_none(self).0)).value_type) } } #[cfg(feature = "v2_74")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))] #[doc(alias = "g_param_value_is_valid")] #[inline] pub fn value_is_valid(&self, value: &Value) -> bool { unsafe { from_glib(gobject_ffi::g_param_value_is_valid( self.to_glib_none().0, value.to_glib_none().0, )) } } #[doc(alias = "get_owner_type")] #[inline] pub fn owner_type(&self) -> crate::Type { unsafe { from_glib((*(>::to_glib_none(self).0)).owner_type) } } #[doc(alias = "get_flags")] #[inline] pub fn flags(&self) -> ParamFlags { unsafe { from_glib((*(>::to_glib_none(self).0)).flags) } } #[doc(alias = "g_param_spec_get_blurb")] #[doc(alias = "get_blurb")] #[inline] pub fn blurb(&self) -> Option<&str> { unsafe { let ptr = gobject_ffi::g_param_spec_get_blurb(self.to_glib_none().0); if ptr.is_null() { None } else { CStr::from_ptr(ptr).to_str().ok() } } } #[doc(alias = "g_param_spec_get_default_value")] #[doc(alias = "get_default_value")] #[inline] pub fn default_value(&self) -> &Value { unsafe { &*(gobject_ffi::g_param_spec_get_default_value(self.to_glib_none().0) as *const crate::Value) } } #[doc(alias = "g_param_spec_get_name")] #[doc(alias = "get_name")] #[inline] pub fn name<'a>(&self) -> &'a str { unsafe { CStr::from_ptr(gobject_ffi::g_param_spec_get_name(self.to_glib_none().0)) .to_str() .unwrap() } } #[doc(alias = "g_param_spec_get_name_quark")] #[doc(alias = "get_name_quark")] #[inline] pub fn name_quark(&self) -> crate::Quark { unsafe { from_glib(gobject_ffi::g_param_spec_get_name_quark( self.to_glib_none().0, )) } } // rustdoc-stripper-ignore-next /// Returns the nickname of this `ParamSpec`. /// /// If this `ParamSpec` does not have a nickname, the nickname of its redirect target is returned if it has one. /// Otherwise, `self.name()` is returned. #[doc(alias = "g_param_spec_get_nick")] #[doc(alias = "get_nick")] #[inline] pub fn nick(&self) -> &str { unsafe { CStr::from_ptr(gobject_ffi::g_param_spec_get_nick(self.to_glib_none().0)) .to_str() .unwrap() } } //pub fn get_qdata(&self, quark: /*Ignored*/glib::Quark) -> /*Unimplemented*/Option { // unsafe { TODO: call gobject_ffi::g_param_spec_get_qdata() } //} #[doc(alias = "g_param_spec_get_redirect_target")] #[doc(alias = "get_redirect_target")] #[inline] pub fn redirect_target(&self) -> Option { unsafe { from_glib_none(gobject_ffi::g_param_spec_get_redirect_target( self.to_glib_none().0, )) } } //pub fn set_qdata(&self, quark: /*Ignored*/glib::Quark, data: Option) { // unsafe { TODO: call gobject_ffi::g_param_spec_set_qdata() } //} //pub fn set_qdata_full(&self, quark: /*Ignored*/glib::Quark, data: Option, destroy: /*Unknown conversion*//*Unimplemented*/DestroyNotify) { // unsafe { TODO: call gobject_ffi::g_param_spec_set_qdata_full() } //} //pub fn steal_qdata(&self, quark: /*Ignored*/glib::Quark) -> /*Unimplemented*/Option { // unsafe { TODO: call gobject_ffi::g_param_spec_steal_qdata() } //} #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] #[doc(alias = "g_param_spec_is_valid_name")] #[inline] pub fn is_valid_name(name: &str) -> bool { unsafe { from_glib(gobject_ffi::g_param_spec_is_valid_name( name.to_glib_none().0, )) } } } pub unsafe trait ParamSpecType: StaticType + FromGlibPtrFull<*mut gobject_ffi::GParamSpec> + 'static { } macro_rules! define_param_spec { ($rust_type:ident, $ffi_type:path, $type_name:literal) => { impl StaticType for $rust_type { #[inline] fn static_type() -> Type { // Instead of using the direct reference to the `g_param_spec_types` table, we // use `g_type_from_name` to query for each of the param spec types. This is // because rust currently has issues properly linking variables from external // libraries without using a `#[link]` attribute. unsafe { from_glib(gobject_ffi::g_type_from_name(concat!($type_name, "\0").as_ptr() as *const _)) } } } #[doc(hidden)] impl crate::value::ValueType for $rust_type { type Type = $rust_type; } #[doc(hidden)] impl crate::value::ValueTypeOptional for $rust_type {} #[doc(hidden)] unsafe impl<'a> crate::value::FromValue<'a> for $rust_type { type Checker = $crate::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a crate::Value) -> Self { let ptr = gobject_ffi::g_value_dup_param(value.to_glib_none().0); debug_assert!(!ptr.is_null()); from_glib_full(ptr as *mut $ffi_type) } } #[doc(hidden)] unsafe impl<'a> crate::value::FromValue<'a> for &'a $rust_type { type Checker = crate::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a crate::Value) -> Self { debug_assert_eq!(std::mem::size_of::(), std::mem::size_of::()); let value = &*(value as *const crate::Value as *const crate::gobject_ffi::GValue); let ptr = &value.data[0].v_pointer as *const crate::ffi::gpointer as *const *const gobject_ffi::GParamSpec; debug_assert!(!(*ptr).is_null()); &*(ptr as *const $rust_type) } } #[doc(hidden)] impl crate::value::ToValue for $rust_type { fn to_value(&self) -> crate::Value { unsafe { let mut value = crate::Value::from_type_unchecked($rust_type::static_type()); gobject_ffi::g_value_take_param(value.to_glib_none_mut().0, $crate::translate::ToGlibPtr::<*const $ffi_type>::to_glib_full(self) as *mut _); value } } fn value_type(&self) -> crate::Type { $rust_type::static_type() } } #[doc(hidden)] impl From<$rust_type> for crate::Value { #[inline] fn from(s: $rust_type) -> Self { unsafe { let mut value = crate::Value::from_type_unchecked($rust_type::static_type()); gobject_ffi::g_value_take_param( value.to_glib_none_mut().0, $crate::translate::IntoGlibPtr::<*mut gobject_ffi::GParamSpec>::into_glib_ptr(s), ); value } } } #[doc(hidden)] impl crate::value::ToValueOptional for $rust_type { fn to_value_optional(s: Option<&Self>) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { gobject_ffi::g_value_take_param(value.to_glib_none_mut().0, $crate::translate::ToGlibPtr::<*const $ffi_type>::to_glib_full(&s) as *mut _); } value } } unsafe impl Send for $rust_type {} unsafe impl Sync for $rust_type {} impl std::ops::Deref for $rust_type { type Target = ParamSpec; #[inline] fn deref(&self) -> &Self::Target { unsafe { &*(self as *const $rust_type as *const ParamSpec) } } } unsafe impl ParamSpecType for $rust_type {} #[doc(hidden)] impl<'a> ToGlibPtr<'a, *const gobject_ffi::GParamSpec> for $rust_type { type Storage = std::marker::PhantomData<&'a $crate::shared::Shared<$ffi_type, $rust_type>>; #[inline] fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *const gobject_ffi::GParamSpec, Self> { let stash = $crate::translate::ToGlibPtr::<*const $ffi_type>::to_glib_none(self); $crate::translate::Stash(stash.0 as *const _, stash.1) } #[inline] fn to_glib_full(&self) -> *const gobject_ffi::GParamSpec { $crate::translate::ToGlibPtr::<*const $ffi_type>::to_glib_full(self) as *const _ } } #[doc(hidden)] impl<'a> ToGlibPtr<'a, *mut gobject_ffi::GParamSpec> for $rust_type { type Storage = std::marker::PhantomData<&'a $crate::shared::Shared<$ffi_type, $rust_type>>; #[inline] fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *mut gobject_ffi::GParamSpec, Self> { let stash = $crate::translate::ToGlibPtr::<*mut $ffi_type>::to_glib_none(self); $crate::translate::Stash(stash.0 as *mut _, stash.1) } #[inline] fn to_glib_full(&self) -> *mut gobject_ffi::GParamSpec { $crate::translate::ToGlibPtr::<*mut $ffi_type>::to_glib_full(self) as *mut _ } } #[doc(hidden)] impl IntoGlibPtr<*mut gobject_ffi::GParamSpec> for $rust_type { #[inline] unsafe fn into_glib_ptr(self) -> *mut gobject_ffi::GParamSpec { let s = std::mem::ManuallyDrop::new(self); s.to_glib_none().0 } } #[doc(hidden)] impl IntoGlibPtr<*const gobject_ffi::GParamSpec> for $rust_type { #[inline] unsafe fn into_glib_ptr(self) -> *const gobject_ffi::GParamSpec { let s = std::mem::ManuallyDrop::new(self); s.to_glib_none().0 } } #[doc(hidden)] impl FromGlibPtrNone<*const gobject_ffi::GParamSpec> for $rust_type { #[inline] unsafe fn from_glib_none(ptr: *const gobject_ffi::GParamSpec) -> Self { from_glib_none(ptr as *const $ffi_type) } } #[doc(hidden)] impl FromGlibPtrNone<*mut gobject_ffi::GParamSpec> for $rust_type { #[inline] unsafe fn from_glib_none(ptr: *mut gobject_ffi::GParamSpec) -> Self { from_glib_none(ptr as *mut $ffi_type) } } #[doc(hidden)] impl FromGlibPtrBorrow<*const gobject_ffi::GParamSpec> for $rust_type { #[inline] unsafe fn from_glib_borrow(ptr: *const gobject_ffi::GParamSpec) -> Borrowed { from_glib_borrow(ptr as *const $ffi_type) } } #[doc(hidden)] impl FromGlibPtrBorrow<*mut gobject_ffi::GParamSpec> for $rust_type { #[inline] unsafe fn from_glib_borrow(ptr: *mut gobject_ffi::GParamSpec) -> Borrowed { from_glib_borrow(ptr as *mut $ffi_type) } } #[doc(hidden)] impl FromGlibPtrFull<*mut gobject_ffi::GParamSpec> for $rust_type { #[inline] unsafe fn from_glib_full(ptr: *mut gobject_ffi::GParamSpec) -> Self { from_glib_full(ptr as *mut $ffi_type) } } impl $rust_type { #[inline] pub fn upcast(self) -> ParamSpec { unsafe { from_glib_full(IntoGlibPtr::<*mut $ffi_type>::into_glib_ptr(self) as *mut gobject_ffi::GParamSpec) } } #[inline] pub fn upcast_ref(&self) -> &ParamSpec { &*self } } impl AsRef for $rust_type { #[inline] fn as_ref(&self) -> &ParamSpec { &self } } }; } macro_rules! define_param_spec_default { ($rust_type:ident, $ffi_type:path, $value_type:ty, $from_glib:expr) => { impl $rust_type { #[inline] #[allow(clippy::redundant_closure_call)] pub fn default_value(&self) -> $value_type { unsafe { let ptr = $crate::translate::ToGlibPtr::<*const $ffi_type>::to_glib_none(self).0; $from_glib((*ptr).default_value) } } } }; } macro_rules! define_param_spec_min_max { ($rust_type:ident, $ffi_type:path, $value_type:ty) => { impl $rust_type { #[inline] pub fn minimum(&self) -> $value_type { unsafe { let ptr = $crate::translate::ToGlibPtr::<*const $ffi_type>::to_glib_none(self).0; (*ptr).minimum } } #[inline] pub fn maximum(&self) -> $value_type { unsafe { let ptr = $crate::translate::ToGlibPtr::<*const $ffi_type>::to_glib_none(self).0; (*ptr).maximum } } } }; } macro_rules! define_param_spec_numeric { ($rust_type:ident, $ffi_type:path, $value_type:ty, $type_name:literal, $ffi_fun:ident) => { define_param_spec!($rust_type, $ffi_type, $type_name); define_param_spec_default!($rust_type, $ffi_type, $value_type, |x| x); define_param_spec_min_max!($rust_type, $ffi_type, $value_type); impl $rust_type { unsafe fn new_unchecked<'a>( name: &str, nick: impl Into>, blurb: impl Into>, minimum: $value_type, maximum: $value_type, default_value: $value_type, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_none(gobject_ffi::$ffi_fun( name.to_glib_none().0, nick.into().to_glib_none().0, blurb.into().to_glib_none().0, minimum, maximum, default_value, flags.into_glib(), )) } } } }; } /// A trait implemented by the various [`ParamSpec`] builder types. /// /// It is useful for providing a builder pattern for [`ParamSpec`] defined /// outside of GLib like in GStreamer or GTK 4. pub trait ParamSpecBuilderExt<'a>: Sized { /// Implementation detail. fn set_nick(&mut self, nick: Option<&'a str>); /// Implementation detail. fn set_blurb(&mut self, blurb: Option<&'a str>); /// Implementation detail. fn set_flags(&mut self, flags: crate::ParamFlags); /// Implementation detail. fn current_flags(&self) -> crate::ParamFlags; /// By default, the nickname of its redirect target will be used if it has one. /// Otherwise, `self.name` will be used. fn nick(mut self, nick: &'a str) -> Self { self.set_nick(Some(nick)); self } /// Default: `None` fn blurb(mut self, blurb: &'a str) -> Self { self.set_blurb(Some(blurb)); self } /// Default: `glib::ParamFlags::READWRITE` fn flags(mut self, flags: crate::ParamFlags) -> Self { self.set_flags(flags); self } /// Mark the property as read only and drops the READWRITE flag set by default. fn read_only(self) -> Self { let flags = (self.current_flags() - crate::ParamFlags::WRITABLE) | crate::ParamFlags::READABLE; self.flags(flags) } /// Mark the property as write only and drops the READWRITE flag set by default. fn write_only(self) -> Self { let flags = (self.current_flags() - crate::ParamFlags::READABLE) | crate::ParamFlags::WRITABLE; self.flags(flags) } /// Mark the property as readwrite, it is the default value. fn readwrite(self) -> Self { let flags = self.current_flags() | crate::ParamFlags::READWRITE; self.flags(flags) } /// Mark the property as construct fn construct(self) -> Self { let flags = self.current_flags() | crate::ParamFlags::CONSTRUCT; self.flags(flags) } /// Mark the property as construct only fn construct_only(self) -> Self { let flags = self.current_flags() | crate::ParamFlags::CONSTRUCT_ONLY; self.flags(flags) } /// Mark the property as lax validation fn lax_validation(self) -> Self { let flags = self.current_flags() | crate::ParamFlags::LAX_VALIDATION; self.flags(flags) } /// Mark the property as explicit notify fn explicit_notify(self) -> Self { let flags = self.current_flags() | crate::ParamFlags::EXPLICIT_NOTIFY; self.flags(flags) } /// Mark the property as deprecated fn deprecated(self) -> Self { let flags = self.current_flags() | crate::ParamFlags::DEPRECATED; self.flags(flags) } } macro_rules! define_builder { (@constructors $rust_type:ident, $alias:literal, $builder_type:ident $(($($req_ident:ident: $req_ty:ty,)*))?) => { impl<'a> $builder_type<'a> { fn new(name: &'a str, $($($req_ident: $req_ty)*)?) -> Self { assert_param_name(name); Self { name, $($($req_ident: Some($req_ident),)*)? ..Default::default() } } } impl $rust_type { #[doc(alias = $alias)] pub fn builder(name: &str, $($($req_ident: $req_ty),*)?) -> $builder_type<'_> { $builder_type::new(name, $($($req_ident),*)?) } } impl<'a> crate::prelude::ParamSpecBuilderExt<'a> for $builder_type<'a> { fn set_nick(&mut self, nick: Option<&'a str>) { self.nick = nick; } fn set_blurb(&mut self, blurb: Option<&'a str>) { self.blurb = blurb; } fn set_flags(&mut self, flags: crate::ParamFlags) { self.flags = flags; } fn current_flags(&self) -> crate::ParamFlags { self.flags } } }; ( $rust_type:ident, $alias:literal, $builder_type:ident { $($field_id:ident: $field_ty:ty $(= $field_expr:expr)?,)* } $(requires $required_tt:tt)? ) => { #[derive(Default)] #[must_use] pub struct $builder_type<'a> { name: &'a str, nick: Option<&'a str>, blurb: Option<&'a str>, flags: crate::ParamFlags, $($field_id: Option<$field_ty>),* } impl<'a> $builder_type<'a> { $( $(#[doc = concat!("Default: `", stringify!($field_expr), "`")])? pub fn $field_id(mut self, value: $field_ty) -> Self { self.$field_id = Some(value); self } )* #[must_use] pub fn build(self) -> ParamSpec { unsafe { $rust_type::new_unchecked( self.name, self.nick, self.blurb, $(self .$field_id $(.or(Some($field_expr)))? .expect("impossible: missing parameter in ParamSpec*Builder") ,)* self.flags ) } } } define_builder!(@constructors $rust_type, $alias, $builder_type $($required_tt)?); } } macro_rules! define_builder_numeric { ($rust_type:ident, $alias:literal, $builder_type:ident, $n_ty:ty) => { define_builder!( $rust_type, $alias, $builder_type { minimum: $n_ty = <$n_ty>::MIN, maximum: $n_ty = <$n_ty>::MAX, default_value: $n_ty = <$n_ty as Default>::default(), } ); }; } #[track_caller] // the default panic formatter will use its caller as the location in its error message fn assert_param_name(name: &str) { assert!( is_canonical_pspec_name(name), "{name} is not a valid canonical parameter name", ); } wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecChar")] pub struct ParamSpecChar(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecChar, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec_numeric!( ParamSpecChar, gobject_ffi::GParamSpecChar, i8, "GParamChar", g_param_spec_char ); define_builder_numeric!(ParamSpecChar, "g_param_spec_char", ParamSpecCharBuilder, i8); wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecUChar")] pub struct ParamSpecUChar(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecUChar, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec_numeric!( ParamSpecUChar, gobject_ffi::GParamSpecUChar, u8, "GParamUChar", g_param_spec_uchar ); define_builder_numeric!( ParamSpecUChar, "g_param_spec_uchar", ParamSpecUCharBuilder, u8 ); wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecBoolean")] pub struct ParamSpecBoolean(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecBoolean, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec!( ParamSpecBoolean, gobject_ffi::GParamSpecBoolean, "GParamBoolean" ); define_param_spec_default!( ParamSpecBoolean, gobject_ffi::GParamSpecBoolean, bool, |x| from_glib(x) ); impl ParamSpecBoolean { unsafe fn new_unchecked<'a>( name: &str, nick: impl Into>, blurb: impl Into>, default_value: bool, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_none(gobject_ffi::g_param_spec_boolean( name.to_glib_none().0, nick.into().to_glib_none().0, blurb.into().to_glib_none().0, default_value.into_glib(), flags.into_glib(), )) } } } define_builder!( ParamSpecBoolean, "g_param_spec_builder", ParamSpecBooleanBuilder { default_value: bool = false, } ); wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecInt")] pub struct ParamSpecInt(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecInt, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec_numeric!( ParamSpecInt, gobject_ffi::GParamSpecInt, i32, "GParamInt", g_param_spec_int ); define_builder_numeric!(ParamSpecInt, "g_param_spec_int", ParamSpecIntBuilder, i32); wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecUInt")] pub struct ParamSpecUInt(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecUInt, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec_numeric!( ParamSpecUInt, gobject_ffi::GParamSpecUInt, u32, "GParamUInt", g_param_spec_uint ); define_builder_numeric!( ParamSpecUInt, "g_param_spec_uint", ParamSpecUIntBuilder, u32 ); wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecLong")] pub struct ParamSpecLong(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecLong, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec_numeric!( ParamSpecLong, gobject_ffi::GParamSpecLong, libc::c_long, "GParamLong", g_param_spec_long ); define_builder_numeric!( ParamSpecLong, "g_param_spec_long", ParamSpecLongBuilder, libc::c_long ); wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecULong")] pub struct ParamSpecULong(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecULong, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec_numeric!( ParamSpecULong, gobject_ffi::GParamSpecULong, libc::c_ulong, "GParamULong", g_param_spec_ulong ); define_builder_numeric!( ParamSpecULong, "g_param_spec_ulong", ParamSpecULongBuilder, libc::c_ulong ); wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecInt64")] pub struct ParamSpecInt64(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecInt64, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec_numeric!( ParamSpecInt64, gobject_ffi::GParamSpecInt64, i64, "GParamInt64", g_param_spec_int64 ); define_builder_numeric!( ParamSpecInt64, "g_param_spec_int64", ParamSpecInt64Builder, i64 ); wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecUInt64")] pub struct ParamSpecUInt64(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecUInt64, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec_numeric!( ParamSpecUInt64, gobject_ffi::GParamSpecUInt64, u64, "GParamUInt64", g_param_spec_uint64 ); define_builder_numeric!( ParamSpecUInt64, "g_param_spec_uint64", ParamSpecUInt64Builder, u64 ); wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecUnichar")] pub struct ParamSpecUnichar(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecUnichar, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec!( ParamSpecUnichar, gobject_ffi::GParamSpecUnichar, "GParamUnichar" ); define_param_spec_default!(ParamSpecUnichar, gobject_ffi::GParamSpecUnichar, Result, TryFrom::try_from); impl ParamSpecUnichar { unsafe fn new_unchecked<'a>( name: &str, nick: impl Into>, blurb: impl Into>, default_value: char, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_none(gobject_ffi::g_param_spec_unichar( name.to_glib_none().0, nick.into().to_glib_none().0, blurb.into().to_glib_none().0, default_value.into_glib(), flags.into_glib(), )) } } } define_builder!( ParamSpecUnichar, "g_param_spec_unichar", ParamSpecUnicharBuilder { default_value: char, } requires (default_value: char,) ); wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecEnum")] pub struct ParamSpecEnum(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecEnum, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec!(ParamSpecEnum, gobject_ffi::GParamSpecEnum, "GParamEnum"); impl ParamSpecEnum { unsafe fn new_unchecked<'a>( name: &str, nick: impl Into>, blurb: impl Into>, enum_type: crate::Type, default_value: i32, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_none(gobject_ffi::g_param_spec_enum( name.to_glib_none().0, nick.into().to_glib_none().0, blurb.into().to_glib_none().0, enum_type.into_glib(), default_value, flags.into_glib(), )) } } #[doc(alias = "get_enum_class")] #[inline] pub fn enum_class(&self) -> crate::EnumClass { unsafe { let ptr = ToGlibPtr::<*const gobject_ffi::GParamSpecEnum>::to_glib_none(self).0; debug_assert!(!(*ptr).enum_class.is_null()); crate::EnumClass::with_type(from_glib((*(*ptr).enum_class).g_type_class.g_type)) .expect("Invalid enum class") } } #[inline] pub fn default_value>(&self) -> Result { unsafe { if !self.enum_class().type_().is_a(T::static_type()) { return Err(bool_error!( "Wrong type -- expected {} got {}", self.enum_class().type_(), T::static_type() )); } Ok(from_glib(self.default_value_as_i32())) } } #[inline] pub fn default_value_as_i32(&self) -> i32 { unsafe { let ptr = ToGlibPtr::<*const gobject_ffi::GParamSpecEnum>::to_glib_none(self).0; (*ptr).default_value } } #[doc(alias = "g_param_spec_enum")] pub fn builder_with_default + IntoGlib>( name: &str, default_value: T, ) -> ParamSpecEnumBuilder { ParamSpecEnumBuilder::new(name, default_value) } #[doc(alias = "g_param_spec_enum")] pub fn builder + IntoGlib + Default>( name: &str, ) -> ParamSpecEnumBuilder { ParamSpecEnumBuilder::new(name, T::default()) } } #[must_use] pub struct ParamSpecEnumBuilder<'a, T: StaticType + FromGlib + IntoGlib> { name: &'a str, nick: Option<&'a str>, blurb: Option<&'a str>, flags: crate::ParamFlags, default_value: T, } impl<'a, T: StaticType + FromGlib + IntoGlib> ParamSpecEnumBuilder<'a, T> { fn new(name: &'a str, default_value: T) -> Self { assert_param_name(name); assert!(T::static_type().is_a(Type::ENUM)); Self { name, nick: None, blurb: None, flags: crate::ParamFlags::default(), default_value, } } pub fn default_value(mut self, default: T) -> Self { self.default_value = default; self } #[must_use] pub fn build(self) -> ParamSpec { unsafe { ParamSpecEnum::new_unchecked( self.name, self.nick, self.blurb, T::static_type(), self.default_value.into_glib(), self.flags, ) } } } impl<'a, T: StaticType + FromGlib + IntoGlib> crate::prelude::ParamSpecBuilderExt<'a> for ParamSpecEnumBuilder<'a, T> { fn set_nick(&mut self, nick: Option<&'a str>) { self.nick = nick; } fn set_blurb(&mut self, blurb: Option<&'a str>) { self.blurb = blurb; } fn set_flags(&mut self, flags: crate::ParamFlags) { self.flags = flags; } fn current_flags(&self) -> crate::ParamFlags { self.flags } } wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecFlags")] pub struct ParamSpecFlags(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecFlags, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec!(ParamSpecFlags, gobject_ffi::GParamSpecFlags, "GParamFlags"); impl ParamSpecFlags { unsafe fn new_unchecked<'a>( name: &str, nick: impl Into>, blurb: impl Into>, flags_type: crate::Type, default_value: u32, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_none(gobject_ffi::g_param_spec_flags( name.to_glib_none().0, nick.into().to_glib_none().0, blurb.into().to_glib_none().0, flags_type.into_glib(), default_value, flags.into_glib(), )) } } #[doc(alias = "get_flags_class")] #[inline] pub fn flags_class(&self) -> crate::FlagsClass { unsafe { let ptr = ToGlibPtr::<*const gobject_ffi::GParamSpecFlags>::to_glib_none(self).0; debug_assert!(!(*ptr).flags_class.is_null()); crate::FlagsClass::with_type(from_glib((*(*ptr).flags_class).g_type_class.g_type)) .expect("Invalid flags class") } } #[inline] pub fn default_value>(&self) -> Result { unsafe { if !self.flags_class().type_().is_a(T::static_type()) { return Err(bool_error!( "Wrong type -- expected {} got {}", self.flags_class().type_(), T::static_type() )); } Ok(from_glib(self.default_value_as_u32())) } } #[inline] pub fn default_value_as_u32(&self) -> u32 { unsafe { let ptr = ToGlibPtr::<*const gobject_ffi::GParamSpecFlags>::to_glib_none(self).0; (*ptr).default_value } } #[doc(alias = "g_param_spec_flags")] pub fn builder + IntoGlib>( name: &str, ) -> ParamSpecFlagsBuilder { ParamSpecFlagsBuilder::new(name) } } #[must_use] pub struct ParamSpecFlagsBuilder<'a, T: StaticType + FromGlib + IntoGlib> { name: &'a str, nick: Option<&'a str>, blurb: Option<&'a str>, flags: crate::ParamFlags, default_value: T, } impl<'a, T: StaticType + FromGlib + IntoGlib> ParamSpecFlagsBuilder<'a, T> { fn new(name: &'a str) -> Self { assert_param_name(name); assert!(T::static_type().is_a(Type::FLAGS)); unsafe { Self { name, nick: None, blurb: None, flags: crate::ParamFlags::default(), default_value: from_glib(0), } } } #[doc = "Default: 0`"] pub fn default_value(mut self, value: T) -> Self { self.default_value = value; self } #[must_use] pub fn build(self) -> ParamSpec { unsafe { ParamSpecFlags::new_unchecked( self.name, self.nick, self.blurb, T::static_type(), self.default_value.into_glib(), self.flags, ) } } } impl<'a, T: StaticType + FromGlib + IntoGlib> crate::prelude::ParamSpecBuilderExt<'a> for ParamSpecFlagsBuilder<'a, T> { fn set_nick(&mut self, nick: Option<&'a str>) { self.nick = nick; } fn set_blurb(&mut self, blurb: Option<&'a str>) { self.blurb = blurb; } fn set_flags(&mut self, flags: crate::ParamFlags) { self.flags = flags; } fn current_flags(&self) -> crate::ParamFlags { self.flags } } wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecFloat")] pub struct ParamSpecFloat(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecFloat, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec_numeric!( ParamSpecFloat, gobject_ffi::GParamSpecFloat, f32, "GParamFloat", g_param_spec_float ); define_builder_numeric!( ParamSpecFloat, "g_param_spec_float", ParamSpecFloatBuilder, f32 ); wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecDouble")] pub struct ParamSpecDouble(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecDouble, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec_numeric!( ParamSpecDouble, gobject_ffi::GParamSpecDouble, f64, "GParamDouble", g_param_spec_double ); define_builder_numeric!( ParamSpecDouble, "g_param_spec_double", ParamSpecDoubleBuilder, f64 ); wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecString")] pub struct ParamSpecString(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecString, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec!( ParamSpecString, gobject_ffi::GParamSpecString, "GParamString" ); define_param_spec_default!( ParamSpecString, gobject_ffi::GParamSpecString, Option<&str>, |x: *mut libc::c_char| { use std::ffi::CStr; if x.is_null() { None } else { Some(CStr::from_ptr(x).to_str().unwrap()) } } ); impl ParamSpecString { unsafe fn new_unchecked<'a>( name: &str, nick: impl Into>, blurb: impl Into>, default_value: Option<&str>, flags: ParamFlags, ) -> ParamSpec { let default_value = default_value.to_glib_none(); unsafe { from_glib_none(gobject_ffi::g_param_spec_string( name.to_glib_none().0, nick.into().to_glib_none().0, blurb.into().to_glib_none().0, default_value.0, flags.into_glib(), )) } } #[doc(alias = "g_param_spec_string")] pub fn builder(name: &str) -> ParamSpecStringBuilder { ParamSpecStringBuilder::new(name) } } #[must_use] pub struct ParamSpecStringBuilder<'a> { name: &'a str, nick: Option<&'a str>, blurb: Option<&'a str>, flags: crate::ParamFlags, default_value: Option<&'a str>, } impl<'a> ParamSpecStringBuilder<'a> { fn new(name: &'a str) -> Self { assert_param_name(name); Self { name, nick: None, blurb: None, flags: crate::ParamFlags::default(), default_value: None, } } #[doc = "Default: None`"] pub fn default_value(mut self, value: impl Into>) -> Self { self.default_value = value.into(); self } #[must_use] pub fn build(self) -> ParamSpec { unsafe { ParamSpecString::new_unchecked( self.name, self.nick, self.blurb, self.default_value, self.flags, ) } } } impl<'a> crate::prelude::ParamSpecBuilderExt<'a> for ParamSpecStringBuilder<'a> { fn set_nick(&mut self, nick: Option<&'a str>) { self.nick = nick; } fn set_blurb(&mut self, blurb: Option<&'a str>) { self.blurb = blurb; } fn set_flags(&mut self, flags: crate::ParamFlags) { self.flags = flags; } fn current_flags(&self) -> crate::ParamFlags { self.flags } } wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecParam")] pub struct ParamSpecParam(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecParam, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec!(ParamSpecParam, gobject_ffi::GParamSpecParam, "GParamParam"); impl ParamSpecParam { unsafe fn new_unchecked<'a>( name: &str, nick: impl Into>, blurb: impl Into>, param_type: crate::Type, flags: ParamFlags, ) -> ParamSpec { assert!(param_type.is_a(crate::Type::PARAM_SPEC)); unsafe { from_glib_none(gobject_ffi::g_param_spec_param( name.to_glib_none().0, nick.into().to_glib_none().0, blurb.into().to_glib_none().0, param_type.into_glib(), flags.into_glib(), )) } } } define_builder!( ParamSpecParam, "g_param_spec_param", ParamSpecParamBuilder { param_type: crate::Type, } requires (param_type: crate::Type,) ); wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecBoxed")] pub struct ParamSpecBoxed(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecBoxed, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec!(ParamSpecBoxed, gobject_ffi::GParamSpecBoxed, "GParamBoxed"); impl ParamSpecBoxed { unsafe fn new_unchecked<'a>( name: &str, nick: impl Into>, blurb: impl Into>, boxed_type: crate::Type, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_none(gobject_ffi::g_param_spec_boxed( name.to_glib_none().0, nick.into().to_glib_none().0, blurb.into().to_glib_none().0, boxed_type.into_glib(), flags.into_glib(), )) } } #[doc(alias = "g_param_spec_boxed")] pub fn builder(name: &str) -> ParamSpecBoxedBuilder { ParamSpecBoxedBuilder::new(name) } } #[must_use] pub struct ParamSpecBoxedBuilder<'a, T: StaticType> { name: &'a str, nick: Option<&'a str>, blurb: Option<&'a str>, flags: crate::ParamFlags, phantom: std::marker::PhantomData, } impl<'a, T: StaticType> ParamSpecBoxedBuilder<'a, T> { fn new(name: &'a str) -> Self { assert_param_name(name); assert!(T::static_type().is_a(Type::BOXED)); Self { name, nick: None, blurb: None, flags: crate::ParamFlags::default(), phantom: Default::default(), } } #[must_use] pub fn build(self) -> ParamSpec { unsafe { ParamSpecBoxed::new_unchecked( self.name, self.nick, self.blurb, T::static_type(), self.flags, ) } } } impl<'a, T: StaticType> crate::prelude::ParamSpecBuilderExt<'a> for ParamSpecBoxedBuilder<'a, T> { fn set_nick(&mut self, nick: Option<&'a str>) { self.nick = nick; } fn set_blurb(&mut self, blurb: Option<&'a str>) { self.blurb = blurb; } fn set_flags(&mut self, flags: crate::ParamFlags) { self.flags = flags; } fn current_flags(&self) -> crate::ParamFlags { self.flags } } wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecPointer")] pub struct ParamSpecPointer(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecPointer, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec!( ParamSpecPointer, gobject_ffi::GParamSpecPointer, "GParamPointer" ); impl ParamSpecPointer { unsafe fn new_unchecked<'a>( name: &str, nick: impl Into>, blurb: impl Into>, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_none(gobject_ffi::g_param_spec_pointer( name.to_glib_none().0, nick.into().to_glib_none().0, blurb.into().to_glib_none().0, flags.into_glib(), )) } } } define_builder!( ParamSpecPointer, "g_param_spec_pointer", ParamSpecPointerBuilder {} ); wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecValueArray")] pub struct ParamSpecValueArray(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecValueArray, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec!( ParamSpecValueArray, gobject_ffi::GParamSpecValueArray, "GParamValueArray" ); impl ParamSpecValueArray { unsafe fn new_unchecked<'a>( name: &str, nick: impl Into>, blurb: impl Into>, element_spec: Option>, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_none(gobject_ffi::g_param_spec_value_array( name.to_glib_none().0, nick.into().to_glib_none().0, blurb.into().to_glib_none().0, element_spec.as_ref().map(|p| p.as_ref()).to_glib_none().0, flags.into_glib(), )) } } #[doc(alias = "get_element_spec")] #[inline] pub fn element_spec(&self) -> Option<&ParamSpec> { unsafe { let ptr = ToGlibPtr::<*const gobject_ffi::GParamSpecValueArray>::to_glib_none(self).0; if (*ptr).element_spec.is_null() { None } else { Some( &*(&(*ptr).element_spec as *const *mut gobject_ffi::GParamSpec as *const ParamSpec), ) } } } #[doc(alias = "get_fixed_n_elements")] #[inline] pub fn fixed_n_elements(&self) -> u32 { unsafe { let ptr = ToGlibPtr::<*const gobject_ffi::GParamSpecValueArray>::to_glib_none(self).0; (*ptr).fixed_n_elements } } #[doc(alias = "g_param_spec_value_array")] pub fn builder(name: &str) -> ParamSpecValueArrayBuilder { ParamSpecValueArrayBuilder::new(name) } } #[must_use] pub struct ParamSpecValueArrayBuilder<'a> { name: &'a str, nick: Option<&'a str>, blurb: Option<&'a str>, flags: crate::ParamFlags, element_spec: Option<&'a ParamSpec>, } impl<'a> ParamSpecValueArrayBuilder<'a> { fn new(name: &'a str) -> Self { assert_param_name(name); Self { name, nick: None, blurb: None, flags: crate::ParamFlags::default(), element_spec: None, } } #[doc = "Default: None`"] pub fn element_spec(mut self, value: impl Into>) -> Self { self.element_spec = value.into(); self } #[must_use] pub fn build(self) -> ParamSpec { unsafe { ParamSpecValueArray::new_unchecked( self.name, self.nick, self.blurb, self.element_spec, self.flags, ) } } } impl<'a> crate::prelude::ParamSpecBuilderExt<'a> for ParamSpecValueArrayBuilder<'a> { fn set_nick(&mut self, nick: Option<&'a str>) { self.nick = nick; } fn set_blurb(&mut self, blurb: Option<&'a str>) { self.blurb = blurb; } fn set_flags(&mut self, flags: crate::ParamFlags) { self.flags = flags; } fn current_flags(&self) -> crate::ParamFlags { self.flags } } wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecObject")] pub struct ParamSpecObject(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecObject, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec!( ParamSpecObject, gobject_ffi::GParamSpecObject, "GParamObject" ); impl ParamSpecObject { unsafe fn new_unchecked<'a>( name: &str, nick: impl Into>, blurb: impl Into>, object_type: crate::Type, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_none(gobject_ffi::g_param_spec_object( name.to_glib_none().0, nick.into().to_glib_none().0, blurb.into().to_glib_none().0, object_type.into_glib(), flags.into_glib(), )) } } #[doc(alias = "g_param_spec_object")] pub fn builder>(name: &str) -> ParamSpecObjectBuilder { ParamSpecObjectBuilder::new(name) } } #[must_use] pub struct ParamSpecObjectBuilder<'a, T: StaticType> { name: &'a str, nick: Option<&'a str>, blurb: Option<&'a str>, flags: crate::ParamFlags, phantom: std::marker::PhantomData, } impl<'a, T: StaticType> ParamSpecObjectBuilder<'a, T> { fn new(name: &'a str) -> Self { assert_param_name(name); Self { name, nick: None, blurb: None, flags: crate::ParamFlags::default(), phantom: Default::default(), } } #[must_use] pub fn build(self) -> ParamSpec { unsafe { ParamSpecObject::new_unchecked( self.name, self.nick, self.blurb, T::static_type(), self.flags, ) } } } impl<'a, T: StaticType> crate::prelude::ParamSpecBuilderExt<'a> for ParamSpecObjectBuilder<'a, T> { fn set_nick(&mut self, nick: Option<&'a str>) { self.nick = nick; } fn set_blurb(&mut self, blurb: Option<&'a str>) { self.blurb = blurb; } fn set_flags(&mut self, flags: crate::ParamFlags) { self.flags = flags; } fn current_flags(&self) -> crate::ParamFlags { self.flags } } wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecOverride")] pub struct ParamSpecOverride(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecOverride, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec!( ParamSpecOverride, gobject_ffi::GParamSpecOverride, "GParamOverride" ); impl ParamSpecOverride { unsafe fn new_unchecked(name: &str, overridden: impl AsRef) -> ParamSpec { from_glib_none(gobject_ffi::g_param_spec_override( name.to_glib_none().0, overridden.as_ref().to_glib_none().0, )) } // rustdoc-stripper-ignore-next /// Create a [`ParamSpecOverride`] to override an interface property. /// /// # Examples /// /// ```ignore /// let pspec = ParamSpecOverride::for_interface::("vadjustment"); /// ``` /// /// # Panics /// /// If the property `name` doesn't exist in the interface. #[allow(clippy::new_ret_no_self)] #[doc(alias = "g_param_spec_override")] pub fn for_interface + IsInterface>(name: &str) -> ParamSpec { assert_param_name(name); // in case it's an interface let interface_ref: InterfaceRef = Interface::from_type(T::static_type()).unwrap(); let pspec = interface_ref .find_property(name) .unwrap_or_else(|| panic!("Couldn't find a property named `{name}` to override")); unsafe { Self::new_unchecked(name, &pspec) } } // rustdoc-stripper-ignore-next /// Create a [`ParamSpecOverride`] to override a class property. /// /// # Examples /// /// ```rust, ignore /// let pspec = ParamSpecOverride::for_class::("label"); /// ``` /// /// # Panics /// /// If the property `name` doesn't exist in the class. #[allow(clippy::new_ret_no_self)] #[doc(alias = "g_param_spec_override")] pub fn for_class + IsClass>(name: &str) -> ParamSpec { assert_param_name(name); let pspec = ObjectClass::from_type(T::static_type()) .unwrap() .find_property(name) .unwrap_or_else(|| panic!("Couldn't find a property named `{name}` to override")); unsafe { Self::new_unchecked(name, &pspec) } } #[doc(alias = "get_overridden")] #[inline] pub fn overridden(&self) -> ParamSpec { unsafe { let ptr = ToGlibPtr::<*const gobject_ffi::GParamSpecOverride>::to_glib_none(self).0; from_glib_none((*ptr).overridden) } } #[doc(alias = "g_param_spec_override")] pub fn builder<'a>(name: &'a str, overridden: &'a ParamSpec) -> ParamSpecOverrideBuilder<'a> { ParamSpecOverrideBuilder::new(name, overridden) } } // This builder is not autogenerated because it's the only one that doesn't take // `nick`, `blurb` and `flags` as parameters. #[must_use] pub struct ParamSpecOverrideBuilder<'a> { name: &'a str, overridden: &'a ParamSpec, } impl<'a> ParamSpecOverrideBuilder<'a> { fn new(name: &'a str, overridden: &'a ParamSpec) -> Self { assert_param_name(name); Self { name, overridden } } pub fn overridden(mut self, spec: &'a ParamSpec) -> Self { self.overridden = spec; self } #[must_use] pub fn build(self) -> ParamSpec { unsafe { ParamSpecOverride::new_unchecked(self.name, self.overridden) } } } wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecGType")] pub struct ParamSpecGType(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecGType, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec!(ParamSpecGType, gobject_ffi::GParamSpecGType, "GParamGType"); impl ParamSpecGType { unsafe fn new_unchecked<'a>( name: &str, nick: impl Into>, blurb: impl Into>, is_a_type: crate::Type, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_none(gobject_ffi::g_param_spec_gtype( name.to_glib_none().0, nick.into().to_glib_none().0, blurb.into().to_glib_none().0, is_a_type.into_glib(), flags.into_glib(), )) } } } define_builder!( ParamSpecGType, "g_param_spec_gtype", ParamSpecGTypeBuilder { is_a_type: crate::Type = crate::Type::UNIT, } ); wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GParamSpecVariant")] pub struct ParamSpecVariant(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut gobject_ffi::GParamSpecVariant, unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), } } define_param_spec!( ParamSpecVariant, gobject_ffi::GParamSpecVariant, "GParamVariant" ); define_param_spec_default!( ParamSpecVariant, gobject_ffi::GParamSpecVariant, Option, |x: *mut ffi::GVariant| from_glib_none(x) ); impl ParamSpecVariant { unsafe fn new_unchecked<'a>( name: &str, nick: impl Into>, blurb: impl Into>, type_: &crate::VariantTy, default_value: Option<&crate::Variant>, flags: ParamFlags, ) -> ParamSpec { unsafe { from_glib_none(gobject_ffi::g_param_spec_variant( name.to_glib_none().0, nick.into().to_glib_none().0, blurb.into().to_glib_none().0, type_.to_glib_none().0, default_value.to_glib_none().0, flags.into_glib(), )) } } #[doc(alias = "get_type")] #[inline] pub fn type_(&self) -> Option<&crate::VariantTy> { unsafe { let ptr = ToGlibPtr::<*const gobject_ffi::GParamSpecVariant>::to_glib_none(self).0; if (*ptr).type_.is_null() { None } else { Some(crate::VariantTy::from_ptr((*ptr).type_)) } } } #[doc(alias = "g_param_spec_variant")] pub fn builder<'a>(name: &'a str, type_: &'a crate::VariantTy) -> ParamSpecVariantBuilder<'a> { ParamSpecVariantBuilder::new(name, type_) } } #[must_use] pub struct ParamSpecVariantBuilder<'a> { name: &'a str, nick: Option<&'a str>, blurb: Option<&'a str>, flags: crate::ParamFlags, type_: &'a crate::VariantTy, default_value: Option<&'a crate::Variant>, } impl<'a> ParamSpecVariantBuilder<'a> { fn new(name: &'a str, type_: &'a crate::VariantTy) -> Self { assert_param_name(name); Self { name, nick: None, blurb: None, flags: crate::ParamFlags::default(), type_, default_value: None, } } #[doc = "Default: None`"] pub fn default_value(mut self, value: impl Into>) -> Self { self.default_value = value.into(); self } #[must_use] pub fn build(self) -> ParamSpec { unsafe { ParamSpecVariant::new_unchecked( self.name, self.nick, self.blurb, self.type_, self.default_value, self.flags, ) } } } impl<'a> crate::prelude::ParamSpecBuilderExt<'a> for ParamSpecVariantBuilder<'a> { fn set_nick(&mut self, nick: Option<&'a str>) { self.nick = nick; } fn set_blurb(&mut self, blurb: Option<&'a str>) { self.blurb = blurb; } fn set_flags(&mut self, flags: crate::ParamFlags) { self.flags = flags; } fn current_flags(&self) -> crate::ParamFlags { self.flags } } pub trait HasParamSpec { type ParamSpec; // rustdoc-stripper-ignore-next /// Preferred value to be used as setter for the associated ParamSpec. type SetValue: ?Sized; type BuilderFn; fn param_spec_builder() -> Self::BuilderFn; } impl HasParamSpec for Option { type ParamSpec = T::ParamSpec; type SetValue = T::SetValue; type BuilderFn = T::BuilderFn; fn param_spec_builder() -> Self::BuilderFn { T::param_spec_builder() } } impl HasParamSpec for &T { type ParamSpec = T::ParamSpec; type SetValue = T::SetValue; type BuilderFn = T::BuilderFn; fn param_spec_builder() -> Self::BuilderFn { T::param_spec_builder() } } impl HasParamSpec for crate::GString { type ParamSpec = ParamSpecString; type SetValue = str; type BuilderFn = fn(&str) -> ParamSpecStringBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl HasParamSpec for str { type ParamSpec = ParamSpecString; type SetValue = str; type BuilderFn = fn(&str) -> ParamSpecStringBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl HasParamSpec for String { type ParamSpec = ParamSpecString; type SetValue = str; type BuilderFn = fn(&str) -> ParamSpecStringBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl HasParamSpec for Box { type ParamSpec = ParamSpecString; type SetValue = str; type BuilderFn = fn(&str) -> ParamSpecStringBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl HasParamSpec for crate::StrV { type ParamSpec = ParamSpecBoxed; type SetValue = Self; type BuilderFn = fn(&str) -> ParamSpecBoxedBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl HasParamSpec for Vec { type ParamSpec = ParamSpecBoxed; type SetValue = Self; type BuilderFn = fn(&str) -> ParamSpecBoxedBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl HasParamSpec for Path { type ParamSpec = ParamSpecString; type SetValue = Path; type BuilderFn = fn(&str) -> ParamSpecStringBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl HasParamSpec for PathBuf { type ParamSpec = ParamSpecString; type SetValue = Path; type BuilderFn = fn(&str) -> ParamSpecStringBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl HasParamSpec for char { type ParamSpec = ParamSpecUnichar; type SetValue = Self; type BuilderFn = fn(&str, char) -> ParamSpecUnicharBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } // Simple types which have `type SetValue = Self` // and a builder function that doesn't require any parameter except the name macro_rules! has_simple_spec { ($t:ty, $s:ty, $b:ty) => { impl HasParamSpec for $t { type ParamSpec = $s; type SetValue = Self; type BuilderFn = fn(&str) -> $b; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } }; } has_simple_spec!(f64, ParamSpecDouble, ParamSpecDoubleBuilder); has_simple_spec!(f32, ParamSpecFloat, ParamSpecFloatBuilder); has_simple_spec!(i64, ParamSpecInt64, ParamSpecInt64Builder); has_simple_spec!(NonZeroI64, ParamSpecInt64, ParamSpecInt64Builder); has_simple_spec!(i32, ParamSpecInt, ParamSpecIntBuilder); has_simple_spec!(NonZeroI32, ParamSpecInt, ParamSpecIntBuilder); has_simple_spec!(i8, ParamSpecChar, ParamSpecCharBuilder); has_simple_spec!(NonZeroI8, ParamSpecChar, ParamSpecCharBuilder); has_simple_spec!(u64, ParamSpecUInt64, ParamSpecUInt64Builder); has_simple_spec!(NonZeroU64, ParamSpecUInt64, ParamSpecUInt64Builder); has_simple_spec!(u32, ParamSpecUInt, ParamSpecUIntBuilder); has_simple_spec!(NonZeroU32, ParamSpecUInt, ParamSpecUIntBuilder); has_simple_spec!(u8, ParamSpecUChar, ParamSpecUCharBuilder); has_simple_spec!(NonZeroU8, ParamSpecUChar, ParamSpecUCharBuilder); has_simple_spec!(bool, ParamSpecBoolean, ParamSpecBooleanBuilder); impl HasParamSpec for crate::Variant { type ParamSpec = ParamSpecVariant; type SetValue = Self; type BuilderFn = for<'a> fn(&'a str, ty: &'a crate::VariantTy) -> ParamSpecVariantBuilder<'a>; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } #[cfg(test)] mod tests { use super::*; #[test] fn test_param_spec_string() { let pspec = ParamSpecString::builder("name") .default_value(Some("default")) .build(); assert_eq!(pspec.name(), "name"); assert_eq!(pspec.nick(), "name"); assert_eq!(pspec.blurb(), None); let default_value = pspec.default_value(); assert_eq!(default_value.get::<&str>().unwrap(), "default"); assert_eq!(pspec.flags(), ParamFlags::READWRITE); assert_eq!(pspec.value_type(), Type::STRING); assert_eq!(pspec.type_(), ParamSpecString::static_type()); let pspec_ref = pspec .downcast_ref::() .expect("Not a string param spec"); assert_eq!(pspec_ref.default_value(), Some("default")); let pspec = pspec .downcast::() .expect("Not a string param spec"); assert_eq!(pspec.default_value(), Some("default")); } #[test] fn test_param_spec_int_builder() { let pspec = ParamSpecInt::builder("name") .blurb("Simple int parameter") .minimum(-2) .explicit_notify() .build(); assert_eq!(pspec.name(), "name"); assert_eq!(pspec.nick(), "name"); assert_eq!(pspec.blurb(), Some("Simple int parameter")); assert_eq!( pspec.flags(), ParamFlags::READWRITE | ParamFlags::EXPLICIT_NOTIFY ); } #[test] fn test_param_spec_builder_flags() { let pspec = ParamSpecInt::builder("name") .minimum(-2) .read_only() .build() .downcast::() .unwrap(); assert_eq!(pspec.minimum(), -2); assert_eq!(pspec.flags(), ParamFlags::READABLE); let pspec = ParamSpecInt::builder("name") .read_only() .write_only() .minimum(-2) .build() .downcast::() .unwrap(); assert_eq!(pspec.minimum(), -2); assert_eq!(pspec.flags(), ParamFlags::WRITABLE); let pspec = ParamSpecInt::builder("name") .read_only() .write_only() .readwrite() .minimum(-2) .build() .downcast::() .unwrap(); assert_eq!(pspec.minimum(), -2); assert_eq!(pspec.flags(), ParamFlags::READWRITE); } #[test] fn test_has_param_spec() { let pspec = ::param_spec_builder()("name") .blurb("Simple int parameter") .minimum(-2) .explicit_notify() .build(); assert_eq!(pspec.name(), "name"); assert_eq!(pspec.blurb(), Some("Simple int parameter")); assert_eq!( pspec.flags(), ParamFlags::READWRITE | ParamFlags::EXPLICIT_NOTIFY ); } } glib-0.20.9/src/prelude.rs000064400000000000000000000011361046102023000134270ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! Traits and essential types intended for blanket imports. pub use crate::{ error::ErrorDomain, gobject::traits::{DynamicObjectRegisterExt, TypeModuleExt, TypePluginExt}, object::{Cast, CastNone, IsA, ObjectClassExt, ObjectExt, ObjectType}, param_spec::{HasParamSpec, ParamSpecBuilderExt, ParamSpecType}, types::{StaticType, StaticTypeExt}, value::{ToSendValue, ToValue, ValueType}, variant::{FixedSizeVariantType, FromVariant, StaticVariantType, ToVariant}, }; glib-0.20.9/src/property.rs000064400000000000000000000170771046102023000136660ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::cell::Cell; use std::cell::RefCell; use std::marker::PhantomData; use std::rc::Rc; use std::sync::atomic::Ordering; use std::sync::Arc; use std::sync::Mutex; use std::sync::RwLock; use crate::prelude::*; use crate::Object; use crate::SendWeakRef; use crate::WeakRef; // rustdoc-stripper-ignore-next /// A type that can be used as a property. It covers every type which have an associated `ParamSpec` /// (`HasParamSpec`) and some useful types wrapping `HasParamSpec`. /// The definition is recursive, so you can nest many `Property`s together. The final `ParamSpec` will /// be the one of the innermost type pub trait Property { type Value: HasParamSpec; } impl Property for T { type Value = T; } impl Property for PhantomData { type Value = T::Value; } impl Property for RefCell { type Value = T::Value; } impl Property for Cell { type Value = T::Value; } impl Property for Mutex { type Value = T::Value; } impl Property for RwLock { type Value = T::Value; } impl Property for std::cell::OnceCell { type Value = T::Value; } impl Property for std::sync::OnceLock { type Value = T::Value; } // Handle smart pointers transparently impl Property for Rc { type Value = T::Value; } impl Property for Arc { type Value = T::Value; } impl + HasParamSpec> Property for WeakRef { type Value = Option; } impl + HasParamSpec> Property for SendWeakRef { type Value = Option; } // rustdoc-stripper-ignore-next /// A container type implementing this trait can be read by the default getter generated by the [`Properties`](crate::Properties) macro. pub trait PropertyGet { type Value; fn get R>(&self, f: F) -> R; } // rustdoc-stripper-ignore-next /// A container type implementing this trait can be written by the default setter generated by the [`Properties`](crate::Properties) macro. /// It takes a `FnOnce(&mut Self::Value)` so that the caller may access nested fields of a struct /// by doing `${Self::Value}.member` pub trait PropertySetNested { type SetNestedValue; fn set_nested(&self, f: F); } // rustdoc-stripper-ignore-next /// A container type implementing this trait can be written by the default setter generated by the [`Properties`](crate::Properties) macro. pub trait PropertySet { type SetValue; fn set(&self, v: Self::SetValue); } impl PropertySet for T { type SetValue = T::SetNestedValue; fn set(&self, v: Self::SetValue) { self.set_nested(|x| *x = v); } } impl PropertyGet for T { type Value = T; fn get R>(&self, f: F) -> R { f(self) } } impl PropertyGet for Cell { type Value = T; fn get R>(&self, f: F) -> R { f(&Cell::get(self)) } } impl PropertySet for Cell { type SetValue = T; fn set(&self, v: Self::SetValue) { self.set(v); } } impl PropertyGet for RefCell { type Value = T; fn get R>(&self, f: F) -> R { f(&self.borrow()) } } impl PropertySetNested for RefCell { type SetNestedValue = T; fn set_nested(&self, f: F) { f(&mut self.borrow_mut()); } } impl PropertyGet for Mutex { type Value = T; fn get R>(&self, f: F) -> R { f(&self.lock().unwrap()) } } impl PropertySetNested for Mutex { type SetNestedValue = T; fn set_nested(&self, f: F) { f(&mut self.lock().unwrap()); } } impl PropertyGet for RwLock { type Value = T; fn get R>(&self, f: F) -> R { f(&self.read().unwrap()) } } impl PropertySetNested for RwLock { type SetNestedValue = T; fn set_nested(&self, f: F) { f(&mut self.write().unwrap()); } } impl PropertyGet for std::cell::OnceCell { type Value = T; fn get R>(&self, f: F) -> R { f(self.get().unwrap()) } } impl PropertyGet for std::sync::OnceLock { type Value = T; fn get R>(&self, f: F) -> R { f(self.get().unwrap()) } } impl PropertySet for std::cell::OnceCell { type SetValue = T; fn set(&self, v: Self::SetValue) { // I can't use `unwrap` because I would have to add a `Debug` bound to _v if let Err(_v) = self.set(v) { panic!("can't set value of OnceCell multiple times") }; } } impl PropertySet for std::sync::OnceLock { type SetValue = T; fn set(&self, v: Self::SetValue) { // I can't use `unwrap` because I would have to add a `Debug` bound to _v if let Err(_v) = self.set(v) { panic!("can't set value of OnceCell multiple times") }; } } impl> PropertyGet for WeakRef { type Value = Option; fn get R>(&self, f: F) -> R { f(&self.upgrade()) } } impl> PropertySet for WeakRef { type SetValue = Option; fn set(&self, v: Self::SetValue) { self.set(v.as_ref()) } } impl> PropertyGet for SendWeakRef { type Value = Option; fn get R>(&self, f: F) -> R { f(&self.upgrade()) } } impl> PropertySet for SendWeakRef { type SetValue = Option; fn set(&self, v: Self::SetValue) { WeakRef::set(self, v.as_ref()); } } // Smart pointers wrapping a `PropertyRead`/`PropertyWrite` impl PropertyGet for Rc { type Value = T::Value; fn get R>(&self, f: F) -> R { (**self).get(f) } } impl PropertySetNested for Rc { type SetNestedValue = T::SetNestedValue; fn set_nested(&self, f: F) { (**self).set_nested(f) } } impl PropertyGet for Arc { type Value = T::Value; fn get R>(&self, f: F) -> R { (**self).get(f) } } impl PropertySetNested for Arc { type SetNestedValue = T::SetNestedValue; fn set_nested(&self, f: F) { (**self).set_nested(f) } } macro_rules! impl_atomic { ($atomic:ty, $valuety:ty) => { impl Property for $atomic { type Value = $valuety; } impl PropertyGet for $atomic { type Value = $valuety; fn get R>(&self, f: F) -> R { f(&self.load(Ordering::Acquire)) } } impl PropertySet for $atomic { type SetValue = $valuety; fn set(&self, v: Self::SetValue) { self.store(v, Ordering::Release); } } }; } impl_atomic!(std::sync::atomic::AtomicBool, bool); impl_atomic!(std::sync::atomic::AtomicI8, i8); impl_atomic!(std::sync::atomic::AtomicI32, i32); #[cfg(target_has_atomic = "64")] impl_atomic!(std::sync::atomic::AtomicI64, i64); impl_atomic!(std::sync::atomic::AtomicU8, u8); impl_atomic!(std::sync::atomic::AtomicU32, u32); #[cfg(target_has_atomic = "64")] impl_atomic!(std::sync::atomic::AtomicU64, u64); glib-0.20.9/src/quark.rs000064400000000000000000000052611046102023000131150ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{fmt, num::NonZeroU32}; use crate::{ffi, translate::*, GStr}; #[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[repr(transparent)] #[doc(alias = "GQuark")] pub struct Quark(NonZeroU32); impl Quark { #[doc(alias = "g_quark_from_string")] #[allow(clippy::should_implement_trait)] pub fn from_str(s: impl IntoGStr) -> Self { unsafe { s.run_with_gstr(|s| from_glib(ffi::g_quark_from_string(s.as_ptr()))) } } #[doc(alias = "g_quark_from_static_string")] #[allow(clippy::should_implement_trait)] pub fn from_static_str(s: &'static GStr) -> Self { unsafe { from_glib(ffi::g_quark_from_static_string(s.as_ptr())) } } #[allow(clippy::trivially_copy_pass_by_ref)] #[doc(alias = "g_quark_to_string")] pub fn as_str<'a>(&self) -> &'a GStr { unsafe { GStr::from_ptr(ffi::g_quark_to_string(self.into_glib())) } } #[doc(alias = "g_quark_try_string")] pub fn try_from_str(s: &str) -> Option { unsafe { Self::try_from_glib(ffi::g_quark_try_string(s.to_glib_none().0)).ok() } } } impl fmt::Debug for Quark { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.write_str(Quark::as_str(self)) } } impl From for Quark { fn from(s: T) -> Self { Self::from_str(s) } } impl std::str::FromStr for Quark { type Err = std::convert::Infallible; fn from_str(s: &str) -> Result { Ok(Self::from_str(s)) } } #[doc(hidden)] impl FromGlib for Quark { #[inline] unsafe fn from_glib(value: ffi::GQuark) -> Self { debug_assert_ne!(value, 0); Self(NonZeroU32::new_unchecked(value)) } } #[doc(hidden)] impl TryFromGlib for Quark { type Error = GlibNoneError; unsafe fn try_from_glib(value: ffi::GQuark) -> Result { if value == 0 { Err(GlibNoneError) } else { Ok(Self(NonZeroU32::new_unchecked(value))) } } } #[doc(hidden)] impl IntoGlib for Quark { type GlibType = ffi::GQuark; #[inline] fn into_glib(self) -> ffi::GQuark { self.0.get() } } #[doc(hidden)] impl IntoGlib for Option { type GlibType = ffi::GQuark; #[inline] fn into_glib(self) -> ffi::GQuark { self.map(|s| s.0.get()).unwrap_or(0) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_from_str() { let q1 = Quark::from_str("some-quark"); let q2 = Quark::try_from_str("some-quark"); assert_eq!(Some(q1), q2); assert_eq!(q1.as_str(), "some-quark"); } } glib-0.20.9/src/regex.rs000064400000000000000000000240261046102023000131040ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! This module is inefficient and should not be used by Rust programs except for //! compatibility with GLib.Regex based APIs. use crate::{ ffi, translate::*, GStr, GStringPtr, MatchInfo, PtrSlice, Regex, RegexCompileFlags, RegexMatchFlags, }; use std::{mem, ptr}; impl Regex { #[doc(alias = "g_regex_get_string_number")] #[doc(alias = "get_string_number")] pub fn string_number(&self, name: impl IntoGStr) -> i32 { name.run_with_gstr(|name| unsafe { ffi::g_regex_get_string_number(self.to_glib_none().0, name.to_glib_none().0) }) } #[doc(alias = "g_regex_escape_nul")] pub fn escape_nul(string: impl IntoGStr) -> crate::GString { unsafe { string.run_with_gstr(|string| { from_glib_full(ffi::g_regex_escape_nul( string.to_glib_none().0, string.len() as _, )) }) } } #[doc(alias = "g_regex_escape_string")] pub fn escape_string(string: impl IntoGStr) -> crate::GString { unsafe { string.run_with_gstr(|string| { from_glib_full(ffi::g_regex_escape_string( string.to_glib_none().0, string.len() as _, )) }) } } #[doc(alias = "g_regex_check_replacement")] pub fn check_replacement(replacement: impl IntoGStr) -> Result { replacement.run_with_gstr(|replacement| unsafe { let mut has_references = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let is_ok = ffi::g_regex_check_replacement( replacement.to_glib_none().0, has_references.as_mut_ptr(), &mut error, ); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(from_glib(has_references.assume_init())) } else { Err(from_glib_full(error)) } }) } #[doc(alias = "g_regex_match_simple")] pub fn match_simple( pattern: impl IntoGStr, string: impl IntoGStr, compile_options: RegexCompileFlags, match_options: RegexMatchFlags, ) -> bool { pattern.run_with_gstr(|pattern| { string.run_with_gstr(|string| unsafe { from_glib(ffi::g_regex_match_simple( pattern.to_glib_none().0, string.to_glib_none().0, compile_options.into_glib(), match_options.into_glib(), )) }) }) } #[doc(alias = "g_regex_replace")] pub fn replace( &self, string: impl IntoGStr, start_position: i32, replacement: impl IntoGStr, match_options: RegexMatchFlags, ) -> Result { unsafe { string.run_with_gstr(|string| { replacement.run_with_gstr(|replacement| { let mut error = ptr::null_mut(); let ret = ffi::g_regex_replace( self.to_glib_none().0, string.as_ptr() as *const _, string.len() as _, start_position, replacement.to_glib_none().0, match_options.into_glib(), &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } }) }) } } #[doc(alias = "g_regex_match_all")] pub fn match_all<'input>( &self, string: &'input GStr, match_options: RegexMatchFlags, ) -> Option> { self.match_all_full(string, 0, match_options).ok() } #[doc(alias = "g_regex_match_all_full")] pub fn match_all_full<'input>( &self, string: &'input GStr, start_position: i32, match_options: RegexMatchFlags, ) -> Result, crate::Error> { unsafe { let mut match_info = ptr::null_mut(); let mut error = ptr::null_mut(); let is_ok = ffi::g_regex_match_all_full( self.to_glib_none().0, string.to_glib_none().0, string.len() as _, start_position, match_options.into_glib(), &mut match_info, &mut error, ); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(from_glib_full(match_info)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_regex_match")] pub fn match_<'input>( &self, string: &'input GStr, match_options: RegexMatchFlags, ) -> Option> { self.match_full(string, 0, match_options).ok() } #[doc(alias = "g_regex_match_full")] pub fn match_full<'input>( &self, string: &'input GStr, start_position: i32, match_options: RegexMatchFlags, ) -> Result, crate::Error> { unsafe { let mut match_info = ptr::null_mut(); let mut error = ptr::null_mut(); let is_ok = ffi::g_regex_match_full( self.to_glib_none().0, string.to_glib_none().0, string.len() as _, start_position, match_options.into_glib(), &mut match_info, &mut error, ); debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(from_glib_full(match_info)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "g_regex_replace_literal")] pub fn replace_literal( &self, string: impl IntoGStr, start_position: i32, replacement: impl IntoGStr, match_options: RegexMatchFlags, ) -> Result { unsafe { string.run_with_gstr(|string| { replacement.run_with_gstr(|replacement| { let mut error = ptr::null_mut(); let ret = ffi::g_regex_replace_literal( self.to_glib_none().0, string.to_glib_none().0, string.len() as _, start_position, replacement.to_glib_none().0, match_options.into_glib(), &mut error, ); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } }) }) } } #[doc(alias = "g_regex_split")] pub fn split( &self, string: impl IntoGStr, match_options: RegexMatchFlags, ) -> PtrSlice { self.split_full(string, 0, match_options, 0) .unwrap_or_default() } #[doc(alias = "g_regex_split_full")] pub fn split_full( &self, string: impl IntoGStr, start_position: i32, match_options: RegexMatchFlags, max_tokens: i32, ) -> Result, crate::Error> { unsafe { let mut error = ptr::null_mut(); string.run_with_gstr(|string| { let ret = ffi::g_regex_split_full( self.to_glib_none().0, string.to_glib_none().0, string.len() as _, start_position, match_options.into_glib(), max_tokens, &mut error, ); if error.is_null() { Ok(FromGlibPtrContainer::from_glib_full(ret)) } else { Err(from_glib_full(error)) } }) } } #[doc(alias = "g_regex_split_simple")] pub fn split_simple( pattern: impl IntoGStr, string: impl IntoGStr, compile_options: RegexCompileFlags, match_options: RegexMatchFlags, ) -> PtrSlice { pattern.run_with_gstr(|pattern| { string.run_with_gstr(|string| unsafe { FromGlibPtrContainer::from_glib_full(ffi::g_regex_split_simple( pattern.to_glib_none().0, string.to_glib_none().0, compile_options.into_glib(), match_options.into_glib(), )) }) }) } } #[cfg(test)] mod tests { use super::*; use crate::RegexCompileFlags; #[test] fn test_replace_literal() { let regex = Regex::new( "s[ai]mple", RegexCompileFlags::OPTIMIZE, RegexMatchFlags::DEFAULT, ) .expect("Regex new") .expect("Null regex"); let quote = "This is a simple sample."; let result = regex .replace_literal(quote, 0, "XXX", RegexMatchFlags::DEFAULT) .expect("regex replace"); assert_eq!(result, "This is a XXX XXX."); } #[test] fn test_split() { let regex = Regex::new( "s[ai]mple", RegexCompileFlags::OPTIMIZE, RegexMatchFlags::DEFAULT, ) .expect("Regex new") .expect("Null regex"); let quote = "This is a simple sample."; let result = regex.split(quote, RegexMatchFlags::DEFAULT); assert_eq!(result.len(), 3); assert_eq!(result[0], "This is a "); assert_eq!(result[1], " "); assert_eq!(result[2], "."); } } glib-0.20.9/src/shared.rs000064400000000000000000000573231046102023000132460ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! `IMPL` Shared (reference counted) wrapper implementation. use std::{ cmp, fmt, hash::{Hash, Hasher}, marker::PhantomData, ptr, }; use crate::translate::*; // rustdoc-stripper-ignore-next /// Wrapper implementations for shared types. See `wrapper!`. #[macro_export] macro_rules! glib_shared_wrapper { ([$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty, @ref $ref_arg:ident $ref_expr:expr, @unref $unref_arg:ident $unref_expr:expr $(, @type_ $get_type_expr:expr)?) => { $crate::glib_shared_wrapper!( @generic_impl [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name, @ref $ref_arg $ref_expr, @unref $unref_arg $unref_expr ); $crate::glib_shared_wrapper!(@value_impl $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name $(, @type_ $get_type_expr)?); }; (@generic_impl [$($attr:meta)*] $visibility:vis $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty, @ref $ref_arg:ident $ref_expr:expr, @unref $unref_arg:ident $unref_expr:expr) => { $(#[$attr])* #[doc = "\n\nGLib type: Shared boxed type with reference counted clone semantics."] #[repr(transparent)] $visibility struct $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? { inner: $crate::shared::Shared<$ffi_name, Self>, } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $name $(<$($generic),+>)? { #[doc = "Return the inner pointer to the underlying C value."] #[inline] pub fn as_ptr(&self) -> *mut $ffi_name { unsafe { *(self as *const Self as *const *const $ffi_name) as *mut $ffi_name } } #[doc = "Borrows the underlying C value."] #[inline] pub unsafe fn from_glib_ptr_borrow(ptr: &*mut $ffi_name) -> &Self { debug_assert_eq!( std::mem::size_of::(), std::mem::size_of::<$crate::ffi::gpointer>() ); debug_assert!(!ptr.is_null()); &*(ptr as *const *mut $ffi_name as *const Self) } } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::clone::Clone for $name $(<$($generic),+>)? { #[doc = "Makes a clone of this shared reference.\n\nThis increments the strong reference count of the reference. Dropping the reference will decrement it again."] #[inline] fn clone(&self) -> Self { Self { inner: std::clone::Clone::clone(&self.inner), } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::shared::SharedMemoryManager for $name $(<$($generic),+>)? { type Target = $ffi_name; #[inline] unsafe fn ref_($ref_arg: *mut Self::Target) { $ref_expr; } #[inline] #[allow(clippy::no_effect)] unsafe fn unref($unref_arg: *mut Self::Target) { $unref_expr; } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::GlibPtrDefault for $name $(<$($generic),+>)? { type GlibType = *mut $ffi_name; } #[doc(hidden)] unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::TransparentPtrType for $name $(<$($generic),+>)? {} #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibPtr<'a, *mut $ffi_name> for $name $(<$($generic),+>)? { type Storage = std::marker::PhantomData<&'a $crate::shared::Shared<$ffi_name, Self>>; #[inline] fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *mut $ffi_name, Self> { let stash = $crate::translate::ToGlibPtr::to_glib_none(&self.inner); $crate::translate::Stash(stash.0, stash.1) } #[inline] fn to_glib_full(&self) -> *mut $ffi_name { $crate::translate::ToGlibPtr::to_glib_full(&self.inner) } } #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibPtr<'a, *const $ffi_name> for $name $(<$($generic),+>)? { type Storage = std::marker::PhantomData<&'a $crate::shared::Shared<$ffi_name, Self>>; #[inline] fn to_glib_none(&'a self) -> $crate::translate::Stash<'a, *const $ffi_name, Self> { let stash = $crate::translate::ToGlibPtr::to_glib_none(&self.inner); $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.inner) as *const _ } } #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibContainerFromSlice<'a, *mut *mut $ffi_name> for $name $(<$($generic),+>)? { type Storage = (std::marker::PhantomData<&'a [Self]>, Option>); fn to_glib_none_from_slice(t: &'a [Self]) -> (*mut *mut $ffi_name, Self::Storage) { let mut v_ptr = Vec::with_capacity(t.len() + 1); unsafe { let ptr = v_ptr.as_mut_ptr(); std::ptr::copy_nonoverlapping(t.as_ptr() as *mut *mut $ffi_name, ptr, t.len()); std::ptr::write(ptr.add(t.len()), std::ptr::null_mut()); v_ptr.set_len(t.len() + 1); } (v_ptr.as_ptr() as *mut *mut $ffi_name, (std::marker::PhantomData, Some(v_ptr))) } fn to_glib_container_from_slice(t: &'a [Self]) -> (*mut *mut $ffi_name, Self::Storage) { let v_ptr = unsafe { let v_ptr = $crate::ffi::g_malloc(std::mem::size_of::<*mut $ffi_name>() * (t.len() + 1)) as *mut *mut $ffi_name; std::ptr::copy_nonoverlapping(t.as_ptr() as *mut *mut $ffi_name, v_ptr, t.len()); std::ptr::write(v_ptr.add(t.len()), std::ptr::null_mut()); v_ptr }; (v_ptr, (std::marker::PhantomData, None)) } fn to_glib_full_from_slice(t: &[Self]) -> *mut *mut $ffi_name { unsafe { let v_ptr = $crate::ffi::g_malloc(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)); } std::ptr::write(v_ptr.add(t.len()), std::ptr::null_mut()); v_ptr } } } #[doc(hidden)] impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::translate::ToGlibContainerFromSlice<'a, *const *mut $ffi_name> for $name $(<$($generic),+>)? { type Storage = (std::marker::PhantomData<&'a [Self]>, Option>); fn to_glib_none_from_slice(t: &'a [Self]) -> (*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 [Self]) -> (*const *mut $ffi_name, Self::Storage) { // Can't have consumer free a *const pointer unimplemented!() } fn to_glib_full_from_slice(_: &[Self]) -> *const *mut $ffi_name { // Can't have consumer free a *const pointer unimplemented!() } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrNone<*mut $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn from_glib_none(ptr: *mut $ffi_name) -> Self { Self { inner: $crate::translate::from_glib_none(ptr), } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrNone<*const $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn from_glib_none(ptr: *const $ffi_name) -> Self { Self { inner: $crate::translate::from_glib_none(ptr), } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrFull<*mut $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn from_glib_full(ptr: *mut $ffi_name) -> Self { Self { inner: $crate::translate::from_glib_full(ptr), } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrBorrow<*mut $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn from_glib_borrow(ptr: *mut $ffi_name) -> $crate::translate::Borrowed { $crate::translate::Borrowed::new( Self { inner: $crate::translate::from_glib_borrow::<_, $crate::shared::Shared<_, _>>(ptr).into_inner(), } ) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrBorrow<*const $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn from_glib_borrow(ptr: *const $ffi_name) -> $crate::translate::Borrowed { $crate::translate::from_glib_borrow::<_, Self>(ptr as *mut $ffi_name) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name $(<$($generic),+>)? { 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); let res_ptr = res.as_mut_ptr(); for i in 0..num { ::std::ptr::write(res_ptr.add(i), $crate::translate::from_glib_none(std::ptr::read(ptr.add(i)))); } res.set_len(num); res } unsafe fn from_glib_container_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { let res = $crate::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); $crate::ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { if num == 0 || ptr.is_null() { $crate::ffi::g_free(ptr as *mut _); return Vec::new(); } let mut res = Vec::with_capacity(num); let res_ptr = res.as_mut_ptr(); ::std::ptr::copy_nonoverlapping(ptr as *mut Self, res_ptr, num); res.set_len(num); $crate::ffi::g_free(ptr as *mut _); res } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrArrayContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name $(<$($generic),+>)? { 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 $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibContainerAsVec<*mut $ffi_name, *const *mut $ffi_name> for $name $(<$($generic),+>)? { 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 $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::FromGlibPtrArrayContainerAsVec<*mut $ffi_name, *const *mut $ffi_name> for $name $(<$($generic),+>)? { 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!() } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::IntoGlibPtr<*mut $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn into_glib_ptr(self) -> *mut $ffi_name { let s = std::mem::ManuallyDrop::new(self); $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(&*s).0 as *mut _ } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::translate::IntoGlibPtr<*const $ffi_name> for $name $(<$($generic),+>)? { #[inline] unsafe fn into_glib_ptr(self) -> *const $ffi_name { let s = std::mem::ManuallyDrop::new(self); $crate::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(&*s).0 as *const _ } } }; (@value_impl $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty) => { }; (@value_impl $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)?, $ffi_name:ty, @type_ $get_type_expr:expr) => { impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::prelude::StaticType for $name $(<$($generic),+>)? { #[inline] fn static_type() -> $crate::types::Type { #[allow(unused_unsafe)] #[allow(clippy::macro_metavars_in_unsafe)] unsafe { $crate::translate::from_glib($get_type_expr) } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::value::ValueType for $name $(<$($generic),+>)? { type Type = Self; } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::value::ValueTypeOptional for $name $(<$($generic),+>)? { } #[doc(hidden)] unsafe impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::value::FromValue<'a> for $name $(<$($generic),+>)? { type Checker = $crate::value::GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a $crate::Value) -> Self { let ptr = $crate::gobject_ffi::g_value_dup_boxed($crate::translate::ToGlibPtr::to_glib_none(value).0); debug_assert!(!ptr.is_null()); >::from_glib_full(ptr as *mut $ffi_name) } } #[doc(hidden)] unsafe impl<'a $(, $($generic $(: $bound $(+ $bound2)*)?),+)?> $crate::value::FromValue<'a> for &'a $name $(<$($generic),+>)? { type Checker = $crate::value::GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a $crate::Value) -> Self { let value = &*(value as *const $crate::Value as *const $crate::gobject_ffi::GValue); <$name $(<$($generic),+>)?>::from_glib_ptr_borrow(&*(&value.data[0].v_pointer as *const $crate::ffi::gpointer as *const *mut $ffi_name)) } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::value::ToValue for $name $(<$($generic),+>)? { #[inline] fn to_value(&self) -> $crate::Value { unsafe { let mut value = $crate::Value::from_type_unchecked(::static_type()); $crate::gobject_ffi::g_value_take_boxed( $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::translate::ToGlibPtr::<*mut $ffi_name>::to_glib_full(self) as *mut _, ); value } } #[inline] fn value_type(&self) -> $crate::Type { ::static_type() } } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::convert::From<$name $(<$($generic),+>)?> for $crate::Value { #[inline] fn from(s: $name $(<$($generic),+>)?) -> Self { unsafe { let mut value = $crate::Value::from_type_unchecked(<$name $(<$($generic),+>)? as $crate::prelude::StaticType>::static_type()); $crate::gobject_ffi::g_value_take_boxed( $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::translate::IntoGlibPtr::<*mut $ffi_name>::into_glib_ptr(s) as *mut _, ); value } } } #[doc(hidden)] impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::value::ToValueOptional for $name $(<$($generic),+>)? { #[inline] fn to_value_optional(s: Option<&Self>) -> $crate::Value { let mut value = $crate::Value::for_value_type::(); unsafe { $crate::gobject_ffi::g_value_take_boxed( $crate::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::translate::ToGlibPtr::<*mut $ffi_name>::to_glib_full(&s) as *mut _, ); } value } } impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::prelude::HasParamSpec for $name $(<$($generic),+>)? { type ParamSpec = $crate::ParamSpecBoxed; type SetValue = Self; type BuilderFn = fn(&str) -> $crate::ParamSpecBoxedBuilder; fn param_spec_builder() -> Self::BuilderFn { |name| Self::ParamSpec::builder(name) } } }; } pub trait SharedMemoryManager { type Target; /// # Safety /// /// Callers are responsible for ensuring that a matching call to `unref` /// is made at an appropriate time. unsafe fn ref_(ptr: *mut Self::Target); /// # Safety /// /// Callers are responsible for ensuring that a matching call to `ref` was /// made before this is called, and that the pointer is not used after the /// `unref` call. unsafe fn unref(ptr: *mut Self::Target); } /// Encapsulates memory management logic for shared types. #[repr(transparent)] pub struct Shared> { inner: ptr::NonNull, mm: PhantomData<*const MM>, } impl> Drop for Shared { #[inline] fn drop(&mut self) { unsafe { MM::unref(self.inner.as_ptr()); } } } impl> Clone for Shared { #[inline] fn clone(&self) -> Self { unsafe { MM::ref_(self.inner.as_ptr()); } Self { inner: self.inner, mm: PhantomData, } } } impl> fmt::Debug for Shared { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Shared") .field("inner", &self.inner) .finish() } } impl> PartialOrd for Shared { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl> Ord for Shared { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { self.inner.cmp(&other.inner) } } impl> PartialEq for Shared { #[inline] fn eq(&self, other: &Self) -> bool { self.inner == other.inner } } impl> Eq for Shared {} impl> Hash for Shared { #[inline] 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 = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut T, Self> { Stash(self.inner.as_ptr(), PhantomData) } #[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 { debug_assert!(!ptr.is_null()); MM::ref_(ptr); Self { inner: ptr::NonNull::new_unchecked(ptr), mm: PhantomData, } } } impl> FromGlibPtrNone<*const T> for Shared { #[inline] unsafe fn from_glib_none(ptr: *const T) -> Self { debug_assert!(!ptr.is_null()); MM::ref_(ptr as *mut _); Self { inner: ptr::NonNull::new_unchecked(ptr as *mut _), mm: PhantomData, } } } impl> FromGlibPtrFull<*mut T> for Shared { #[inline] unsafe fn from_glib_full(ptr: *mut T) -> Self { debug_assert!(!ptr.is_null()); Self { inner: ptr::NonNull::new_unchecked(ptr), mm: PhantomData, } } } impl> FromGlibPtrBorrow<*mut T> for Shared { #[inline] unsafe fn from_glib_borrow(ptr: *mut T) -> Borrowed { debug_assert!(!ptr.is_null()); Borrowed::new(Self { inner: ptr::NonNull::new_unchecked(ptr), mm: PhantomData, }) } } glib-0.20.9/src/signal.rs000064400000000000000000000137531046102023000132540ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! `IMPL` Low level signal support. use std::{mem, num::NonZeroU64}; use crate::{ffi, gobject_ffi}; use libc::{c_char, c_ulong, c_void}; use crate::{prelude::*, translate::*}; // rustdoc-stripper-ignore-next /// The id of a signal that is returned by `connect`. /// /// This type does not implement `Clone` to prevent disconnecting /// the same signal handler multiple times. /// /// ```ignore /// use glib::SignalHandlerId; /// use gtk::prelude::*; /// use std::cell::RefCell; /// /// struct Button { /// widget: gtk::Button, /// clicked_handler_id: RefCell>, /// } /// /// impl Button { /// fn new() -> Self { /// let widget = gtk::Button::new(); /// let clicked_handler_id = RefCell::new(Some(widget.connect_clicked(|_button| { /// // Do something. /// }))); /// Self { /// widget, /// clicked_handler_id, /// } /// } /// /// fn disconnect(&self) { /// if let Some(id) = self.clicked_handler_id.take() { /// self.widget.disconnect(id) /// } /// } /// } /// ``` #[derive(Debug, Eq, PartialEq)] pub struct SignalHandlerId(NonZeroU64); impl SignalHandlerId { // rustdoc-stripper-ignore-next /// Returns the internal signal handler ID. pub unsafe fn as_raw(&self) -> libc::c_ulong { self.0.get() as libc::c_ulong } } impl FromGlib for SignalHandlerId { #[inline] unsafe fn from_glib(val: c_ulong) -> Self { debug_assert_ne!(val, 0); Self(NonZeroU64::new_unchecked(val as _)) } } pub unsafe fn connect_raw( receiver: *mut gobject_ffi::GObject, signal_name: *const c_char, trampoline: gobject_ffi::GCallback, closure: *mut F, ) -> SignalHandlerId { unsafe extern "C" fn destroy_closure(ptr: *mut c_void, _: *mut gobject_ffi::GClosure) { // destroy let _ = Box::::from_raw(ptr as *mut _); } debug_assert_eq!(mem::size_of::<*mut F>(), mem::size_of::()); debug_assert!(trampoline.is_some()); let handle = gobject_ffi::g_signal_connect_data( receiver, signal_name, trampoline, closure as *mut _, Some(destroy_closure::), 0, ); debug_assert!(handle > 0); from_glib(handle) } #[doc(alias = "g_signal_handler_block")] pub fn signal_handler_block(instance: &T, handler_id: &SignalHandlerId) { unsafe { gobject_ffi::g_signal_handler_block( instance.as_object_ref().to_glib_none().0, handler_id.as_raw(), ); } } #[doc(alias = "g_signal_handler_unblock")] pub fn signal_handler_unblock(instance: &T, handler_id: &SignalHandlerId) { unsafe { gobject_ffi::g_signal_handler_unblock( instance.as_object_ref().to_glib_none().0, handler_id.as_raw(), ); } } #[allow(clippy::needless_pass_by_value)] #[doc(alias = "g_signal_handler_disconnect")] pub fn signal_handler_disconnect(instance: &T, handler_id: SignalHandlerId) { unsafe { gobject_ffi::g_signal_handler_disconnect( instance.as_object_ref().to_glib_none().0, handler_id.as_raw(), ); } } #[doc(alias = "g_signal_stop_emission_by_name")] pub fn signal_stop_emission_by_name(instance: &T, signal_name: &str) { unsafe { gobject_ffi::g_signal_stop_emission_by_name( instance.as_object_ref().to_glib_none().0, signal_name.to_glib_none().0, ); } } #[doc(alias = "g_signal_has_handler_pending")] pub fn signal_has_handler_pending( instance: &T, signal_id: crate::subclass::SignalId, detail: Option, may_be_blocked: bool, ) -> bool { unsafe { from_glib(gobject_ffi::g_signal_has_handler_pending( instance.as_object_ref().to_glib_none().0, signal_id.into_glib(), detail.map_or(0, |d| d.into_glib()), may_be_blocked.into_glib(), )) } } // rustdoc-stripper-ignore-next /// Whether to invoke the other event handlers. /// /// `Stop` and `Proceed` map to `GDK_EVENT_STOP` (`true`) and /// `GDK_EVENT_PROPAGATE` (`false`), respectively. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Propagation { // Stop other handlers from being invoked for the event. #[doc(alias = "GDK_EVENT_STOP")] Stop, // Propagate the event further. #[doc(alias = "GDK_EVENT_PROPAGATE")] Proceed, } impl Propagation { // rustdoc-stripper-ignore-next /// Returns `true` if this is a `Stop` variant. pub fn is_stop(&self) -> bool { matches!(self, Self::Stop) } // rustdoc-stripper-ignore-next /// Returns `true` if this is a `Proceed` variant. pub fn is_proceed(&self) -> bool { matches!(self, Self::Proceed) } } impl From for Propagation { fn from(value: bool) -> Self { if value { Self::Stop } else { Self::Proceed } } } impl From for bool { fn from(c: Propagation) -> Self { match c { Propagation::Stop => true, Propagation::Proceed => false, } } } #[doc(hidden)] impl IntoGlib for Propagation { type GlibType = ffi::gboolean; #[inline] fn into_glib(self) -> ffi::gboolean { bool::from(self).into_glib() } } #[doc(hidden)] impl FromGlib for Propagation { #[inline] unsafe fn from_glib(value: ffi::gboolean) -> Self { bool::from_glib(value).into() } } impl crate::value::ToValue for Propagation { fn to_value(&self) -> crate::Value { bool::from(*self).to_value() } fn value_type(&self) -> crate::Type { ::static_type() } } impl From for crate::Value { #[inline] fn from(v: Propagation) -> Self { bool::from(v).into() } } glib-0.20.9/src/source.rs000064400000000000000000001230371046102023000132740ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #[cfg(unix)] use std::os::unix::io::RawFd; use std::{cell::RefCell, mem::transmute, num::NonZeroU32, time::Duration}; use crate::ffi::{self, gboolean, gpointer}; #[cfg(all(not(unix), docsrs))] use libc::c_int as RawFd; #[cfg(unix)] use crate::IOCondition; use crate::{thread_guard::ThreadGuard, translate::*, ControlFlow, MainContext, Source}; // rustdoc-stripper-ignore-next /// The id of a source that is returned by `idle_add` and `timeout_add`. /// /// This type does not implement `Clone` to prevent calling [`SourceId::remove`] /// multiple times on the same source. #[derive(Debug, Eq, PartialEq)] pub struct SourceId(NonZeroU32); impl SourceId { // rustdoc-stripper-ignore-next /// Returns the internal source ID. pub fn as_raw(&self) -> u32 { self.0.get() } // rustdoc-stripper-ignore-next /// 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. #[doc(alias = "g_source_remove")] pub fn remove(self) { unsafe { result_from_gboolean!( ffi::g_source_remove(self.as_raw()), "Failed to remove source" ) .unwrap() } } } #[doc(hidden)] impl FromGlib for SourceId { #[inline] unsafe fn from_glib(val: u32) -> Self { debug_assert_ne!(val, 0); Self(NonZeroU32::new_unchecked(val)) } } // rustdoc-stripper-ignore-next /// Process identifier #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[doc(alias = "GPid")] pub struct Pid(pub ffi::GPid); unsafe impl Send for Pid {} unsafe impl Sync for Pid {} #[doc(hidden)] impl IntoGlib for Pid { type GlibType = ffi::GPid; #[inline] fn into_glib(self) -> ffi::GPid { self.0 } } #[doc(hidden)] impl FromGlib for Pid { #[inline] unsafe fn from_glib(val: ffi::GPid) -> Self { Self(val) } } unsafe extern "C" fn trampoline ControlFlow + Send + 'static>( func: gpointer, ) -> gboolean { let func: &RefCell = &*(func as *const RefCell); (*func.borrow_mut())().into_glib() } unsafe extern "C" fn trampoline_local ControlFlow + 'static>( func: gpointer, ) -> gboolean { let func: &ThreadGuard> = &*(func as *const ThreadGuard>); (*func.get_ref().borrow_mut())().into_glib() } unsafe extern "C" fn destroy_closure ControlFlow + Send + 'static>(ptr: gpointer) { let _ = Box::>::from_raw(ptr as *mut _); } unsafe extern "C" fn destroy_closure_local ControlFlow + 'static>(ptr: gpointer) { let _ = Box::>>::from_raw(ptr as *mut _); } fn into_raw ControlFlow + Send + 'static>(func: F) -> gpointer { let func: Box> = Box::new(RefCell::new(func)); Box::into_raw(func) as gpointer } fn into_raw_local ControlFlow + 'static>(func: F) -> gpointer { let func: Box>> = Box::new(ThreadGuard::new(RefCell::new(func))); Box::into_raw(func) as gpointer } unsafe extern "C" fn trampoline_child_watch( pid: ffi::GPid, status: i32, func: gpointer, ) { let func: &RefCell = &*(func as *const RefCell); (*func.borrow_mut())(Pid(pid), status) } unsafe extern "C" fn trampoline_child_watch_local( pid: ffi::GPid, status: i32, func: gpointer, ) { let func: &ThreadGuard> = &*(func as *const ThreadGuard>); (*func.get_ref().borrow_mut())(Pid(pid), status) } unsafe extern "C" fn destroy_closure_child_watch( ptr: gpointer, ) { let _ = Box::>::from_raw(ptr as *mut _); } unsafe extern "C" fn destroy_closure_child_watch_local( ptr: gpointer, ) { let _ = 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 } fn into_raw_child_watch_local(func: F) -> gpointer { let func: Box>> = Box::new(ThreadGuard::new(RefCell::new(func))); Box::into_raw(func) as gpointer } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] unsafe extern "C" fn trampoline_unix_fd< F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static, >( fd: i32, condition: ffi::GIOCondition, func: gpointer, ) -> gboolean { let func: &RefCell = &*(func as *const RefCell); (*func.borrow_mut())(fd, from_glib(condition)).into_glib() } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] unsafe extern "C" fn trampoline_unix_fd_local< F: FnMut(RawFd, IOCondition) -> ControlFlow + 'static, >( fd: i32, condition: ffi::GIOCondition, func: gpointer, ) -> gboolean { let func: &ThreadGuard> = &*(func as *const ThreadGuard>); (*func.get_ref().borrow_mut())(fd, from_glib(condition)).into_glib() } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] unsafe extern "C" fn destroy_closure_unix_fd< F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static, >( ptr: gpointer, ) { let _ = Box::>::from_raw(ptr as *mut _); } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] unsafe extern "C" fn destroy_closure_unix_fd_local< F: FnMut(RawFd, IOCondition) -> ControlFlow + 'static, >( ptr: gpointer, ) { let _ = Box::>>::from_raw(ptr as *mut _); } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] fn into_raw_unix_fd ControlFlow + Send + 'static>( func: F, ) -> gpointer { let func: Box> = Box::new(RefCell::new(func)); Box::into_raw(func) as gpointer } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] fn into_raw_unix_fd_local ControlFlow + 'static>( func: F, ) -> gpointer { let func: Box>> = Box::new(ThreadGuard::new(RefCell::new(func))); Box::into_raw(func) as gpointer } // rustdoc-stripper-ignore-next /// Transform a generic FnOnce into a closure that can be used as callback in various glib methods /// /// The resulting function can only be called once and will panic otherwise. It will return `ControlFlow::Break` /// in order to prevent being called twice. #[inline(always)] fn fnmut_callback_wrapper( func: impl FnOnce() + Send + 'static, ) -> impl FnMut() -> ControlFlow + Send + 'static { let mut func = Some(func); move || { let func = func .take() .expect("GSource closure called after returning ControlFlow::Break"); func(); ControlFlow::Break } } // rustdoc-stripper-ignore-next /// Transform a generic FnOnce into a closure that can be used as callback in various glib methods /// /// The resulting function can only be called once and will panic otherwise. It will return `ControlFlow::Break` /// in order to prevent being called twice. /// /// Different to `fnmut_callback_wrapper()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. #[inline(always)] fn fnmut_callback_wrapper_local( func: impl FnOnce() + 'static, ) -> impl FnMut() -> ControlFlow + 'static { let mut func = Some(func); move || { let func = func .take() .expect("GSource closure called after returning glib::ControlFlow::Break"); func(); ControlFlow::Break } } // rustdoc-stripper-ignore-next /// Adds a closure to be called by the default main loop when it's idle. /// /// `func` will be called repeatedly until it returns `ControlFlow::Break`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. #[doc(alias = "g_idle_add_full")] pub fn idle_add(func: F) -> SourceId where F: FnMut() -> ControlFlow + Send + 'static, { unsafe { from_glib(ffi::g_idle_add_full( ffi::G_PRIORITY_DEFAULT_IDLE, Some(trampoline::), into_raw(func), Some(destroy_closure::), )) } } // rustdoc-stripper-ignore-next /// Adds a closure to be called by the default main loop when it's idle. /// /// `func` will be called repeatedly with `priority` until it returns /// `ControlFlow::Break`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. #[doc(alias = "g_idle_add_full")] pub fn idle_add_full(priority: Priority, func: F) -> SourceId where F: FnMut() -> ControlFlow + Send + 'static, { unsafe { from_glib(ffi::g_idle_add_full( priority.into_glib(), Some(trampoline::), into_raw(func), Some(destroy_closure::), )) } } // rustdoc-stripper-ignore-next /// Adds a closure to be called by the default main loop when it's idle. /// /// `func` will be called repeatedly until it returns `ControlFlow::Break`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// In comparison to `idle_add()`, this only requires `func` to be /// `FnOnce`, and will automatically return `ControlFlow::Break`. #[doc(alias = "g_idle_add_full")] #[doc(alias = "g_idle_add_once")] pub fn idle_add_once(func: F) -> SourceId where F: FnOnce() + Send + 'static, { idle_add(fnmut_callback_wrapper(func)) } // rustdoc-stripper-ignore-next /// Adds a closure to be called by the default main loop when it's idle. /// /// `func` will be called repeatedly until it returns `ControlFlow::Break`. /// /// 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 default main context. #[doc(alias = "g_idle_add_full")] pub fn idle_add_local(func: F) -> SourceId where F: FnMut() -> ControlFlow + 'static, { unsafe { let context = MainContext::default(); let _acquire = context .acquire() .expect("default main context already acquired by another thread"); from_glib(ffi::g_idle_add_full( ffi::G_PRIORITY_DEFAULT_IDLE, Some(trampoline_local::), into_raw_local(func), Some(destroy_closure_local::), )) } } // rustdoc-stripper-ignore-next /// Adds a closure to be called by the default main loop when it's idle. /// /// `func` will be called repeatedly with `priority` until it returns /// `ControlFlow::Break`. /// /// 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 default main context. #[doc(alias = "g_idle_add_full")] pub fn idle_add_local_full(priority: Priority, func: F) -> SourceId where F: FnMut() -> ControlFlow + 'static, { unsafe { let context = MainContext::default(); let _acquire = context .acquire() .expect("default main context already acquired by another thread"); from_glib(ffi::g_idle_add_full( priority.into_glib(), Some(trampoline_local::), into_raw_local(func), Some(destroy_closure_local::), )) } } // rustdoc-stripper-ignore-next /// Adds a closure to be called by the default main loop when it's idle. /// /// `func` will be called repeatedly until it returns `ControlFlow::Break`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `idle_add()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. /// /// In comparison to `idle_add_local()`, this only requires `func` to be /// `FnOnce`, and will automatically return `ControlFlow::Break`. #[doc(alias = "g_idle_add_full")] pub fn idle_add_local_once(func: F) -> SourceId where F: FnOnce() + 'static, { idle_add_local(fnmut_callback_wrapper_local(func)) } // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. Prefer `timeout_add_seconds` when millisecond /// precision is not necessary. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. #[doc(alias = "g_timeout_add_full")] pub fn timeout_add(interval: Duration, func: F) -> SourceId where F: FnMut() -> ControlFlow + Send + 'static, { unsafe { from_glib(ffi::g_timeout_add_full( ffi::G_PRIORITY_DEFAULT, interval.as_millis() as _, Some(trampoline::), into_raw(func), Some(destroy_closure::), )) } } // rustdoc-stripper-ignore-next /// 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 with `priority` /// until it returns `ControlFlow::Break`. Precise timing is not guaranteed, the /// timeout may be delayed by other events. Prefer `timeout_add_seconds` when /// millisecond precision is not necessary. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. #[doc(alias = "g_timeout_add_full")] pub fn timeout_add_full(interval: Duration, priority: Priority, func: F) -> SourceId where F: FnMut() -> ControlFlow + Send + 'static, { unsafe { from_glib(ffi::g_timeout_add_full( priority.into_glib(), interval.as_millis() as _, Some(trampoline::), into_raw(func), Some(destroy_closure::), )) } } // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. Prefer `timeout_add_seconds` when millisecond /// precision is not necessary. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// In comparison to `timeout_add()`, this only requires `func` to be /// `FnOnce`, and will automatically return `ControlFlow::Break`. #[doc(alias = "g_timeout_add_full")] #[doc(alias = "g_timeout_add_once")] pub fn timeout_add_once(interval: Duration, func: F) -> SourceId where F: FnOnce() + Send + 'static, { timeout_add(interval, fnmut_callback_wrapper(func)) } // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. Prefer `timeout_add_seconds` when millisecond /// precision is not necessary. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `timeout_add()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. #[doc(alias = "g_timeout_add_full")] pub fn timeout_add_local(interval: Duration, func: F) -> SourceId where F: FnMut() -> ControlFlow + 'static, { unsafe { let context = MainContext::default(); let _acquire = context .acquire() .expect("default main context already acquired by another thread"); from_glib(ffi::g_timeout_add_full( ffi::G_PRIORITY_DEFAULT, interval.as_millis() as _, Some(trampoline_local::), into_raw_local(func), Some(destroy_closure_local::), )) } } // rustdoc-stripper-ignore-next /// 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 with `priority` /// until it returns `ControlFlow::Break`. Precise timing is not guaranteed, the /// timeout may be delayed by other events. Prefer `timeout_add_seconds` when /// millisecond precision is not necessary. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `timeout_add()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. #[doc(alias = "g_timeout_add_full")] pub fn timeout_add_local_full(interval: Duration, priority: Priority, func: F) -> SourceId where F: FnMut() -> ControlFlow + 'static, { unsafe { let context = MainContext::default(); let _acquire = context .acquire() .expect("default main context already acquired by another thread"); from_glib(ffi::g_timeout_add_full( priority.into_glib(), interval.as_millis() as _, Some(trampoline_local::), into_raw_local(func), Some(destroy_closure_local::), )) } } // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. Prefer `timeout_add_seconds` when millisecond /// precision is not necessary. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `timeout_add()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. /// /// In comparison to `timeout_add_local()`, this only requires `func` to be /// `FnOnce`, and will automatically return `ControlFlow::Break`. #[doc(alias = "g_timeout_add_full")] pub fn timeout_add_local_once(interval: Duration, func: F) -> SourceId where F: FnOnce() + 'static, { timeout_add_local(interval, fnmut_callback_wrapper_local(func)) } // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. #[doc(alias = "g_timeout_add_seconds_full")] pub fn timeout_add_seconds(interval: u32, func: F) -> SourceId where F: FnMut() -> ControlFlow + Send + 'static, { unsafe { from_glib(ffi::g_timeout_add_seconds_full( ffi::G_PRIORITY_DEFAULT, interval, Some(trampoline::), into_raw(func), Some(destroy_closure::), )) } } // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// In comparison to `timeout_add_seconds()`, this only requires `func` to be /// `FnOnce`, and will automatically return `ControlFlow::Break`. #[doc(alias = "g_timeout_add_seconds_full")] pub fn timeout_add_seconds_once(interval: u32, func: F) -> SourceId where F: FnOnce() + Send + 'static, { timeout_add_seconds(interval, fnmut_callback_wrapper(func)) } // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `timeout_add_seconds()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. #[doc(alias = "g_timeout_add_seconds_full")] pub fn timeout_add_seconds_local(interval: u32, func: F) -> SourceId where F: FnMut() -> ControlFlow + 'static, { unsafe { let context = MainContext::default(); let _acquire = context .acquire() .expect("default main context already acquired by another thread"); from_glib(ffi::g_timeout_add_seconds_full( ffi::G_PRIORITY_DEFAULT, interval, Some(trampoline_local::), into_raw_local(func), Some(destroy_closure_local::), )) } } // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `timeout_add_seconds()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. /// /// In comparison to `timeout_add_seconds_local()`, this only requires `func` to be /// `FnOnce`, and will automatically return `ControlFlow::Break`. #[doc(alias = "g_timeout_add_seconds_full")] pub fn timeout_add_seconds_local_once(interval: u32, func: F) -> SourceId where F: FnOnce() + 'static, { timeout_add_seconds_local(interval, fnmut_callback_wrapper_local(func)) } // rustdoc-stripper-ignore-next /// Adds a closure to be called by the main loop the returned `Source` is attached to when a child /// process exits. /// /// `func` will be called when `pid` exits #[doc(alias = "g_child_watch_add_full")] pub fn child_watch_add(pid: Pid, func: F) -> SourceId where F: FnMut(Pid, i32) + Send + 'static, { unsafe { from_glib(ffi::g_child_watch_add_full( ffi::G_PRIORITY_DEFAULT, pid.0, Some(trampoline_child_watch::), into_raw_child_watch(func), Some(destroy_closure_child_watch::), )) } } // rustdoc-stripper-ignore-next /// Adds a closure to be called by the main loop the returned `Source` is attached to when a child /// process exits. /// /// `func` will be called when `pid` exits /// /// Different to `child_watch_add()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. #[doc(alias = "g_child_watch_add_full")] pub fn child_watch_add_local(pid: Pid, func: F) -> SourceId where F: FnMut(Pid, i32) + 'static, { unsafe { let context = MainContext::default(); let _acquire = context .acquire() .expect("default main context already acquired by another thread"); from_glib(ffi::g_child_watch_add_full( ffi::G_PRIORITY_DEFAULT, pid.0, Some(trampoline_child_watch_local::), into_raw_child_watch_local(func), Some(destroy_closure_child_watch_local::), )) } } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. #[doc(alias = "g_unix_signal_add_full")] pub fn unix_signal_add(signum: i32, func: F) -> SourceId where F: FnMut() -> ControlFlow + Send + 'static, { unsafe { from_glib(ffi::g_unix_signal_add_full( ffi::G_PRIORITY_DEFAULT, signum, Some(trampoline::), into_raw(func), Some(destroy_closure::), )) } } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// In comparison to `unix_signal_add()`, this only requires `func` to be /// `FnOnce`, and will automatically return `ControlFlow::Break`. #[doc(alias = "g_unix_signal_add_full")] pub fn unix_signal_add_once(signum: i32, func: F) -> SourceId where F: FnOnce() + Send + 'static, { unix_signal_add(signum, fnmut_callback_wrapper(func)) } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `unix_signal_add()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. #[doc(alias = "g_unix_signal_add_full")] pub fn unix_signal_add_local(signum: i32, func: F) -> SourceId where F: FnMut() -> ControlFlow + 'static, { unsafe { let context = MainContext::default(); let _acquire = context .acquire() .expect("default main context already acquired by another thread"); from_glib(ffi::g_unix_signal_add_full( ffi::G_PRIORITY_DEFAULT, signum, Some(trampoline_local::), into_raw_local(func), Some(destroy_closure_local::), )) } } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `unix_signal_add()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. /// /// In comparison to `unix_signal_add_local()`, this only requires `func` to be /// `FnOnce`, and will automatically return `ControlFlow::Break`. #[doc(alias = "g_unix_signal_add_full")] pub fn unix_signal_add_local_once(signum: i32, func: F) -> SourceId where F: FnOnce() + 'static, { unix_signal_add_local(signum, fnmut_callback_wrapper_local(func)) } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. #[doc(alias = "g_unix_fd_add_full")] pub fn unix_fd_add(fd: RawFd, condition: IOCondition, func: F) -> SourceId where F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static, { unsafe { from_glib(ffi::g_unix_fd_add_full( ffi::G_PRIORITY_DEFAULT, fd, condition.into_glib(), Some(trampoline_unix_fd::), into_raw_unix_fd(func), Some(destroy_closure_unix_fd::), )) } } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] // rustdoc-stripper-ignore-next /// 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 with `priority` while the file descriptor matches the given IO condition /// until it returns `ControlFlow::Break`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. #[doc(alias = "g_unix_fd_add_full")] pub fn unix_fd_add_full( fd: RawFd, priority: Priority, condition: IOCondition, func: F, ) -> SourceId where F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static, { unsafe { from_glib(ffi::g_unix_fd_add_full( priority.into_glib(), fd, condition.into_glib(), Some(trampoline_unix_fd::), into_raw_unix_fd(func), Some(destroy_closure_unix_fd::), )) } } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `unix_fd_add()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. #[doc(alias = "g_unix_fd_add_full")] pub fn unix_fd_add_local(fd: RawFd, condition: IOCondition, func: F) -> SourceId where F: FnMut(RawFd, IOCondition) -> ControlFlow + 'static, { unsafe { let context = MainContext::default(); let _acquire = context .acquire() .expect("default main context already acquired by another thread"); from_glib(ffi::g_unix_fd_add_full( ffi::G_PRIORITY_DEFAULT, fd, condition.into_glib(), Some(trampoline_unix_fd_local::), into_raw_unix_fd_local(func), Some(destroy_closure_unix_fd_local::), )) } } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] // rustdoc-stripper-ignore-next /// 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 with `priority` while the file descriptor matches the given IO condition /// until it returns `ControlFlow::Break`. /// /// The default main loop almost always is the main loop of the main thread. /// Thus, the closure is called on the main thread. /// /// Different to `unix_fd_add()`, this does not require `func` to be /// `Send` but can only be called from the thread that owns the main context. /// /// This function panics if called from a different thread than the one that /// owns the main context. #[doc(alias = "g_unix_fd_add_full")] pub fn unix_fd_add_local_full( fd: RawFd, priority: Priority, condition: IOCondition, func: F, ) -> SourceId where F: FnMut(RawFd, IOCondition) -> ControlFlow + 'static, { unsafe { let context = MainContext::default(); let _acquire = context .acquire() .expect("default main context already acquired by another thread"); from_glib(ffi::g_unix_fd_add_full( priority.into_glib(), fd, condition.into_glib(), Some(trampoline_unix_fd_local::), into_raw_unix_fd_local(func), Some(destroy_closure_unix_fd_local::), )) } } // rustdoc-stripper-ignore-next /// The priority of sources #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] pub struct Priority(i32); impl Priority { #[doc(alias = "G_PRIORITY_HIGH")] pub const HIGH: Self = Self(ffi::G_PRIORITY_HIGH); #[doc(alias = "G_PRIORITY_DEFAULT")] pub const DEFAULT: Self = Self(ffi::G_PRIORITY_DEFAULT); #[doc(alias = "G_PRIORITY_HIGH_IDLE")] pub const HIGH_IDLE: Self = Self(ffi::G_PRIORITY_HIGH_IDLE); #[doc(alias = "G_PRIORITY_DEFAULT_IDLE")] pub const DEFAULT_IDLE: Self = Self(ffi::G_PRIORITY_DEFAULT_IDLE); #[doc(alias = "G_PRIORITY_LOW")] pub const LOW: Self = Self(ffi::G_PRIORITY_LOW); } impl Default for Priority { fn default() -> Self { Self::DEFAULT } } #[doc(hidden)] impl IntoGlib for Priority { type GlibType = i32; #[inline] fn into_glib(self) -> i32 { self.0 } } #[doc(hidden)] impl FromGlib for Priority { #[inline] unsafe fn from_glib(val: i32) -> Self { Self::from(val) } } impl From for Priority { fn from(value: i32) -> Self { Self(value) } } // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. #[doc(alias = "g_idle_source_new")] pub fn idle_source_new(name: Option<&str>, priority: Priority, func: F) -> Source where F: FnMut() -> ControlFlow + Send + 'static, { unsafe { let source = ffi::g_idle_source_new(); ffi::g_source_set_callback( source, Some(trampoline::), into_raw(func), Some(destroy_closure::), ); ffi::g_source_set_priority(source, priority.into_glib()); if let Some(name) = name { ffi::g_source_set_name(source, name.to_glib_none().0); } from_glib_full(source) } } // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. Prefer `timeout_add_seconds` when millisecond /// precision is not necessary. #[doc(alias = "g_timeout_source_new")] pub fn timeout_source_new( interval: Duration, name: Option<&str>, priority: Priority, func: F, ) -> Source where F: FnMut() -> ControlFlow + Send + 'static, { unsafe { let source = ffi::g_timeout_source_new(interval.as_millis() as _); ffi::g_source_set_callback( source, Some(trampoline::), into_raw(func), Some(destroy_closure::), ); ffi::g_source_set_priority(source, priority.into_glib()); if let Some(name) = name { ffi::g_source_set_name(source, name.to_glib_none().0); } from_glib_full(source) } } // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. Precise timing is not guaranteed, the timeout may /// be delayed by other events. #[doc(alias = "g_timeout_source_new_seconds")] pub fn timeout_source_new_seconds( interval: u32, name: Option<&str>, priority: Priority, func: F, ) -> Source where F: FnMut() -> ControlFlow + Send + 'static, { unsafe { let source = ffi::g_timeout_source_new_seconds(interval); ffi::g_source_set_callback( source, Some(trampoline::), into_raw(func), Some(destroy_closure::), ); ffi::g_source_set_priority(source, priority.into_glib()); if let Some(name) = name { ffi::g_source_set_name(source, name.to_glib_none().0); } from_glib_full(source) } } // rustdoc-stripper-ignore-next /// Adds a closure to be called by the main loop the returned `Source` is attached to when a child /// process exits. /// /// `func` will be called when `pid` exits #[doc(alias = "g_child_watch_source_new")] pub fn child_watch_source_new( pid: Pid, name: Option<&str>, priority: Priority, func: F, ) -> Source where F: FnMut(Pid, i32) + Send + 'static, { unsafe { let source = ffi::g_child_watch_source_new(pid.0); ffi::g_source_set_callback( source, Some(transmute::< *mut (), unsafe extern "C" fn(ffi::gpointer) -> ffi::gboolean, >(trampoline_child_watch:: as *mut ())), into_raw_child_watch(func), Some(destroy_closure_child_watch::), ); ffi::g_source_set_priority(source, priority.into_glib()); if let Some(name) = name { ffi::g_source_set_name(source, name.to_glib_none().0); } from_glib_full(source) } } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. #[doc(alias = "g_unix_signal_source_new")] pub fn unix_signal_source_new( signum: i32, name: Option<&str>, priority: Priority, func: F, ) -> Source where F: FnMut() -> ControlFlow + Send + 'static, { unsafe { let source = ffi::g_unix_signal_source_new(signum); ffi::g_source_set_callback( source, Some(trampoline::), into_raw(func), Some(destroy_closure::), ); ffi::g_source_set_priority(source, priority.into_glib()); if let Some(name) = name { ffi::g_source_set_name(source, name.to_glib_none().0); } from_glib_full(source) } } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] // rustdoc-stripper-ignore-next /// 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 `ControlFlow::Break`. #[doc(alias = "g_unix_fd_source_new")] pub fn unix_fd_source_new( fd: RawFd, condition: IOCondition, name: Option<&str>, priority: Priority, func: F, ) -> Source where F: FnMut(RawFd, IOCondition) -> ControlFlow + Send + 'static, { unsafe { let source = ffi::g_unix_fd_source_new(fd, condition.into_glib()); ffi::g_source_set_callback( source, Some(transmute::< *const (), unsafe extern "C" fn(ffi::gpointer) -> ffi::gboolean, >(trampoline_unix_fd:: as *const ())), into_raw_unix_fd(func), Some(destroy_closure_unix_fd::), ); ffi::g_source_set_priority(source, priority.into_glib()); if let Some(name) = name { ffi::g_source_set_name(source, name.to_glib_none().0); } from_glib_full(source) } } impl Source { #[doc(alias = "g_source_attach")] pub fn attach(&self, context: Option<&MainContext>) -> SourceId { unsafe { from_glib(ffi::g_source_attach( self.to_glib_none().0, context.to_glib_none().0, )) } } } glib-0.20.9/src/source_futures.rs000064400000000000000000000363461046102023000150570ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{pin, pin::Pin, time::Duration}; use futures_channel::{mpsc, oneshot}; use futures_core::{ future::{FusedFuture, Future}, stream::{FusedStream, Stream}, task, task::Poll, }; use crate::{ControlFlow, MainContext, Priority, Source}; // rustdoc-stripper-ignore-next /// Represents a `Future` around a `glib::Source`. The future will /// be resolved once the source has provided a value pub struct SourceFuture { create_source: Option, source: Option<(Source, oneshot::Receiver)>, } impl SourceFuture where F: FnOnce(oneshot::Sender) -> Source + 'static, { // rustdoc-stripper-ignore-next /// Create a new `SourceFuture` /// /// The provided closure should return a newly created `glib::Source` when called /// and pass the value provided by the source to the oneshot sender that is passed /// to the closure. pub fn new(create_source: F) -> SourceFuture { SourceFuture { create_source: Some(create_source), source: None, } } } impl Unpin for SourceFuture {} impl Future for SourceFuture where F: FnOnce(oneshot::Sender) -> Source + 'static, { type Output = T; fn poll(mut self: pin::Pin<&mut Self>, ctx: &mut task::Context) -> Poll { let SourceFuture { ref mut create_source, ref mut source, .. } = *self; if let Some(create_source) = create_source.take() { let main_context = MainContext::ref_thread_default(); assert!( main_context.is_owner(), "Spawning futures only allowed if the thread is owning the MainContext" ); // Channel for sending back the Source result to our future here. // // In theory, we could directly continue polling the // corresponding task from the Source callback, // however this would break at the very least // the g_main_current_source() API. let (send, recv) = oneshot::channel(); let s = create_source(send); s.attach(Some(&main_context)); *source = Some((s, recv)); } // At this point we must have a receiver let res = { let &mut (_, ref mut receiver) = source.as_mut().unwrap(); Pin::new(receiver).poll(ctx) }; #[allow(clippy::match_wild_err_arm)] match res { Poll::Ready(Err(_)) => panic!("Source sender was unexpectedly closed"), Poll::Ready(Ok(v)) => { // Get rid of the reference to the source, it triggered let _ = source.take(); Poll::Ready(v) } Poll::Pending => Poll::Pending, } } } impl FusedFuture for SourceFuture where F: FnOnce(oneshot::Sender) -> Source + 'static, { fn is_terminated(&self) -> bool { self.create_source.is_none() && self .source .as_ref() .map_or(true, |(_, receiver)| receiver.is_terminated()) } } 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(); } } } // rustdoc-stripper-ignore-next /// Create a `Future` that will resolve after the given number of milliseconds. /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn timeout_future(value: Duration) -> Pin + Send + 'static>> { timeout_future_with_priority(crate::Priority::default(), value) } // rustdoc-stripper-ignore-next /// Create a `Future` that will resolve after the given number of milliseconds. /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn timeout_future_with_priority( priority: Priority, value: Duration, ) -> Pin + Send + 'static>> { Box::pin(SourceFuture::new(move |send| { let mut send = Some(send); crate::timeout_source_new(value, None, priority, move || { let _ = send.take().unwrap().send(()); ControlFlow::Break }) })) } // rustdoc-stripper-ignore-next /// Create a `Future` that will resolve after the given number of seconds. /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn timeout_future_seconds(value: u32) -> Pin + Send + 'static>> { timeout_future_seconds_with_priority(crate::Priority::default(), value) } // rustdoc-stripper-ignore-next /// Create a `Future` that will resolve after the given number of seconds. /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn timeout_future_seconds_with_priority( priority: Priority, value: u32, ) -> Pin + Send + 'static>> { Box::pin(SourceFuture::new(move |send| { let mut send = Some(send); crate::timeout_source_new_seconds(value, None, priority, move || { let _ = send.take().unwrap().send(()); ControlFlow::Break }) })) } // rustdoc-stripper-ignore-next /// Create a `Future` that will resolve once the child process with the given pid exits /// /// The `Future` will resolve to the pid of the child process and the exit code. /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn child_watch_future( pid: crate::Pid, ) -> Pin + Send + 'static>> { child_watch_future_with_priority(crate::Priority::default(), pid) } // rustdoc-stripper-ignore-next /// Create a `Future` that will resolve once the child process with the given pid exits /// /// The `Future` will resolve to the pid of the child process and the exit code. /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn child_watch_future_with_priority( priority: Priority, pid: crate::Pid, ) -> Pin + Send + 'static>> { Box::pin(SourceFuture::new(move |send| { let mut send = Some(send); crate::child_watch_source_new(pid, None, priority, move |pid, code| { let _ = send.take().unwrap().send((pid, code)); }) })) } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] // rustdoc-stripper-ignore-next /// Create a `Future` that will resolve once the given UNIX signal is raised /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn unix_signal_future(signum: i32) -> Pin + Send + 'static>> { unix_signal_future_with_priority(crate::Priority::default(), signum) } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] // rustdoc-stripper-ignore-next /// Create a `Future` that will resolve once the given UNIX signal is raised /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn unix_signal_future_with_priority( priority: Priority, signum: i32, ) -> Pin + Send + 'static>> { Box::pin(SourceFuture::new(move |send| { let mut send = Some(send); crate::unix_signal_source_new(signum, None, priority, move || { let _ = send.take().unwrap().send(()); ControlFlow::Break }) })) } // rustdoc-stripper-ignore-next /// Represents a `Stream` around a `glib::Source`. The stream will /// be provide all values that are provided by the source pub struct SourceStream { create_source: Option, source: Option<(Source, mpsc::UnboundedReceiver)>, } impl Unpin for SourceStream {} impl SourceStream where F: FnOnce(mpsc::UnboundedSender) -> Source + 'static, { // rustdoc-stripper-ignore-next /// Create a new `SourceStream` /// /// The provided closure should return a newly created `glib::Source` when called /// and pass the values provided by the source to the sender that is passed /// to the closure. pub fn new(create_source: F) -> SourceStream { SourceStream { create_source: Some(create_source), source: None, } } } impl Stream for SourceStream where F: FnOnce(mpsc::UnboundedSender) -> Source + 'static, { type Item = T; fn poll_next(mut self: pin::Pin<&mut Self>, ctx: &mut task::Context) -> Poll> { let SourceStream { ref mut create_source, ref mut source, .. } = *self; if let Some(create_source) = create_source.take() { let main_context = MainContext::ref_thread_default(); assert!( main_context.is_owner(), "Spawning futures only allowed if the thread is owning the MainContext" ); // Channel for sending back the Source result to our future here. // // In theory we could directly continue polling the // corresponding task from the Source callback, // however this would break at the very least // the g_main_current_source() API. let (send, recv) = mpsc::unbounded(); let s = create_source(send); s.attach(Some(&main_context)); *source = Some((s, recv)); } // At this point we must have a receiver let res = { let &mut (_, ref mut receiver) = source.as_mut().unwrap(); Pin::new(receiver).poll_next(ctx) }; #[allow(clippy::match_wild_err_arm)] match res { Poll::Ready(v) => { if v.is_none() { // Get rid of the reference to the source, it triggered let _ = source.take(); } Poll::Ready(v) } Poll::Pending => Poll::Pending, } } } impl FusedStream for SourceStream where F: FnOnce(mpsc::UnboundedSender) -> Source + 'static, { fn is_terminated(&self) -> bool { self.create_source.is_none() && self .source .as_ref() .map_or(true, |(_, receiver)| receiver.is_terminated()) } } 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(); } } } // rustdoc-stripper-ignore-next /// Create a `Stream` that will provide a value every given number of milliseconds. /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn interval_stream(value: Duration) -> Pin + Send + 'static>> { interval_stream_with_priority(crate::Priority::default(), value) } // rustdoc-stripper-ignore-next /// Create a `Stream` that will provide a value every given number of milliseconds. /// /// The `Future` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn interval_stream_with_priority( priority: Priority, value: Duration, ) -> Pin + Send + 'static>> { Box::pin(SourceStream::new(move |send| { crate::timeout_source_new(value, None, priority, move || { if send.unbounded_send(()).is_err() { ControlFlow::Break } else { ControlFlow::Continue } }) })) } // rustdoc-stripper-ignore-next /// Create a `Stream` that will provide a value every given number of seconds. /// /// The `Stream` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn interval_stream_seconds(value: u32) -> Pin + Send + 'static>> { interval_stream_seconds_with_priority(crate::Priority::default(), value) } // rustdoc-stripper-ignore-next /// Create a `Stream` that will provide a value every given number of seconds. /// /// The `Stream` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn interval_stream_seconds_with_priority( priority: Priority, value: u32, ) -> Pin + Send + 'static>> { Box::pin(SourceStream::new(move |send| { crate::timeout_source_new_seconds(value, None, priority, move || { if send.unbounded_send(()).is_err() { ControlFlow::Break } else { ControlFlow::Continue } }) })) } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] // rustdoc-stripper-ignore-next /// Create a `Stream` that will provide a value whenever the given UNIX signal is raised /// /// The `Stream` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn unix_signal_stream(signum: i32) -> Pin + Send + 'static>> { unix_signal_stream_with_priority(crate::Priority::default(), signum) } #[cfg(unix)] #[cfg_attr(docsrs, doc(cfg(unix)))] // rustdoc-stripper-ignore-next /// Create a `Stream` that will provide a value whenever the given UNIX signal is raised /// /// The `Stream` must be spawned on an `Executor` backed by a `glib::MainContext`. pub fn unix_signal_stream_with_priority( priority: Priority, signum: i32, ) -> Pin + Send + 'static>> { Box::pin(SourceStream::new(move |send| { crate::unix_signal_source_new(signum, None, priority, move || { if send.unbounded_send(()).is_err() { ControlFlow::Break } else { ControlFlow::Continue } }) })) } #[cfg(test)] mod tests { use std::{thread, time::Duration}; use futures_util::{future::FutureExt, stream::StreamExt}; use super::*; #[test] fn test_timeout() { let c = MainContext::new(); c.block_on(timeout_future(Duration::from_millis(20))); } #[test] fn test_timeout_send() { let c = MainContext::new(); let l = crate::MainLoop::new(Some(&c), false); let l_clone = l.clone(); c.spawn(timeout_future(Duration::from_millis(20)).then(move |()| { l_clone.quit(); futures_util::future::ready(()) })); l.run(); } #[test] fn test_interval() { let c = MainContext::new(); let mut count = 0; { let count = &mut count; c.block_on( interval_stream(Duration::from_millis(20)) .take(2) .for_each(|()| { *count += 1; futures_util::future::ready(()) }) .map(|_| ()), ); } assert_eq!(count, 2); } #[test] fn test_timeout_and_channel() { let c = MainContext::new(); let res = c.block_on(timeout_future(Duration::from_millis(20)).then(|()| { let (sender, receiver) = oneshot::channel(); thread::spawn(move || { sender.send(1).unwrap(); }); receiver.then(|i| futures_util::future::ready(i.unwrap())) })); assert_eq!(res, 1); } } glib-0.20.9/src/subclass/basic.rs000064400000000000000000000040541046102023000146710ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! This module contains basic instance and class structs to be used for //! `GObject` subclasses that don't require any additional data in these //! structs and don't provide any new virtual methods. use std::{fmt, ops}; use super::prelude::*; use crate::prelude::*; // rustdoc-stripper-ignore-next /// A basic instance struct that does not store any additional data. #[repr(C)] pub struct InstanceStruct { parent: ::GlibType, } impl fmt::Debug for InstanceStruct where ::GlibType: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("InstanceStruct") .field("parent", &self.parent) .finish() } } unsafe impl super::types::InstanceStruct for InstanceStruct { type Type = T; } // rustdoc-stripper-ignore-next /// A basic class struct that does not store any additional data /// or virtual methods. #[repr(C)] pub struct ClassStruct { parent_class: ::GlibClassType, } impl fmt::Debug for ClassStruct where ::GlibClassType: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("InstanceStruct") .field("parent_class", &self.parent_class) .finish() } } unsafe impl super::types::ClassStruct for ClassStruct { type Type = T; } impl ops::Deref for ClassStruct { type Target = crate::Class<::Type>; #[inline] fn deref(&self) -> &Self::Target { unsafe { &*(self as *const _ as *const Self::Target) } } } impl ops::DerefMut for ClassStruct { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { unsafe { &mut *(self as *mut _ as *mut Self::Target) } } } glib-0.20.9/src/subclass/boxed.rs000064400000000000000000000110261046102023000147060ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! Module for registering boxed types for Rust types. use crate::{ffi, gobject_ffi, prelude::*, translate::*}; // rustdoc-stripper-ignore-next /// Trait for defining boxed types. /// /// Links together the type name with the type itself. /// /// See [`register_boxed_type`] for registering an implementation of this trait /// with the type system. /// /// [`register_boxed_type`]: fn.register_boxed_type.html pub trait BoxedType: StaticType + Clone + Sized + 'static { // rustdoc-stripper-ignore-next /// Boxed type name. /// /// This must be unique in the whole process. const NAME: &'static str; // rustdoc-stripper-ignore-next /// Allow name conflicts for this boxed type. /// /// By default, trying to register a type with a name that was registered before will panic. If /// this is set to `true` then a new name will be selected by appending a counter. /// /// This is useful for defining new types in Rust library crates that might be linked multiple /// times in the same process. /// /// A consequence of setting this to `true` is that it's not guaranteed that /// `glib::Type::from_name(Self::NAME).unwrap() == Self::static_type()`. /// /// Optional. const ALLOW_NAME_CONFLICT: bool = false; } // rustdoc-stripper-ignore-next /// Register a boxed `glib::Type` ID for `T`. /// /// This must be called only once and will panic on a second call. /// /// See [`Boxed!`] for defining a function that ensures that /// this is only called once and returns the type id. /// /// [`Boxed!`]: ../../derive.Boxed.html pub fn register_boxed_type() -> crate::Type { unsafe extern "C" fn boxed_copy(v: ffi::gpointer) -> ffi::gpointer { let v = &*(v as *mut T); let copy = Box::new(v.clone()); Box::into_raw(copy) as ffi::gpointer } unsafe extern "C" fn boxed_free(v: ffi::gpointer) { let v = v as *mut T; let _ = Box::from_raw(v); } unsafe { use std::ffi::CString; let type_name = if T::ALLOW_NAME_CONFLICT { let mut i = 0; loop { let type_name = CString::new(if i == 0 { T::NAME.to_string() } else { format!("{}-{}", T::NAME, i) }) .unwrap(); if gobject_ffi::g_type_from_name(type_name.as_ptr()) == gobject_ffi::G_TYPE_INVALID { break type_name; } i += 1; } } else { let type_name = CString::new(T::NAME).unwrap(); assert_eq!( gobject_ffi::g_type_from_name(type_name.as_ptr()), gobject_ffi::G_TYPE_INVALID, "Type {} has already been registered", type_name.to_str().unwrap() ); type_name }; let type_ = crate::Type::from_glib(gobject_ffi::g_boxed_type_register_static( type_name.as_ptr(), Some(boxed_copy::), Some(boxed_free::), )); assert!(type_.is_valid()); type_ } } #[cfg(test)] mod test { // We rename the current crate as glib, since the macros in glib-macros // generate the glib namespace through the crate_ident_new utility, // and that returns `glib` (and not `crate`) when called inside the glib crate use crate as glib; use crate::prelude::*; use crate::translate::{FromGlibPtrBorrow, FromGlibPtrFull, IntoGlibPtr}; #[derive(Clone, Debug, PartialEq, Eq, glib::Boxed)] #[boxed_type(name = "MyBoxed")] struct MyBoxed(String); #[test] fn test_register() { assert!(MyBoxed::static_type().is_valid()); } #[test] fn test_value() { assert!(MyBoxed::static_type().is_valid()); let b = MyBoxed(String::from("abc")); let v = b.to_value(); let b2 = v.get::<&MyBoxed>().unwrap(); assert_eq!(&b, b2); } #[test] fn test_from_glib_borrow() { assert!(MyBoxed::static_type().is_valid()); let b = MyBoxed(String::from("abc")); let raw_ptr = unsafe { MyBoxed::into_glib_ptr(b) }; // test that the from_glib_borrow does not take ownership of the raw_ptr let _ = unsafe { MyBoxed::from_glib_borrow(raw_ptr) }; let new_b = unsafe { MyBoxed::from_glib_full(raw_ptr) }; assert_eq!(new_b.0, "abc".to_string()); } } glib-0.20.9/src/subclass/interface.rs000064400000000000000000000260061046102023000155510ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{marker, mem}; use super::{types::InterfaceStruct, InitializingType, Signal}; use crate::{ ffi, gobject_ffi, prelude::*, translate::*, Object, ParamSpec, Type, TypeFlags, TypeInfo, }; // rustdoc-stripper-ignore-next /// Trait for a type list of prerequisite object types. pub trait PrerequisiteList { // rustdoc-stripper-ignore-next /// Returns the list of types for this list. fn types() -> Vec; } impl PrerequisiteList for () { fn types() -> Vec { vec![] } } impl PrerequisiteList for (T,) { fn types() -> Vec { vec![T::static_type()] } } // Generates all the PrerequisiteList impls for prerequisite_lists of arbitrary sizes based on a list of type // parameters like A B C. It would generate the impl then for (A, B) and (A, B, C). macro_rules! prerequisite_list_trait( ($name1:ident, $name2: ident, $($name:ident),*) => ( prerequisite_list_trait!(__impl $name1, $name2; $($name),*); ); (__impl $($name:ident),+; $name1:ident, $($name2:ident),*) => ( prerequisite_list_trait_impl!($($name),+); prerequisite_list_trait!(__impl $($name),+ , $name1; $($name2),*); ); (__impl $($name:ident),+; $name1:ident) => ( prerequisite_list_trait_impl!($($name),+); prerequisite_list_trait_impl!($($name),+, $name1); ); ); // Generates the impl block for PrerequisiteList on prerequisite_lists or arbitrary sizes based on its // arguments. Takes a list of type parameters as parameters, e.g. A B C // and then implements the trait on (A, B, C). macro_rules! prerequisite_list_trait_impl( ($($name:ident),+) => ( impl<$($name: ObjectType),+> PrerequisiteList for ( $($name),+ ) { fn types() -> Vec { vec![$($name::static_type()),+] } } ); ); prerequisite_list_trait!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S); /// Type methods required for an [`ObjectInterface`] implementation. /// /// This is usually generated by the [`#[object_interface]`](crate::object_interface) attribute macro. pub unsafe trait ObjectInterfaceType { /// Returns the `glib::Type` ID of the interface. /// /// This will register the type with the type system on the first call. #[doc(alias = "get_type")] fn type_() -> Type; } /// The central trait for defining a `GObject` interface. /// /// Links together the type name, the empty instance and class structs for type /// registration and allows hooking into various steps of the type registration /// and initialization. /// /// See [`register_interface`] for registering an implementation of this trait /// with the type system. /// /// [`register_interface`]: fn.register_interface.html pub trait ObjectInterface: ObjectInterfaceType + Sized + 'static { /// `GObject` type name. /// /// This must be unique in the whole process. const NAME: &'static str; // rustdoc-stripper-ignore-next /// Allow name conflicts for this class. /// /// By default, trying to register a type with a name that was registered before will panic. If /// this is set to `true` then a new name will be selected by appending a counter. /// /// This is useful for defining new types in Rust library crates that might be linked multiple /// times in the same process. /// /// A consequence of setting this to `true` is that it's not guaranteed that /// `glib::Type::from_name(Self::NAME).unwrap() == Self::type_()`. /// /// Note that this is not allowed for dynamic types. If a dynamic type is registered and a type /// with that name exists already, it is assumed that they're the same. /// /// Optional. const ALLOW_NAME_CONFLICT: bool = false; /// Prerequisites for this interface. /// /// Any implementer of the interface must be a subclass of the prerequisites or implement them /// in case of interfaces. type Prerequisites: PrerequisiteList; // rustdoc-stripper-ignore-next /// The C instance struct. This is usually either `std::ffi::c_void` or a newtype wrapper /// around it. /// /// Optional type Instance; // rustdoc-stripper-ignore-next /// The C class struct. type Interface: InterfaceStruct; /// Additional type initialization. /// /// This is called right after the type was registered and allows /// interfaces to do additional type-specific initialization. /// /// Optional fn type_init(_type_: &mut InitializingType) {} /// Interface initialization. /// /// This is called after `type_init` and before the first implementor /// of the interface is created. Interfaces can use this to do interface- /// specific initialization, e.g. for installing signals on the interface, /// and for setting default implementations of interface functions. /// /// Optional fn interface_init(_klass: &mut Self::Interface) {} /// Properties installed for this interface. /// /// All implementors of the interface must provide these properties. fn properties() -> &'static [ParamSpec] { &[] } /// Signals installed for this interface. fn signals() -> &'static [Signal] { &[] } } pub trait ObjectInterfaceExt: ObjectInterface { /// Get interface from an instance. /// /// This will panic if `obj` does not implement the interface. #[inline] #[deprecated = "Use from_obj() instead"] fn from_instance>(obj: &T) -> &Self { Self::from_obj(obj) } /// Get interface from an instance. /// /// This will panic if `obj` does not implement the interface. #[inline] fn from_obj>(obj: &T) -> &Self { assert!(obj.as_ref().type_().is_a(Self::type_())); unsafe { let klass = (*(obj.as_ptr() as *const gobject_ffi::GTypeInstance)).g_class; let interface = gobject_ffi::g_type_interface_peek(klass as *mut _, Self::type_().into_glib()); debug_assert!(!interface.is_null()); &*(interface as *const Self) } } } impl ObjectInterfaceExt for T {} unsafe extern "C" fn interface_init( klass: ffi::gpointer, _klass_data: ffi::gpointer, ) { let iface = &mut *(klass as *mut T::Interface); let pspecs = ::properties(); for pspec in pspecs { gobject_ffi::g_object_interface_install_property( iface as *mut T::Interface as *mut _, pspec.to_glib_none().0, ); } let type_ = T::type_(); let signals = ::signals(); for signal in signals { signal.register(type_); } T::interface_init(iface); } /// Register a `glib::Type` ID for `T::Class`. /// /// This must be called only once and will panic on a second call. /// /// The [`object_interface!`] macro will create a `type_()` function around this, which will /// ensure that it's only ever called once. /// /// [`object_interface!`]: ../../macro.object_interface.html pub fn register_interface() -> Type { assert_eq!(mem::size_of::(), 0); unsafe { use std::ffi::CString; let type_name = if T::ALLOW_NAME_CONFLICT { let mut i = 0; loop { let type_name = CString::new(if i == 0 { T::NAME.to_string() } else { format!("{}-{}", T::NAME, i) }) .unwrap(); if gobject_ffi::g_type_from_name(type_name.as_ptr()) == gobject_ffi::G_TYPE_INVALID { break type_name; } i += 1; } } else { let type_name = CString::new(T::NAME).unwrap(); assert_eq!( gobject_ffi::g_type_from_name(type_name.as_ptr()), gobject_ffi::G_TYPE_INVALID, "Type {} has already been registered", type_name.to_str().unwrap() ); type_name }; let type_ = gobject_ffi::g_type_register_static_simple( Type::INTERFACE.into_glib(), type_name.as_ptr(), mem::size_of::() as u32, Some(interface_init::), 0, None, 0, ); let prerequisites = T::Prerequisites::types(); for prerequisite in prerequisites { gobject_ffi::g_type_interface_add_prerequisite(type_, prerequisite.into_glib()); } let type_ = Type::from_glib(type_); assert!(type_.is_valid()); T::type_init(&mut InitializingType::(type_, marker::PhantomData)); type_ } } /// Registers a `glib::Type` ID for `T::Class` as a dynamic type. /// /// An object interface must be explicitly registered as a dynamic type when /// the system loads the implementation by calling [`TypePluginImpl::use_`] or /// more specifically [`TypeModuleImpl::load`]. Therefore, unlike for object /// interfaces registered as static types, object interfaces registered as /// dynamic types can be registered several times. /// /// The [`object_interface_dynamic!`] macro helper attribute will create /// `register_interface()` and `on_implementation_load()` functions around this, /// which will ensure that the function is called when necessary. /// /// [`object_interface_dynamic!`]: ../../../glib_macros/attr.object_interface.html /// [`TypePluginImpl::use_`]: ../type_plugin/trait.TypePluginImpl.html#method.use_ /// [`TypeModuleImpl::load`]: ../type_module/trait.TypeModuleImpl.html#method.load pub fn register_dynamic_interface( type_plugin: &P, ) -> Type { assert_eq!(mem::size_of::(), 0); unsafe { use std::ffi::CString; let type_name = CString::new(T::NAME).unwrap(); let already_registered = gobject_ffi::g_type_from_name(type_name.as_ptr()) != gobject_ffi::G_TYPE_INVALID; let type_info = TypeInfo(gobject_ffi::GTypeInfo { class_size: mem::size_of::() as u16, class_init: Some(interface_init::), ..TypeInfo::default().0 }); // registers the interface within the `type_plugin` let type_ = type_plugin.register_dynamic_type( Type::INTERFACE, type_name.to_str().unwrap(), &type_info, TypeFlags::ABSTRACT, ); let prerequisites = T::Prerequisites::types(); for prerequisite in prerequisites { // adding prerequisite interface can be done only once if !already_registered { gobject_ffi::g_type_interface_add_prerequisite( type_.into_glib(), prerequisite.into_glib(), ); } } assert!(type_.is_valid()); T::type_init(&mut InitializingType::(type_, marker::PhantomData)); type_ } } glib-0.20.9/src/subclass/mod.rs000064400000000000000000000407561046102023000144000ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #![allow(clippy::needless_doctest_main)] // rustdoc-stripper-ignore-next //! Module containing infrastructure for subclassing `GObject`s and registering boxed types. //! //! # Example for registering a `glib::Object` subclass //! //! The following code implements a subclass of `glib::Object` with a //! string-typed "name" property. //! //! ```rust //! use glib::prelude::*; //! use glib::subclass; //! use glib::subclass::prelude::*; //! use glib::{Variant, VariantType}; //! //! use std::cell::{Cell, RefCell}; //! //! #[derive(Debug, Eq, PartialEq, Clone, Copy, glib::Enum)] //! #[repr(u32)] //! // type_name: GType name of the enum (mandatory) //! #[enum_type(name = "SimpleObjectAnimal")] //! enum Animal { //! Goat = 0, //! #[enum_value(name = "The Dog")] //! Dog = 1, //! // name: the name of the GEnumValue (optional), default to the enum name in CamelCase //! // nick: the nick of the GEnumValue (optional), default to the enum name in kebab-case //! #[enum_value(name = "The Cat", nick = "chat")] //! Cat = 2, //! } //! //! impl Default for Animal { //! fn default() -> Self { //! Animal::Goat //! } //! } //! //! #[glib::flags(name = "MyFlags")] //! enum MyFlags { //! #[flags_value(name = "Flag A", nick = "nick-a")] //! A = 0b00000001, //! #[flags_value(name = "Flag B")] //! B = 0b00000010, //! #[flags_value(skip)] //! AB = Self::A.bits() | Self::B.bits(), //! C = 0b00000100, //! } //! //! impl Default for MyFlags { //! fn default() -> Self { //! MyFlags::A //! } //! } //! //! mod imp { //! use super::*; //! //! // This is the struct containing all state carried with //! // the new type. Generally this has to make use of //! // interior mutability. //! // If it implements the `Default` trait, then `Self::default()` //! // will be called every time a new instance is created. //! #[derive(Default)] //! pub struct SimpleObject { //! name: RefCell>, //! animal: Cell, //! flags: Cell, //! variant: RefCell>, //! } //! //! // ObjectSubclass is the trait that defines the new type and //! // contains all information needed by the GObject type system, //! // including the new type's name, parent type, etc. //! // If you do not want to implement `Default`, you can provide //! // a `new()` method. //! #[glib::object_subclass] //! impl ObjectSubclass for SimpleObject { //! // This type name must be unique per process. //! const NAME: &'static str = "SimpleObject"; //! //! type Type = super::SimpleObject; //! //! // The parent type this one is inheriting from. //! // Optional, if not specified it defaults to `glib::Object` //! type ParentType = glib::Object; //! //! // Interfaces this type implements. //! // Optional, if not specified it defaults to `()` //! type Interfaces = (); //! } //! //! // Trait that is used to override virtual methods of glib::Object. //! impl ObjectImpl for SimpleObject { //! // Called once in the very beginning to list all properties of this class. //! fn properties() -> &'static [glib::ParamSpec] { //! use std::sync::OnceLock; //! static PROPERTIES: OnceLock> = OnceLock::new(); //! PROPERTIES.get_or_init(|| { //! vec![ //! glib::ParamSpecString::builder("name") //! .build(), //! glib::ParamSpecEnum::builder::("animal") //! .build(), //! glib::ParamSpecFlags::builder::("flags") //! .build(), //! glib::ParamSpecVariant::builder("variant", glib::VariantTy::ANY) //! .build(), //! ] //! }) //! } //! //! // 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, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) { //! match pspec.name() { //! "name" => { //! let name = value //! .get() //! .expect("type conformity checked by `Object::set_property`"); //! self.name.replace(name); //! }, //! "animal" => { //! let animal = value //! .get() //! .expect("type conformity checked by `Object::set_property`"); //! self.animal.replace(animal); //! }, //! "flags" => { //! let flags = value //! .get() //! .expect("type conformity checked by `Object::set_property`"); //! self.flags.replace(flags); //! }, //! "variant" => { //! let variant = value //! .get() //! .expect("type conformity checked by `Object::set_property`"); //! self.variant.replace(variant); //! }, //! _ => unimplemented!(), //! } //! } //! //! // Called whenever a property is retrieved from this instance. The id //! // is the same as the index of the property in the PROPERTIES array. //! fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { //! match pspec.name() { //! "name" => self.name.borrow().to_value(), //! "animal" => self.animal.get().to_value(), //! "flags" => self.flags.get().to_value(), //! "variant" => self.variant.borrow().to_value(), //! _ => unimplemented!(), //! } //! } //! //! // Called right after construction of the instance. //! fn constructed(&self) { //! // Chain up to the parent type's implementation of this virtual //! // method. //! self.parent_constructed(); //! //! // And here we could do our own initialization. //! } //! } //! } //! //! // Optionally, define a wrapper type to make it more ergonomic to use from Rust //! glib::wrapper! { //! pub struct SimpleObject(ObjectSubclass); //! } //! //! impl SimpleObject { //! // Create an object instance of the new type. //! pub fn new() -> Self { //! glib::Object::new() //! } //! } //! //! pub fn main() { //! let obj = SimpleObject::new(); //! //! // Get the name property and change its value. //! assert_eq!(obj.property::>("name"), None); //! obj.set_property("name", "test"); //! assert_eq!(&obj.property::("name"), "test"); //! //! assert_eq!(obj.property::("animal"), Animal::Goat); //! obj.set_property("animal", Animal::Cat); //! assert_eq!(obj.property::("animal"), Animal::Cat); //! //! assert_eq!(obj.property::("flags"), MyFlags::A); //! obj.set_property("flags", MyFlags::B); //! assert_eq!(obj.property::("flags"), MyFlags::B); //! } //! ``` //! //! # Example for registering a `glib::Object` subclass within a module //! //! The following code implements a subclass of `glib::Object` and registers it as //! a dynamic type. //! //! ```rust //! use glib::prelude::*; //! use glib::subclass::prelude::*; //! //! pub mod imp { //! use super::*; //! //! // SimpleModuleObject is a dynamic type. //! #[derive(Default)] //! pub struct SimpleModuleObject; //! //! #[glib::object_subclass] //! #[object_subclass_dynamic] //! impl ObjectSubclass for SimpleModuleObject { //! const NAME: &'static str = "SimpleModuleObject"; //! type Type = super::SimpleModuleObject; //! } //! //! impl ObjectImpl for SimpleModuleObject {} //! //! // SimpleTypeModule is the type module within the object subclass is registered as a dynamic type. //! #[derive(Default)] //! pub struct SimpleTypeModule; //! //! #[glib::object_subclass] //! impl ObjectSubclass for SimpleTypeModule { //! const NAME: &'static str = "SimpleTypeModule"; //! type Type = super::SimpleTypeModule; //! type ParentType = glib::TypeModule; //! type Interfaces = (glib::TypePlugin,); //! } //! //! impl ObjectImpl for SimpleTypeModule {} //! //! impl TypeModuleImpl for SimpleTypeModule { //! /// Loads the module and registers the object subclass as a dynamic type. //! fn load(&self) -> bool { //! SimpleModuleObject::on_implementation_load(self.obj().upcast_ref::()) //! } //! //! /// Unloads the module. //! fn unload(&self) { //! SimpleModuleObject::on_implementation_unload(self.obj().upcast_ref::()); //! } //! } //! //! impl TypePluginImpl for SimpleTypeModule {} //! } //! //! // Optionally, defines a wrapper type to make SimpleModuleObject more ergonomic to use from Rust. //! glib::wrapper! { //! pub struct SimpleModuleObject(ObjectSubclass); //! } //! //! // Optionally, defines a wrapper type to make SimpleTypeModule more ergonomic to use from Rust. //! glib::wrapper! { //! pub struct SimpleTypeModule(ObjectSubclass) //! @extends glib::TypeModule, @implements glib::TypePlugin; //! } //! //! impl SimpleTypeModule { //! // Creates an object instance of the new type. //! pub fn new() -> Self { //! glib::Object::new() //! } //! } //! //! pub fn main() { //! let simple_type_module = SimpleTypeModule::new(); //! // at this step, SimpleTypeModule has not been loaded therefore //! // SimpleModuleObject must not be registered yet. //! let simple_module_object_type = imp::SimpleModuleObject::type_(); //! assert!(!simple_module_object_type.is_valid()); //! //! // simulates the GLib type system to load the module. //! TypeModuleExt::use_(&simple_type_module); //! //! // at this step, SimpleModuleObject must have been registered. //! let simple_module_object_type = imp::SimpleModuleObject::type_(); //! assert!(simple_module_object_type.is_valid()); //! } //! ``` //! //! # Example for registering a `glib::Object` subclass within a plugin //! //! The following code implements a subclass of `glib::Object` and registers it as //! a dynamic type. //! //! ```rust //! use glib::prelude::*; //! use glib::subclass::prelude::*; //! //! pub mod imp { //! use super::*; //! //! // SimplePluginObject is a dynamic type. //! #[derive(Default)] //! pub struct SimplePluginObject; //! //! #[glib::object_subclass] //! #[object_subclass_dynamic(plugin_type = super::SimpleTypePlugin)] //! impl ObjectSubclass for SimplePluginObject { //! const NAME: &'static str = "SimplePluginObject"; //! type Type = super::SimplePluginObject; //! } //! //! impl ObjectImpl for SimplePluginObject {} //! //! // SimpleTypePlugin is the type plugin within the object subclass is registered as a dynamic type. //! #[derive(Default)] //! pub struct SimpleTypePlugin { //! type_info: std::cell::Cell> //! } //! //! #[glib::object_subclass] //! impl ObjectSubclass for SimpleTypePlugin { //! const NAME: &'static str = "SimpleTypePlugin"; //! type Type = super::SimpleTypePlugin; //! type Interfaces = (glib::TypePlugin,); //! } //! //! impl ObjectImpl for SimpleTypePlugin {} //! //! impl TypePluginImpl for SimpleTypePlugin { //! /// Uses the plugin and registers the object subclass as a dynamic type. //! fn use_plugin(&self) { //! SimplePluginObject::on_implementation_load(self.obj().as_ref()); //! } //! //! /// Unuses the plugin. //! fn unuse_plugin(&self) { //! SimplePluginObject::on_implementation_unload(self.obj().as_ref()); //! } //! //! /// Returns type information about the object subclass registered as a dynamic type. //! fn complete_type_info(&self, _type_: glib::Type) -> (glib::TypeInfo, glib::TypeValueTable) { //! assert!(self.type_info.get().is_some()); //! // returns type info. //! (self.type_info.get().unwrap(), glib::TypeValueTable::default()) //! } //! } //! //! impl TypePluginRegisterImpl for SimpleTypePlugin { //! fn register_dynamic_type(&self, parent_type: glib::Type, type_name: &str, type_info: &glib::TypeInfo, flags: glib::TypeFlags) -> glib::Type { //! let type_ = glib::Type::from_name(type_name).unwrap_or_else(|| { //! glib::Type::register_dynamic(parent_type, type_name, self.obj().upcast_ref::(), flags) //! }); //! if type_.is_valid() { //! // saves type info. //! self.type_info.set(Some(*type_info)); //! } //! type_ //! } //! } //! } //! //! // Optionally, defines a wrapper type to make SimplePluginObject more ergonomic to use from Rust. //! glib::wrapper! { //! pub struct SimplePluginObject(ObjectSubclass); //! } //! //! // Optionally, defines a wrapper type to make SimpleTypePlugin more ergonomic to use from Rust. //! glib::wrapper! { //! pub struct SimpleTypePlugin(ObjectSubclass) //! @implements glib::TypePlugin; //! } //! //! impl SimpleTypePlugin { //! // Creates an object instance of the new type. //! pub fn new() -> Self { //! glib::Object::new() //! } //! } //! //! pub fn main() { //! let simple_type_plugin = SimpleTypePlugin::new(); //! // at this step, SimpleTypePlugin has not been used therefore //! // SimplePluginObject must not be registered yet. //! let simple_plugin_object_type = imp::SimplePluginObject::type_(); //! assert!(!simple_plugin_object_type.is_valid()); //! //! // simulates the GLib type system to use the plugin. //! TypePluginExt::use_(&simple_type_plugin); //! //! // at this step, SimplePluginObject must have been registered. //! let simple_plugin_object_type = imp::SimplePluginObject::type_(); //! assert!(simple_plugin_object_type.is_valid()); //! } //! ``` //! //!//! # Example for registering a boxed type for a Rust struct //! //! The following code boxed type for a tuple struct around `String` and uses it in combination //! with `glib::Value`. //! //! ```rust //! use glib::prelude::*; //! use glib::subclass; //! use glib::subclass::prelude::*; //! //! #[derive(Clone, Debug, PartialEq, Eq, glib::Boxed)] //! #[boxed_type(name = "MyBoxed")] //! struct MyBoxed(String); //! //! pub fn main() { //! assert!(MyBoxed::static_type().is_valid()); //! //! let b = MyBoxed(String::from("abc")); //! let v = b.to_value(); //! let b2 = v.get::<&MyBoxed>().unwrap(); //! assert_eq!(&b, b2); //! } //! ``` pub mod basic; #[macro_use] pub mod types; #[macro_use] pub mod interface; #[macro_use] pub mod object; #[macro_use] pub mod boxed; pub mod shared; pub mod signal; mod object_impl_ref; pub use object_impl_ref::{ObjectImplRef, ObjectImplWeakRef}; pub mod type_module; pub mod type_plugin; pub mod prelude { // rustdoc-stripper-ignore-next //! Prelude that re-exports all important traits from this crate. pub use super::{ boxed::BoxedType, interface::{ObjectInterface, ObjectInterfaceExt, ObjectInterfaceType}, object::{DerivedObjectProperties, ObjectClassSubclassExt, ObjectImpl, ObjectImplExt}, shared::{RefCounted, SharedType}, type_module::{TypeModuleImpl, TypeModuleImplExt}, type_plugin::{TypePluginImpl, TypePluginImplExt, TypePluginRegisterImpl}, types::{ ClassStruct, InstanceStruct, InstanceStructExt, InterfaceStruct, IsImplementable, IsSubclassable, IsSubclassableExt, ObjectSubclass, ObjectSubclassExt, ObjectSubclassIsExt, ObjectSubclassType, }, }; } pub use self::{ boxed::register_boxed_type, interface::{register_dynamic_interface, register_interface}, signal::{ Signal, SignalClassHandlerToken, SignalId, SignalInvocationHint, SignalQuery, SignalType, }, types::{register_dynamic_type, register_type, InitializingObject, InitializingType, TypeData}, }; glib-0.20.9/src/subclass/object.rs000064400000000000000000000734201046102023000150610ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! Module that contains all types needed for creating a direct subclass of `GObject` //! or implementing virtual methods of it. use std::{mem, ptr}; use crate::{ ffi, gobject_ffi, prelude::*, subclass::{prelude::*, Signal}, translate::*, Object, ParamSpec, Slice, Value, }; // rustdoc-stripper-ignore-next /// Trait for implementors of `glib::Object` subclasses. /// /// This allows overriding the virtual methods of `glib::Object`. Except for /// `finalize` as implementing `Drop` would allow the same behavior. pub trait ObjectImpl: ObjectSubclass + ObjectImplExt { // rustdoc-stripper-ignore-next /// Properties installed for this type. fn properties() -> &'static [ParamSpec] { &[] } // rustdoc-stripper-ignore-next /// Signals installed for this type. fn signals() -> &'static [Signal] { &[] } // rustdoc-stripper-ignore-next /// 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`. /// /// `value` is guaranteed to be of the correct type for the given property. fn set_property(&self, _id: usize, _value: &Value, _pspec: &ParamSpec) { unimplemented!() } // rustdoc-stripper-ignore-next /// Property getter. /// /// This is called whenever the property value of the specific subclass with the /// given index should be returned. /// /// The returned `Value` must be of the correct type for the given property. #[doc(alias = "get_property")] fn property(&self, _id: usize, _pspec: &ParamSpec) -> Value { unimplemented!() } // rustdoc-stripper-ignore-next /// Constructed. /// /// This is called once construction of the instance is finished. /// /// Should chain up to the parent class' implementation. fn constructed(&self) { self.parent_constructed(); } // rustdoc-stripper-ignore-next /// Disposes of the object. /// /// When `dispose()` ends, the object should not hold any reference to any other member object. /// The object is also expected to be able to answer client method invocations (with possibly an /// error code but no memory violation) until it is dropped. `dispose()` can be executed more /// than once. fn dispose(&self) {} // rustdoc-stripper-ignore-next /// Function to be called when property change is notified for with /// `self.notify("property")`. fn notify(&self, pspec: &ParamSpec) { self.parent_notify(pspec) } fn dispatch_properties_changed(&self, pspecs: &[ParamSpec]) { self.parent_dispatch_properties_changed(pspecs) } } #[doc(alias = "get_property")] unsafe extern "C" fn property( obj: *mut gobject_ffi::GObject, id: u32, value: *mut gobject_ffi::GValue, pspec: *mut gobject_ffi::GParamSpec, ) { let instance = &*(obj as *mut T::Instance); let imp = instance.imp(); let v = imp.property(id as usize, &from_glib_borrow(pspec)); // We first unset the value we get passed in, in case it contained // any previous data. Then we directly overwrite it with our new // value, and pass ownership of the contained data to the C GValue // by forgetting it on the Rust side. // // Without this, by using the GValue API, we would have to create // a copy of the value when setting it on the destination just to // immediately free the original value afterwards. gobject_ffi::g_value_unset(value); let v = mem::ManuallyDrop::new(v); ptr::write(value, ptr::read(v.to_glib_none().0)); } unsafe extern "C" fn set_property( obj: *mut gobject_ffi::GObject, id: u32, value: *mut gobject_ffi::GValue, pspec: *mut gobject_ffi::GParamSpec, ) { let instance = &*(obj as *mut T::Instance); let imp = instance.imp(); imp.set_property( id as usize, &*(value as *mut Value), &from_glib_borrow(pspec), ); } unsafe extern "C" fn constructed(obj: *mut gobject_ffi::GObject) { let instance = &*(obj as *mut T::Instance); let imp = instance.imp(); imp.constructed(); } unsafe extern "C" fn notify( obj: *mut gobject_ffi::GObject, pspec: *mut gobject_ffi::GParamSpec, ) { let instance = &*(obj as *mut T::Instance); let imp = instance.imp(); imp.notify(&from_glib_borrow(pspec)); } unsafe extern "C" fn dispatch_properties_changed( obj: *mut gobject_ffi::GObject, n_pspecs: u32, pspecs: *mut *mut gobject_ffi::GParamSpec, ) { let instance = &*(obj as *mut T::Instance); let imp = instance.imp(); imp.dispatch_properties_changed(Slice::from_glib_borrow_num(pspecs, n_pspecs as _)); } unsafe extern "C" fn dispose(obj: *mut gobject_ffi::GObject) { let instance = &*(obj as *mut T::Instance); let imp = instance.imp(); imp.dispose(); // Chain up to the parent's dispose. let data = T::type_data(); let parent_class = data.as_ref().parent_class() as *mut gobject_ffi::GObjectClass; if let Some(ref func) = (*parent_class).dispose { func(obj); } } // rustdoc-stripper-ignore-next /// Trait containing only the property related functions of [`ObjectImpl`]. /// Implemented by the [`Properties`](crate::Properties) macro. /// When implementing `ObjectImpl` you may want to delegate the function calls to this trait. pub trait DerivedObjectProperties: ObjectSubclass { // rustdoc-stripper-ignore-next /// Properties installed for this type. fn derived_properties() -> &'static [ParamSpec] { &[] } // rustdoc-stripper-ignore-next /// Similar to [`ObjectImpl`](trait.ObjectImpl.html) but auto-generated by the [`Properties`](crate::Properties) macro /// to allow handling more complex use-cases. fn derived_set_property(&self, _id: usize, _value: &Value, _pspec: &ParamSpec) { unimplemented!() } // rustdoc-stripper-ignore-next /// Similar to [`ObjectImpl`](trait.ObjectImpl.html) but auto-generated by the [`Properties`](crate::Properties) macro /// to allow handling more complex use-cases. fn derived_property(&self, _id: usize, _pspec: &ParamSpec) -> Value { unimplemented!() } } // rustdoc-stripper-ignore-next /// Extension trait for `glib::Object`'s class struct. /// /// This contains various class methods and allows subclasses to override signal class handlers. pub unsafe trait ObjectClassSubclassExt: Sized + 'static { fn override_signal_class_handler(&mut self, name: &str, class_handler: F) where F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option + Send + Sync + 'static, { unsafe { super::types::signal_override_class_handler( name, *(self as *mut _ as *mut ffi::GType), class_handler, ); } } } unsafe impl ObjectClassSubclassExt for crate::Class {} unsafe impl IsSubclassable for Object { fn class_init(class: &mut crate::Class) { let klass = class.as_mut(); klass.set_property = Some(set_property::); klass.get_property = Some(property::); klass.constructed = Some(constructed::); klass.notify = Some(notify::); klass.dispatch_properties_changed = Some(dispatch_properties_changed::); klass.dispose = Some(dispose::); let pspecs = ::properties(); if !pspecs.is_empty() { unsafe { let mut pspecs_ptrs = Vec::with_capacity(pspecs.len() + 1); pspecs_ptrs.push(ptr::null_mut()); for pspec in pspecs { pspecs_ptrs.push(pspec.to_glib_none().0); } gobject_ffi::g_object_class_install_properties( klass, pspecs_ptrs.len() as u32, pspecs_ptrs.as_mut_ptr(), ); } } let type_ = T::type_(); let signals = ::signals(); for signal in signals { signal.register(type_); } } #[inline] fn instance_init(_instance: &mut super::InitializingObject) {} } mod sealed { pub trait Sealed {} impl Sealed for T {} } pub trait ObjectImplExt: sealed::Sealed + ObjectSubclass { // rustdoc-stripper-ignore-next /// Chain up to the parent class' implementation of `glib::Object::constructed()`. #[inline] fn parent_constructed(&self) { unsafe { let data = Self::type_data(); let parent_class = data.as_ref().parent_class() as *mut gobject_ffi::GObjectClass; if let Some(ref func) = (*parent_class).constructed { func(self.obj().unsafe_cast_ref::().to_glib_none().0); } } } // rustdoc-stripper-ignore-next /// Chain up to the parent class' implementation of `glib::Object::notify()`. #[inline] fn parent_notify(&self, pspec: &ParamSpec) { unsafe { let data = Self::type_data(); let parent_class = data.as_ref().parent_class() as *mut gobject_ffi::GObjectClass; if let Some(ref func) = (*parent_class).notify { func( self.obj().unsafe_cast_ref::().to_glib_none().0, pspec.to_glib_none().0, ); } } } // rustdoc-stripper-ignore-next /// Chain up to the parent class' implementation of `glib::Object::dispatch_properties_changed()`. #[inline] fn parent_dispatch_properties_changed(&self, pspecs: &[ParamSpec]) { unsafe { let data = Self::type_data(); let parent_class = data.as_ref().parent_class() as *mut gobject_ffi::GObjectClass; if let Some(ref func) = (*parent_class).dispatch_properties_changed { func( self.obj().unsafe_cast_ref::().to_glib_none().0, pspecs.len() as _, pspecs.as_ptr() as *mut _, ); } } } // rustdoc-stripper-ignore-next /// Chain up to parent class signal handler. fn signal_chain_from_overridden( &self, token: &super::SignalClassHandlerToken, values: &[Value], ) -> Option { unsafe { super::types::signal_chain_from_overridden(self.obj().as_ptr() as *mut _, token, values) } } } impl ObjectImplExt for T {} #[cfg(test)] mod test { use std::cell::RefCell; use super::*; // We rename the current crate as glib, since the macros in glib-macros // generate the glib namespace through the crate_ident_new utility, // and that returns `glib` (and not `crate`) when called inside the glib crate use crate as glib; mod imp { use std::sync::OnceLock; use super::*; // A dummy `Object` to test setting an `Object` property and returning an `Object` in signals #[derive(Default)] pub struct ChildObject; #[glib::object_subclass] impl ObjectSubclass for ChildObject { const NAME: &'static str = "ChildObject"; type Type = super::ChildObject; } impl ObjectImpl for ChildObject {} pub struct SimpleObject { name: RefCell>, construct_name: RefCell>, constructed: RefCell, answer: RefCell, array: RefCell>, } impl Default for SimpleObject { fn default() -> Self { SimpleObject { name: Default::default(), construct_name: Default::default(), constructed: Default::default(), answer: RefCell::new(42i32), array: RefCell::new(vec!["default0".to_string(), "default1".to_string()]), } } } #[glib::object_subclass] impl ObjectSubclass for SimpleObject { const NAME: &'static str = "SimpleObject"; type Type = super::SimpleObject; type Interfaces = (super::Dummy,); } impl ObjectImpl for SimpleObject { fn properties() -> &'static [ParamSpec] { static PROPERTIES: OnceLock> = OnceLock::new(); PROPERTIES.get_or_init(|| { vec![ crate::ParamSpecString::builder("name").build(), crate::ParamSpecString::builder("construct-name") .construct_only() .build(), crate::ParamSpecBoolean::builder("constructed") .read_only() .build(), crate::ParamSpecObject::builder::("child").build(), crate::ParamSpecInt::builder("answer") .default_value(42i32) .build(), crate::ParamSpecValueArray::builder("array").build(), ] }) } fn signals() -> &'static [super::Signal] { static SIGNALS: OnceLock> = OnceLock::new(); SIGNALS.get_or_init(|| { vec![ super::Signal::builder("name-changed") .param_types([String::static_type()]) .build(), super::Signal::builder("change-name") .param_types([String::static_type()]) .return_type::() .action() .class_handler(|_, args| { let obj = args[0] .get::() .expect("Failed to get Object from args[0]"); let new_name = args[1] .get::() .expect("Failed to get Object from args[1]"); let imp = obj.imp(); let old_name = imp.name.replace(Some(new_name)); obj.emit_by_name::<()>("name-changed", &[&*imp.name.borrow()]); Some(old_name.to_value()) }) .build(), super::Signal::builder("create-string") .return_type::() .build(), super::Signal::builder("create-child-object") .return_type::() .build(), ] }) } fn set_property(&self, _id: usize, value: &Value, pspec: &crate::ParamSpec) { match pspec.name() { "name" => { let name = value .get() .expect("type conformity checked by 'Object::set_property'"); self.name.replace(name); self.obj() .emit_by_name::<()>("name-changed", &[&*self.name.borrow()]); } "construct-name" => { let name = value .get() .expect("type conformity checked by 'Object::set_property'"); self.construct_name.replace(name); } "child" => { // not stored, only used to test `set_property` with `Objects` } "answer" => { let answer = value .get() .expect("type conformity checked by 'Object::set_property'"); self.answer.replace(answer); } "array" => { let value = value .get::() .expect("type conformity checked by 'Object::set_property'"); let mut array = self.array.borrow_mut(); array.clear(); array.extend(value.iter().map(|v| v.get().unwrap())); } _ => unimplemented!(), } } fn property(&self, _id: usize, pspec: &crate::ParamSpec) -> Value { match pspec.name() { "name" => self.name.borrow().to_value(), "construct-name" => self.construct_name.borrow().to_value(), "constructed" => self.constructed.borrow().to_value(), "answer" => self.answer.borrow().to_value(), "array" => crate::ValueArray::new(self.array.borrow().iter()).to_value(), _ => unimplemented!(), } } fn constructed(&self) { self.parent_constructed(); debug_assert_eq!(self as *const _, self.obj().imp() as *const _); *self.constructed.borrow_mut() = true; } } #[derive(Clone, Copy)] #[repr(C)] pub struct DummyInterface { parent: gobject_ffi::GTypeInterface, } unsafe impl InterfaceStruct for DummyInterface { type Type = Dummy; } pub enum Dummy {} #[glib::object_interface] impl ObjectInterface for Dummy { const NAME: &'static str = "Dummy"; type Interface = DummyInterface; } } wrapper! { pub struct ChildObject(ObjectSubclass); } wrapper! { pub struct SimpleObject(ObjectSubclass); } wrapper! { pub struct Dummy(ObjectInterface); } unsafe impl IsImplementable for Dummy {} #[test] fn test_create() { let type_ = SimpleObject::static_type(); let obj = Object::with_type(type_); assert!(obj.type_().is_a(Dummy::static_type())); // Assert that the object representation is equivalent to the underlying C GObject pointer assert_eq!( mem::size_of::(), mem::size_of::() ); assert_eq!(obj.as_ptr() as ffi::gpointer, unsafe { *(&obj as *const _ as *const ffi::gpointer) }); assert!(obj.property::("constructed")); let weak = obj.downgrade(); drop(obj); assert!(weak.upgrade().is_none()); } #[test] fn test_properties() { let type_ = SimpleObject::static_type(); let obj = Object::with_type(type_); assert!(obj.type_().is_a(Dummy::static_type())); let properties = obj.list_properties(); assert_eq!(properties.len(), 6); assert_eq!(properties[0].name(), "name"); assert_eq!(properties[1].name(), "construct-name"); assert_eq!(properties[2].name(), "constructed"); assert_eq!(properties[3].name(), "child"); assert_eq!(properties[4].name(), "answer"); assert_eq!(properties[5].name(), "array"); } #[test] fn test_create_child_object() { let obj: ChildObject = Object::new(); assert_eq!(&obj, obj.imp().obj().as_ref()); } #[test] fn test_builder() { let obj = Object::builder::() .property("construct-name", "meh") .property("name", "initial") .build(); assert_eq!( obj.property::("construct-name"), String::from("meh") ); assert_eq!(obj.property::("name"), String::from("initial")); } #[test] fn test_set_property() { let obj = Object::builder::() .property("construct-name", "meh") .property("name", "initial") .build(); assert_eq!( obj.property::("construct-name"), String::from("meh") ); assert_eq!( obj.property::("construct-name"), String::from("meh") ); assert_eq!(obj.property::("name"), String::from("initial")); obj.set_property("name", "test"); assert_eq!(obj.property::("name"), String::from("test")); let child = Object::with_type(ChildObject::static_type()); obj.set_property("child", &child); } #[test] fn builder_property_if() { use crate::ValueArray; let array = ["val0", "val1"]; let obj = Object::builder::() .property_if("name", "some name", true) .property_if("answer", 21i32, 6 != 9) .property_if("array", ValueArray::new(["val0", "val1"]), array.len() == 2) .build(); assert_eq!(obj.property::("name").as_str(), "some name"); assert_eq!( obj.property::>("name").as_deref(), Some("some name") ); assert_eq!(obj.property::("answer"), 21); assert!(obj .property::("array") .iter() .map(|val| val.get::<&str>().unwrap()) .eq(array)); let obj = Object::builder::() .property_if("name", "some name", false) .property_if("answer", 21i32, 6 == 9) .property_if("array", ValueArray::new(array), array.len() == 4) .build(); assert!(obj.property::>("name").is_none()); assert_eq!(obj.property::("answer"), 42); assert!(obj .property::("array") .iter() .map(|val| val.get::<&str>().unwrap()) .eq(["default0", "default1"])); } #[test] fn builder_property_if_some() { use crate::ValueArray; let array = ["val0", "val1"]; let obj = Object::builder::() .property_if_some("name", Some("some name")) .property_if_some("answer", Some(21i32)) .property_if_some("array", Some(ValueArray::new(array))) .build(); assert_eq!(obj.property::("name").as_str(), "some name"); assert_eq!( obj.property::>("name").as_deref(), Some("some name") ); assert_eq!(obj.property::("answer"), 21); assert!(obj .property::("array") .iter() .map(|val| val.get::<&str>().unwrap()) .eq(array)); let obj = Object::builder::() .property_if_some("name", Option::<&str>::None) .property_if_some("answer", Option::::None) .property_if_some("array", Option::::None) .build(); assert!(obj.property::>("name").is_none()); assert_eq!(obj.property::("answer"), 42); assert!(obj .property::("array") .iter() .map(|val| val.get::<&str>().unwrap()) .eq(["default0", "default1"])); } #[test] fn builder_property_from_iter() { use crate::ValueArray; let array = ["val0", "val1"]; let obj = Object::builder::() .property_from_iter::("array", &array) .build(); assert!(obj .property::("array") .iter() .map(|val| val.get::<&str>().unwrap()) .eq(array)); let obj = Object::builder::() .property_from_iter::("array", Vec::<&str>::new()) .build(); assert!(obj.property::("array").is_empty()); } #[test] fn builder_property_if_not_empty() { use crate::ValueArray; let array = ["val0", "val1"]; let obj = Object::builder::() .property_if_not_empty::("array", &array) .build(); assert!(obj .property::("array") .iter() .map(|val| val.get::<&str>().unwrap()) .eq(array)); let empty_vec = Vec::::new(); let obj = Object::builder::() .property_if_not_empty::("array", &empty_vec) .build(); assert!(obj .property::("array") .iter() .map(|val| val.get::<&str>().unwrap()) .eq(["default0", "default1"])); } #[test] #[should_panic = "property 'construct-name' of type 'SimpleObject' is not writable"] fn test_set_property_non_writable() { let obj = Object::builder::() .property("construct-name", "meh") .property("name", "initial") .build(); obj.set_property("construct-name", "test"); } #[test] #[should_panic = "property 'test' of type 'SimpleObject' not found"] fn test_set_property_not_found() { let obj = Object::builder::() .property("construct-name", "meh") .property("name", "initial") .build(); obj.set_property("test", true); } #[test] #[should_panic = "property 'constructed' of type 'SimpleObject' is not writable"] fn test_set_property_not_writable() { let obj = Object::builder::() .property("construct-name", "meh") .property("name", "initial") .build(); obj.set_property("constructed", false); } #[test] #[should_panic = "property 'name' of type 'SimpleObject' can't be set from the given type (expected: 'gchararray', got: 'gboolean')"] fn test_set_property_wrong_type() { let obj = Object::builder::() .property("construct-name", "meh") .property("name", "initial") .build(); obj.set_property("name", false); } #[test] #[should_panic = "property 'child' of type 'SimpleObject' can't be set from the given type (expected: 'ChildObject', got: 'SimpleObject')"] fn test_set_property_wrong_type_2() { let obj = Object::builder::() .property("construct-name", "meh") .property("name", "initial") .build(); let other_obj = Object::with_type(SimpleObject::static_type()); obj.set_property("child", &other_obj); } #[test] #[should_panic = "Can't set construct property 'construct-name' for type 'SimpleObject' twice"] fn test_construct_property_set_twice() { let _obj = Object::builder::() .property("construct-name", "meh") .property("construct-name", "meh2") .build(); } #[test] fn test_signals() { use std::sync::{ atomic::{AtomicBool, Ordering}, Arc, }; let obj = Object::builder::() .property("name", "old-name") .build(); let name_changed_triggered = Arc::new(AtomicBool::new(false)); let name_changed_clone = name_changed_triggered.clone(); obj.connect("name-changed", false, move |args| { let _obj = args[0].get::().expect("Failed to get args[0]"); let name = args[1].get::<&str>().expect("Failed to get args[1]"); assert_eq!(name, "new-name"); name_changed_clone.store(true, Ordering::Relaxed); None }); assert_eq!(obj.property::("name"), String::from("old-name")); assert!(!name_changed_triggered.load(Ordering::Relaxed)); assert_eq!( obj.emit_by_name::("change-name", &[&"new-name"]), "old-name" ); assert!(name_changed_triggered.load(Ordering::Relaxed)); } #[test] fn test_signal_return_expected_type() { let obj = Object::with_type(SimpleObject::static_type()); obj.connect("create-string", false, move |_args| { Some("return value".to_value()) }); let signal_id = imp::SimpleObject::signals()[2].signal_id(); let value = obj.emit::(signal_id, &[]); assert_eq!(value, "return value"); } #[test] fn test_callback_validity() { use std::sync::{ atomic::{AtomicBool, Ordering}, Arc, }; let obj = Object::builder::() .property("name", "old-name") .build(); let name_changed_triggered = Arc::new(AtomicBool::new(false)); let name_changed_clone = name_changed_triggered.clone(); obj.connect_notify(Some("name"), move |_, _| { name_changed_clone.store(true, Ordering::Relaxed); }); obj.notify("name"); assert!(name_changed_triggered.load(Ordering::Relaxed)); } // Note: can't test type mismatch in signals since panics across FFI boundaries // are UB. See https://github.com/gtk-rs/glib/issues/518 #[test] fn test_signal_return_expected_object_type() { let obj = Object::with_type(SimpleObject::static_type()); obj.connect("create-child-object", false, move |_args| { Some(Object::with_type(ChildObject::static_type()).to_value()) }); let value: glib::Object = obj.emit_by_name("create-child-object", &[]); assert!(value.type_().is_a(ChildObject::static_type())); } } glib-0.20.9/src/subclass/object_impl_ref.rs000064400000000000000000000102671046102023000167360ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{cmp, fmt, hash}; use super::prelude::*; use crate::{ clone::{Downgrade, Upgrade}, prelude::*, WeakRef, }; // rustdoc-stripper-ignore-next /// Reference-counted wrapper around an [`ObjectSubclass`] reference. /// /// This can be used for passing into closures as strong or weak reference without manually going /// from the implementation type to the instance type and back. pub struct ObjectImplRef(T::Type); unsafe impl Send for ObjectImplRef {} unsafe impl Sync for ObjectImplRef {} impl ObjectImplRef { // rustdoc-stripper-ignore-next /// Create a new reference-counting wrapper around `imp`. #[inline] pub fn new(imp: &T) -> Self { Self(imp.obj().clone()) } // rustdoc-stripper-ignore-next /// Downgrade to a weak reference. /// /// This can be upgraded to a strong reference again via [`ObjectImplWeakRef::upgrade`]. #[inline] pub fn downgrade(&self) -> ObjectImplWeakRef { ObjectImplWeakRef(self.0.downgrade()) } } impl Clone for ObjectImplRef { #[inline] fn clone(&self) -> Self { Self(self.0.clone()) } } impl fmt::Debug for ObjectImplRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ::fmt(&self.0, f) } } impl std::ops::Deref for ObjectImplRef { type Target = T; #[inline] fn deref(&self) -> &Self::Target { T::from_obj(&self.0) } } impl Downgrade for ObjectImplRef { type Weak = ObjectImplWeakRef; #[inline] fn downgrade(&self) -> Self::Weak { self.downgrade() } } impl PartialOrd for ObjectImplRef { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl PartialOrd for ObjectImplRef where T::Type: PartialOrd, { #[inline] fn partial_cmp(&self, other: &OT) -> Option { self.0.partial_cmp(other) } } impl Ord for ObjectImplRef { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { self.0.cmp(&other.0) } } impl PartialEq for ObjectImplRef { #[inline] fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } impl PartialEq for ObjectImplRef where T::Type: PartialEq, { #[inline] fn eq(&self, other: &OT) -> bool { self.0 == *other } } impl Eq for ObjectImplRef {} impl hash::Hash for ObjectImplRef { #[inline] fn hash(&self, state: &mut H) where H: hash::Hasher, { self.0.hash(state) } } // rustdoc-stripper-ignore-next /// Weak reference to an [`ObjectSubclass`] reference. pub struct ObjectImplWeakRef(WeakRef); unsafe impl Send for ObjectImplWeakRef {} unsafe impl Sync for ObjectImplWeakRef {} impl ObjectImplWeakRef { // rustdoc-stripper-ignore-next /// Upgrade to a strong reference, if possible. /// /// This will return `None` if the underlying object was freed in the meantime. #[inline] pub fn upgrade(&self) -> Option> { let obj = self.0.upgrade()?; Some(ObjectImplRef(obj)) } } impl Clone for ObjectImplWeakRef { #[inline] fn clone(&self) -> Self { Self(self.0.clone()) } } impl fmt::Debug for ObjectImplWeakRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { as fmt::Debug>::fmt(&self.0, f) } } impl Upgrade for ObjectImplWeakRef { type Strong = ObjectImplRef; #[inline] fn upgrade(&self) -> Option { self.upgrade() } } glib-0.20.9/src/subclass/shared.rs000064400000000000000000000251501046102023000150560ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! Module for registering shared types for Rust types. use crate::{ffi, gobject_ffi, prelude::*, translate::*}; pub unsafe trait RefCounted: Clone + Sized + 'static { // rustdoc-stripper-ignore-next /// The inner type type InnerType; // rustdoc-stripper-ignore-next /// The function used to increment the inner type refcount unsafe fn ref_(this: *const Self::InnerType) -> *const Self::InnerType; // rustdoc-stripper-ignore-next /// Provides access to a raw pointer to InnerType fn as_ptr(&self) -> *const Self::InnerType; // rustdoc-stripper-ignore-next /// Converts the RefCounted object to a raw pointer to InnerType unsafe fn into_raw(self) -> *const Self::InnerType; // rustdoc-stripper-ignore-next /// Converts a raw pointer to InnerType to a RefCounted object unsafe fn from_raw(this: *const Self::InnerType) -> Self; } unsafe impl RefCounted for std::sync::Arc where T: 'static, { type InnerType = T; #[inline] unsafe fn ref_(this: *const Self::InnerType) -> *const Self::InnerType { std::sync::Arc::increment_strong_count(this); this } #[inline] fn as_ptr(&self) -> *const Self::InnerType { std::sync::Arc::as_ptr(self) } #[inline] unsafe fn into_raw(self) -> *const Self::InnerType { std::sync::Arc::into_raw(self) } #[inline] unsafe fn from_raw(this: *const Self::InnerType) -> Self { std::sync::Arc::from_raw(this) } } unsafe impl RefCounted for std::rc::Rc where T: 'static, { type InnerType = T; #[inline] unsafe fn ref_(this: *const Self::InnerType) -> *const Self::InnerType { use std::mem::ManuallyDrop; let this_rc = ManuallyDrop::new(std::rc::Rc::from_raw(this)); std::rc::Rc::into_raw(ManuallyDrop::take(&mut this_rc.clone())) } #[inline] fn as_ptr(&self) -> *const Self::InnerType { std::rc::Rc::as_ptr(self) } #[inline] unsafe fn into_raw(self) -> *const Self::InnerType { std::rc::Rc::into_raw(self) } #[inline] unsafe fn from_raw(this: *const Self::InnerType) -> Self { std::rc::Rc::from_raw(this) } } // rustdoc-stripper-ignore-next /// Trait for defining shared types. /// /// Links together the type name with the type itself. /// /// See [`register_shared_type`] for registering an implementation of this trait /// with the type system. /// /// [`register_shared_type`]: fn.register_shared_type.html pub trait SharedType: StaticType + Clone + Sized + 'static { // rustdoc-stripper-ignore-next /// Shared type name. /// /// This must be unique in the whole process. const NAME: &'static str; // rustdoc-stripper-ignore-next /// Allow name conflicts for this boxed type. /// /// By default, trying to register a type with a name that was registered before will panic. If /// this is set to `true` then a new name will be selected by appending a counter. /// /// This is useful for defining new types in Rust library crates that might be linked multiple /// times in the same process. /// /// A consequence of setting this to `true` is that it's not guaranteed that /// `glib::Type::from_name(Self::NAME).unwrap() == Self::static_type()`. /// /// Optional. const ALLOW_NAME_CONFLICT: bool = false; // rustdoc-stripper-ignore-next /// The inner refcounted type type RefCountedType: RefCounted; // rustdoc-stripper-ignore-next /// Converts the SharedType into its inner RefCountedType fn into_refcounted(self) -> Self::RefCountedType; // rustdoc-stripper-ignore-next /// Constructs a SharedType from a RefCountedType fn from_refcounted(this: Self::RefCountedType) -> Self; } // rustdoc-stripper-ignore-next /// Register a boxed `glib::Type` ID for `T`. /// /// This must be called only once and will panic on a second call. /// /// See [`Shared!`] for defining a function that ensures that /// this is only called once and returns the type id. /// /// [`Shared!`]: ../../derive.Shared.html pub fn register_shared_type() -> crate::Type { unsafe { use std::ffi::CString; unsafe extern "C" fn shared_ref(v: ffi::gpointer) -> ffi::gpointer { T::RefCountedType::ref_(v as *const ::InnerType) as ffi::gpointer } unsafe extern "C" fn shared_unref(v: ffi::gpointer) { let _ = T::RefCountedType::from_raw( v as *const ::InnerType, ); } let type_name = if T::ALLOW_NAME_CONFLICT { let mut i = 0; loop { let type_name = CString::new(if i == 0 { T::NAME.to_string() } else { format!("{}-{}", T::NAME, i) }) .unwrap(); if gobject_ffi::g_type_from_name(type_name.as_ptr()) == gobject_ffi::G_TYPE_INVALID { break type_name; } i += 1; } } else { let type_name = CString::new(T::NAME).unwrap(); assert_eq!( gobject_ffi::g_type_from_name(type_name.as_ptr()), gobject_ffi::G_TYPE_INVALID, "Type {} has already been registered", type_name.to_str().unwrap() ); type_name }; let type_ = crate::Type::from_glib(gobject_ffi::g_boxed_type_register_static( type_name.as_ptr(), Some(shared_ref::), Some(shared_unref::), )); assert!(type_.is_valid()); type_ } } #[cfg(test)] mod test { use super::*; // We rename the current crate as glib, since the macros in glib-macros // generate the glib namespace through the crate_ident_new utility, // and that returns `glib` (and not `crate`) when called inside the glib crate use crate as glib; #[derive(Clone, Debug, PartialEq, Eq)] struct MySharedInner { foo: String, } #[derive(Clone, Debug, PartialEq, Eq, glib::SharedBoxed)] #[shared_boxed_type(name = "MySharedArc")] struct MySharedArc(std::sync::Arc); #[derive(Clone, Debug, PartialEq, Eq, glib::SharedBoxed)] #[shared_boxed_type(name = "MySharedRc")] struct MySharedRc(std::rc::Rc); #[test] fn test_register() { assert_ne!(crate::Type::INVALID, MySharedArc::static_type()); assert_ne!(crate::Type::INVALID, MySharedRc::static_type()); } #[test] fn test_value_arc() { assert_ne!(crate::Type::INVALID, MySharedArc::static_type()); let b = MySharedArc::from_refcounted(std::sync::Arc::new(MySharedInner { foo: String::from("abc"), })); let v = b.to_value(); let b2 = v.get::().unwrap(); assert!(std::sync::Arc::ptr_eq(&b.0, &b2.0)); } #[test] fn test_value_rc() { assert_ne!(crate::Type::INVALID, MySharedRc::static_type()); let b = MySharedRc::from_refcounted(std::rc::Rc::new(MySharedInner { foo: String::from("abc"), })); let v = b.to_value(); let b2 = v.get::().unwrap(); assert!(std::rc::Rc::ptr_eq(&b.0, &b2.0)); } #[test] fn same_ffi_pointer_arc() { assert_ne!(crate::Type::INVALID, MySharedArc::static_type()); let b = MySharedArc::from_refcounted(std::sync::Arc::new(MySharedInner { foo: String::from("abc"), })); let inner_raw_ptr = std::sync::Arc::into_raw(b.clone().0); assert_eq!(std::sync::Arc::strong_count(&b.0), 2); let inner_raw_ptr_clone = unsafe { ::RefCountedType::ref_(inner_raw_ptr) }; assert_eq!(std::sync::Arc::strong_count(&b.0), 3); assert!(std::ptr::eq(inner_raw_ptr, inner_raw_ptr_clone)); let _ = unsafe { ::RefCountedType::from_raw(inner_raw_ptr) }; let _ = unsafe { ::RefCountedType::from_raw(inner_raw_ptr_clone) }; assert_eq!(std::sync::Arc::strong_count(&b.0), 1); } #[test] fn same_ffi_pointer_rc() { assert_ne!(crate::Type::INVALID, MySharedRc::static_type()); let b = MySharedRc::from_refcounted(std::rc::Rc::new(MySharedInner { foo: String::from("abc"), })); let inner_raw_ptr = std::rc::Rc::into_raw(b.clone().0); assert_eq!(std::rc::Rc::strong_count(&b.0), 2); let inner_raw_ptr_clone = unsafe { ::RefCountedType::ref_(inner_raw_ptr) }; assert_eq!(std::rc::Rc::strong_count(&b.0), 3); assert!(std::ptr::eq(inner_raw_ptr, inner_raw_ptr_clone)); let _ = unsafe { ::RefCountedType::from_raw(inner_raw_ptr) }; let _ = unsafe { ::RefCountedType::from_raw(inner_raw_ptr_clone) }; assert_eq!(std::rc::Rc::strong_count(&b.0), 1); } #[test] fn from_glib_borrow_arc() { assert_ne!(crate::Type::INVALID, MySharedRc::static_type()); let b = MySharedArc::from_refcounted(std::sync::Arc::new(MySharedInner { foo: String::from("abc"), })); let inner_raw_ptr = std::sync::Arc::into_raw(b.clone().0); assert_eq!(std::sync::Arc::strong_count(&b.0), 2); unsafe { let _ = MySharedArc::from_glib_borrow(inner_raw_ptr); assert_eq!(std::sync::Arc::strong_count(&b.0), 2); } assert_eq!(std::sync::Arc::strong_count(&b.0), 2); unsafe { let _ = std::sync::Arc::from_raw(inner_raw_ptr); } assert_eq!(std::sync::Arc::strong_count(&b.0), 1); } #[test] fn from_glib_borrow_rc() { assert_ne!(crate::Type::INVALID, MySharedRc::static_type()); let b = MySharedRc::from_refcounted(std::rc::Rc::new(MySharedInner { foo: String::from("abc"), })); let inner_raw_ptr = std::rc::Rc::into_raw(b.clone().0); assert_eq!(std::rc::Rc::strong_count(&b.0), 2); unsafe { let _ = MySharedRc::from_glib_borrow(inner_raw_ptr); assert_eq!(std::rc::Rc::strong_count(&b.0), 2); } assert_eq!(std::rc::Rc::strong_count(&b.0), 2); unsafe { let _ = std::rc::Rc::from_raw(inner_raw_ptr); } assert_eq!(std::rc::Rc::strong_count(&b.0), 1); } } glib-0.20.9/src/subclass/signal.rs000064400000000000000000000512001046102023000150600ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{fmt, num::NonZeroU32, ptr, sync::Mutex}; use crate::{ ffi, gobject_ffi, prelude::*, translate::*, utils::is_canonical_pspec_name, Closure, SignalFlags, Type, Value, }; // rustdoc-stripper-ignore-next /// Builder for signals. #[allow(clippy::type_complexity)] #[must_use = "The builder must be built to be used"] pub struct SignalBuilder { name: String, flags: SignalFlags, param_types: Vec, return_type: SignalType, class_handler: Option< Box Option + Send + Sync + 'static>, >, accumulator: Option< Box bool + Send + Sync + 'static>, >, } // rustdoc-stripper-ignore-next /// Signal metadata. pub struct Signal { name: String, flags: SignalFlags, param_types: Vec, return_type: SignalType, registration: Mutex, } // rustdoc-stripper-ignore-next /// Token passed to signal class handlers. pub struct SignalClassHandlerToken( // rustdoc-stripper-ignore-next /// Instance for which the signal is emitted. pub(super) *mut gobject_ffi::GTypeInstance, // rustdoc-stripper-ignore-next /// Return type. pub(super) Type, // rustdoc-stripper-ignore-next /// Arguments value array. pub(super) *const Value, ); impl fmt::Debug for SignalClassHandlerToken { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.debug_struct("SignalClassHandlerToken") .field("type", &unsafe { crate::Object::from_glib_borrow(self.0 as *mut gobject_ffi::GObject) }) .finish() } } // rustdoc-stripper-ignore-next /// Signal invocation hint passed to signal accumulators. #[repr(transparent)] pub struct SignalInvocationHint(gobject_ffi::GSignalInvocationHint); impl SignalInvocationHint { #[inline] pub fn detail(&self) -> Option { unsafe { try_from_glib(self.0.detail).ok() } } #[inline] pub fn run_type(&self) -> SignalFlags { unsafe { from_glib(self.0.run_type) } } } impl fmt::Debug for SignalInvocationHint { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.debug_struct("SignalInvocationHint") .field("detail", &self.detail()) .field("run_type", &self.run_type()) .finish() } } // rustdoc-stripper-ignore-next /// In-depth information of a specific signal pub struct SignalQuery(gobject_ffi::GSignalQuery); unsafe impl Send for SignalQuery {} unsafe impl Sync for SignalQuery {} impl SignalQuery { // rustdoc-stripper-ignore-next /// The name of the signal. #[inline] pub fn signal_name<'a>(&self) -> &'a str { unsafe { let ptr = self.0.signal_name; std::ffi::CStr::from_ptr(ptr).to_str().unwrap() } } // rustdoc-stripper-ignore-next /// The ID of the signal. #[inline] pub fn signal_id(&self) -> SignalId { unsafe { SignalId::from_glib(self.0.signal_id) } } // rustdoc-stripper-ignore-next /// The instance type this signal can be emitted for. #[inline] pub fn type_(&self) -> Type { unsafe { from_glib(self.0.itype) } } // rustdoc-stripper-ignore-next /// The signal flags. #[inline] pub fn flags(&self) -> SignalFlags { unsafe { from_glib(self.0.signal_flags) } } // rustdoc-stripper-ignore-next /// The return type for the user callback. #[inline] pub fn return_type(&self) -> SignalType { unsafe { from_glib(self.0.return_type) } } // rustdoc-stripper-ignore-next /// The number of parameters the user callback takes. #[inline] pub fn n_params(&self) -> u32 { self.0.n_params } // rustdoc-stripper-ignore-next /// The parameters for the user callback. #[inline] pub fn param_types(&self) -> &[SignalType] { if self.n_params() == 0 { return &[]; } unsafe { std::slice::from_raw_parts( self.0.param_types as *const SignalType, self.0.n_params as usize, ) } } } impl fmt::Debug for SignalQuery { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.debug_struct("SignalQuery") .field("signal_name", &self.signal_name()) .field("type", &self.type_()) .field("flags", &self.flags()) .field("return_type", &self.return_type()) .field("param_types", &self.param_types()) .finish() } } // rustdoc-stripper-ignore-next /// Signal ID. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct SignalId(NonZeroU32); impl SignalId { // rustdoc-stripper-ignore-next /// Create a new Signal Identifier. /// /// # Safety /// /// The caller has to ensure it's a valid signal identifier. #[inline] pub unsafe fn new(id: NonZeroU32) -> Self { Self(id) } #[doc(alias = "g_signal_parse_name")] #[inline] pub fn parse_name( name: &str, type_: Type, force_detail: bool, ) -> Option<(Self, Option)> { let mut signal_id = std::mem::MaybeUninit::uninit(); let mut detail_quark = std::mem::MaybeUninit::uninit(); unsafe { let found: bool = name.run_with_gstr(|name| { from_glib(gobject_ffi::g_signal_parse_name( name.as_ptr(), type_.into_glib(), signal_id.as_mut_ptr(), detail_quark.as_mut_ptr(), force_detail.into_glib(), )) }); if found { Some(( from_glib(signal_id.assume_init()), crate::Quark::try_from_glib(detail_quark.assume_init()).ok(), )) } else { None } } } // rustdoc-stripper-ignore-next /// Find a SignalId by its `name`, and the `type` it connects to. #[doc(alias = "g_signal_lookup")] #[inline] pub fn lookup(name: &str, type_: Type) -> Option { unsafe { let signal_id = name.run_with_gstr(|name| { gobject_ffi::g_signal_lookup(name.as_ptr(), type_.into_glib()) }); if signal_id == 0 { None } else { Some(Self::new(NonZeroU32::new_unchecked(signal_id))) } } } // rustdoc-stripper-ignore-next /// Queries more in-depth information about the current signal. #[doc(alias = "g_signal_query")] #[inline] pub fn query(&self) -> SignalQuery { unsafe { let mut query_ptr = std::mem::MaybeUninit::uninit(); gobject_ffi::g_signal_query(self.into_glib(), query_ptr.as_mut_ptr()); let query = query_ptr.assume_init(); debug_assert_ne!(query.signal_id, 0); SignalQuery(query) } } // rustdoc-stripper-ignore-next /// Find the signal name. #[doc(alias = "g_signal_name")] #[inline] pub fn name<'a>(&self) -> &'a str { unsafe { let ptr = gobject_ffi::g_signal_name(self.into_glib()); std::ffi::CStr::from_ptr(ptr).to_str().unwrap() } } } #[doc(hidden)] impl FromGlib for SignalId { #[inline] unsafe fn from_glib(signal_id: u32) -> Self { debug_assert_ne!(signal_id, 0); Self::new(NonZeroU32::new_unchecked(signal_id)) } } #[doc(hidden)] impl IntoGlib for SignalId { type GlibType = u32; #[inline] fn into_glib(self) -> u32 { self.0.into() } } #[derive(Copy, Clone, Hash)] #[repr(transparent)] pub struct SignalType(ffi::GType); impl SignalType { #[inline] pub fn with_static_scope(type_: Type) -> Self { Self(type_.into_glib() | gobject_ffi::G_TYPE_FLAG_RESERVED_ID_BIT) } #[inline] pub fn static_scope(&self) -> bool { (self.0 & gobject_ffi::G_TYPE_FLAG_RESERVED_ID_BIT) != 0 } #[inline] pub fn type_(&self) -> Type { (*self).into() } } impl From for SignalType { #[inline] fn from(type_: Type) -> Self { Self(type_.into_glib()) } } impl From for Type { #[inline] fn from(type_: SignalType) -> Self { // Remove the extra-bit used for G_SIGNAL_TYPE_STATIC_SCOPE let type_ = type_.0 & (!gobject_ffi::G_TYPE_FLAG_RESERVED_ID_BIT); unsafe { from_glib(type_) } } } impl PartialEq for SignalType { #[inline] fn eq(&self, other: &Type) -> bool { let type_: Type = (*self).into(); type_.eq(other) } } impl std::fmt::Debug for SignalType { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let type_: Type = (*self).into(); f.debug_struct("SignalType") .field("name", &type_.name()) .field("static_scope", &self.static_scope()) .finish() } } #[doc(hidden)] impl FromGlib for SignalType { #[inline] unsafe fn from_glib(type_: ffi::GType) -> Self { Self(type_) } } #[doc(hidden)] impl IntoGlib for SignalType { type GlibType = ffi::GType; #[inline] fn into_glib(self) -> ffi::GType { self.0 } } #[allow(clippy::type_complexity)] enum SignalRegistration { Unregistered { class_handler: Option< Box< dyn Fn(&SignalClassHandlerToken, &[Value]) -> Option + Send + Sync + 'static, >, >, accumulator: Option< Box bool + Send + Sync + 'static>, >, }, Registered { type_: Type, signal_id: SignalId, }, } impl SignalBuilder { // rustdoc-stripper-ignore-next /// The signal's parameters. pub fn param_types( mut self, param_types: impl IntoIterator>, ) -> Self { self.param_types = param_types .into_iter() .map(|t| t.into()) .collect::>(); self } // rustdoc-stripper-ignore-next /// The signal's returned value type. pub fn return_type(mut self) -> Self { self.return_type = T::static_type().into(); self } // rustdoc-stripper-ignore-next /// The signal's returned value type. pub fn return_type_from(mut self, type_: impl Into) -> Self { self.return_type = type_.into(); self } // rustdoc-stripper-ignore-next /// Run the signal class handler in the first emission stage. pub fn run_first(mut self) -> Self { self.flags |= SignalFlags::RUN_FIRST; self } // rustdoc-stripper-ignore-next /// Run the signal class handler in the third emission stage. pub fn run_last(mut self) -> Self { self.flags |= SignalFlags::RUN_LAST; self } // rustdoc-stripper-ignore-next /// Run the signal class handler in the last emission stage. pub fn run_cleanup(mut self) -> Self { self.flags |= SignalFlags::RUN_CLEANUP; self } // rustdoc-stripper-ignore-next /// Signals being emitted for an object while currently being in emission for this very object /// will not be emitted recursively, but instead cause the first emission to be restarted. pub fn no_recurse(mut self) -> Self { self.flags |= SignalFlags::NO_RECURSE; self } // rustdoc-stripper-ignore-next /// This signal supports "::detail" appendices to the signal name upon handler connections and /// emissions. pub fn detailed(mut self) -> Self { self.flags |= SignalFlags::DETAILED; self } // rustdoc-stripper-ignore-next /// Action signals are signals that may freely be emitted on alive objects from user code. pub fn action(mut self) -> Self { self.flags |= SignalFlags::ACTION; self } // rustdoc-stripper-ignore-next /// No emissions hooks are supported for this signal. pub fn no_hooks(mut self) -> Self { self.flags |= SignalFlags::NO_HOOKS; self } // rustdoc-stripper-ignore-next /// Varargs signal emission will always collect the arguments, even if there are no signal /// handlers connected. pub fn must_collect(mut self) -> Self { self.flags |= SignalFlags::MUST_COLLECT; self } // rustdoc-stripper-ignore-next /// The signal is deprecated and will be removed in a future version. pub fn deprecated(mut self) -> Self { self.flags |= SignalFlags::DEPRECATED; self } // rustdoc-stripper-ignore-next /// Explicitly set all flags. /// /// This overrides previously set flags on this builder. pub fn flags(mut self, flags: SignalFlags) -> Self { self.flags = flags; self } // rustdoc-stripper-ignore-next /// Class handler for this signal. pub fn class_handler< F: Fn(&SignalClassHandlerToken, &[Value]) -> Option + Send + Sync + 'static, >( mut self, func: F, ) -> Self { self.class_handler = Some(Box::new(func)); self } // rustdoc-stripper-ignore-next /// Accumulator for the return values of the signal. /// /// This is called if multiple signal handlers are connected to the signal for accumulating the /// return values into a single value. pub fn accumulator< F: Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static, >( mut self, func: F, ) -> Self { self.accumulator = Some(Box::new(func)); self } // rustdoc-stripper-ignore-next /// Build the signal. /// /// This does not register the signal yet, which only happens as part of object type /// registration. #[must_use = "Signal returned from the builder must be used for it to be registered"] pub fn build(self) -> Signal { let flags = if self.flags & (SignalFlags::RUN_FIRST | SignalFlags::RUN_LAST | SignalFlags::RUN_CLEANUP) == SignalFlags::empty() { self.flags | SignalFlags::RUN_LAST } else { self.flags }; Signal { name: self.name, flags, param_types: self.param_types.to_vec(), return_type: self.return_type, registration: Mutex::new(SignalRegistration::Unregistered { class_handler: self.class_handler, accumulator: self.accumulator, }), } } } impl Signal { // rustdoc-stripper-ignore-next /// Create a new builder for a signal. pub fn builder(name: &str) -> SignalBuilder { assert!( is_canonical_pspec_name(name), "{name} is not a valid canonical signal name", ); SignalBuilder { name: name.to_owned(), param_types: Vec::default(), return_type: <()>::static_type().into(), flags: SignalFlags::empty(), class_handler: None, accumulator: None, } } // rustdoc-stripper-ignore-next /// Name of the signal. #[inline] pub fn name(&self) -> &str { &self.name } // rustdoc-stripper-ignore-next /// Flags of the signal. #[inline] pub fn flags(&self) -> SignalFlags { self.flags } // rustdoc-stripper-ignore-next /// Parameter types of the signal. #[inline] pub fn param_types(&self) -> &[SignalType] { &self.param_types } // rustdoc-stripper-ignore-next /// Return type of the signal. #[inline] pub fn return_type(&self) -> SignalType { self.return_type } // rustdoc-stripper-ignore-next /// Signal ID. /// /// This will panic if called before the signal was registered. #[inline] pub fn signal_id(&self) -> SignalId { match &*self.registration.lock().unwrap() { SignalRegistration::Unregistered { .. } => panic!("Signal not registered yet"), SignalRegistration::Registered { signal_id, .. } => *signal_id, } } // rustdoc-stripper-ignore-next /// Type this signal was registered for. /// /// This will panic if called before the signal was registered. #[inline] pub fn type_(&self) -> Type { match &*self.registration.lock().unwrap() { SignalRegistration::Unregistered { .. } => panic!("Signal not registered yet"), SignalRegistration::Registered { type_, .. } => *type_, } } pub(super) fn register(&self, type_: Type) { let mut registration = self.registration.lock().unwrap(); let (class_handler, accumulator) = match &mut *registration { SignalRegistration::Unregistered { class_handler, accumulator, } => (class_handler.take(), accumulator.take()), SignalRegistration::Registered { .. } => unreachable!(), }; let return_type = self.return_type; let class_handler = class_handler.map(|class_handler| { Closure::new(move |values| unsafe { let instance = gobject_ffi::g_value_get_object(values[0].to_glib_none().0); let res = class_handler(&SignalClassHandlerToken(instance as *mut _, return_type.into(), values.as_ptr()), values); if return_type == Type::UNIT { if let Some(ref v) = res { panic!("Signal has no return value but class handler returned a value of type {}", v.type_()); } } else { match res { None => { panic!("Signal has a return value but class handler returned none"); } Some(ref v) => { assert!(v.type_().is_a(return_type.into()), "Signal has a return type of {} but class handler returned {}", Type::from(return_type), v.type_()); } } } res }) }); unsafe extern "C" fn accumulator_trampoline( ihint: *mut gobject_ffi::GSignalInvocationHint, return_accu: *mut gobject_ffi::GValue, handler_return: *const gobject_ffi::GValue, data: ffi::gpointer, ) -> ffi::gboolean { let accumulator = &*(data as *const ( SignalType, Box< dyn Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static, >, )); let return_accu = &mut *(return_accu as *mut Value); let handler_return = &*(handler_return as *const Value); let return_type = accumulator.0; assert!( handler_return.type_().is_a(return_type.into()), "Signal has a return type of {} but handler returned {}", Type::from(return_type), handler_return.type_() ); let res = (accumulator.1)(&SignalInvocationHint(*ihint), return_accu, handler_return) .into_glib(); assert!( return_accu.type_().is_a(return_type.into()), "Signal has a return type of {} but accumulator returned {}", Type::from(return_type), return_accu.type_() ); res } let (accumulator, accumulator_trampoline) = if let (Some(accumulator), true) = (accumulator, return_type != Type::UNIT) { ( Box::into_raw(Box::new((return_type, accumulator))), Some:: _>(accumulator_trampoline), ) } else { (ptr::null_mut(), None) }; unsafe { let signal_id = gobject_ffi::g_signal_newv( self.name.to_glib_none().0, type_.into_glib(), self.flags.into_glib(), class_handler.to_glib_none().0, accumulator_trampoline, accumulator as ffi::gpointer, None, return_type.into_glib(), self.param_types.len() as u32, self.param_types.as_ptr() as *mut _, ); *registration = SignalRegistration::Registered { type_, signal_id: SignalId::from_glib(signal_id), }; } } } glib-0.20.9/src/subclass/type_module.rs000064400000000000000000000124771046102023000161460ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::{ffi, gobject_ffi, prelude::*, subclass::prelude::*, translate::*, TypeModule}; pub trait TypeModuleImpl: ObjectImpl + TypeModuleImplExt { // rustdoc-stripper-ignore-next /// Loads the module, registers one or more object subclasses using /// [`register_dynamic_type`] and registers one or more object interfaces /// using [`register_dynamic_interface`] (see [`TypeModule`]). /// /// [`register_dynamic_type`]: ../types/fn.register_dynamic_type.html /// [`register_dynamic_interface`]: ../interface/fn.register_dynamic_interface.html /// [`TypeModule`]: ../../gobject/auto/type_module/struct.TypeModule.html fn load(&self) -> bool; // rustdoc-stripper-ignore-next /// Unloads the module (see [`TypeModuleExt::unuse`]). /// /// [`TypeModuleExt::unuse`]: ../../gobject/auto/type_module/trait.TypeModuleExt.html#method.unuse // rustdoc-stripper-ignore-next-stop fn unload(&self); } pub trait TypeModuleImplExt: ObjectSubclass { fn parent_load(&self) -> bool; fn parent_unload(&self); } impl TypeModuleImplExt for T { fn parent_load(&self) -> bool { unsafe { let data = T::type_data(); let parent_class = data.as_ref().parent_class() as *const gobject_ffi::GTypeModuleClass; let f = (*parent_class) .load .expect("No parent class implementation for \"load\""); from_glib(f(self .obj() .unsafe_cast_ref::() .to_glib_none() .0)) } } fn parent_unload(&self) { unsafe { let data = T::type_data(); let parent_class = data.as_ref().parent_class() as *const gobject_ffi::GTypeModuleClass; let f = (*parent_class) .unload .expect("No parent class implementation for \"unload\""); f(self.obj().unsafe_cast_ref::().to_glib_none().0); } } } unsafe impl IsSubclassable for TypeModule { fn class_init(class: &mut crate::Class) { Self::parent_class_init::(class); let klass = class.as_mut(); klass.load = Some(load::); klass.unload = Some(unload::); } } unsafe extern "C" fn load( type_module: *mut gobject_ffi::GTypeModule, ) -> ffi::gboolean { let instance = &*(type_module as *mut T::Instance); let imp = instance.imp(); let res = imp.load(); // GLib type system expects a module to never be disposed if types has been // successfully loaded. // The following code prevents the Rust wrapper (`glib::TypeModule` subclass) // to dispose the module when dropped by ensuring the reference count is > 1. // Nothing is done if loading types has failed, allowing application to drop // and dispose the invalid module. if res && (*(type_module as *const gobject_ffi::GObject)).ref_count == 1 { unsafe { gobject_ffi::g_object_ref(type_module as _); } } res.into_glib() } unsafe extern "C" fn unload(type_module: *mut gobject_ffi::GTypeModule) { let instance = &*(type_module as *mut T::Instance); let imp = instance.imp(); imp.unload(); } #[cfg(test)] mod tests { use crate as glib; use super::*; mod imp { use super::*; #[derive(Default)] pub struct SimpleModule; #[crate::object_subclass] impl ObjectSubclass for SimpleModule { const NAME: &'static str = "SimpleModule"; type Type = super::SimpleModule; type ParentType = TypeModule; type Interfaces = (crate::TypePlugin,); } impl ObjectImpl for SimpleModule {} impl TypePluginImpl for SimpleModule {} impl TypeModuleImpl for SimpleModule { fn load(&self) -> bool { // register types on implementation load SimpleModuleType::on_implementation_load(self.obj().upcast_ref::()) } fn unload(&self) { // unregister types on implementation unload SimpleModuleType::on_implementation_unload(self.obj().upcast_ref::()); } } #[derive(Default)] pub struct SimpleModuleType; #[crate::object_subclass] #[object_subclass_dynamic] impl ObjectSubclass for SimpleModuleType { const NAME: &'static str = "SimpleModuleType"; type Type = super::SimpleModuleType; } impl ObjectImpl for SimpleModuleType {} } crate::wrapper! { pub struct SimpleModule(ObjectSubclass) @extends TypeModule, @implements crate::TypePlugin; } crate::wrapper! { pub struct SimpleModuleType(ObjectSubclass); } #[test] fn test_module() { assert!(!imp::SimpleModuleType::type_().is_valid()); let simple_module = glib::Object::new::(); // simulates the GLib type system to load the module. assert!(TypeModuleExt::use_(&simple_module)); assert!(imp::SimpleModuleType::type_().is_valid()); TypeModuleExt::unuse(&simple_module); } } glib-0.20.9/src/subclass/type_plugin.rs000064400000000000000000000230411046102023000161440ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::enums::{EnumValues, FlagsValues}; use crate::{ ffi, gobject_ffi, prelude::*, subclass::prelude::*, translate::*, Interface, InterfaceInfo, Type, TypeFlags, TypeInfo, TypePlugin, TypeValueTable, }; pub trait TypePluginImpl: ObjectImpl + TypePluginImplExt { fn use_plugin(&self) { self.parent_use_plugin(); } fn unuse_plugin(&self) { self.parent_unuse_plugin(); } fn complete_type_info(&self, type_: Type) -> (TypeInfo, TypeValueTable) { self.parent_complete_type_info(type_) } fn complete_interface_info(&self, instance_type: Type, interface_type: Type) -> InterfaceInfo { self.parent_complete_interface_info(instance_type, interface_type) } } pub trait TypePluginImplExt: ObjectSubclass { fn parent_use_plugin(&self); fn parent_unuse_plugin(&self); fn parent_complete_type_info(&self, type_: Type) -> (TypeInfo, TypeValueTable); fn parent_complete_interface_info( &self, instance_type: Type, interface_type: Type, ) -> InterfaceInfo; } impl TypePluginImplExt for T { fn parent_use_plugin(&self) { unsafe { let type_data = Self::type_data(); let parent_iface = type_data.as_ref().parent_interface::() as *const gobject_ffi::GTypePluginClass; let f = (*parent_iface) .use_plugin .expect("no parent \"use_plugin\" implementation"); f(self.obj().unsafe_cast_ref::().to_glib_none().0) } } fn parent_unuse_plugin(&self) { unsafe { let type_data = Self::type_data(); let parent_iface = type_data.as_ref().parent_interface::() as *const gobject_ffi::GTypePluginClass; let f = (*parent_iface) .unuse_plugin .expect("no parent \"unuse_plugin\" implementation"); f(self.obj().unsafe_cast_ref::().to_glib_none().0) } } fn parent_complete_type_info(&self, type_: Type) -> (TypeInfo, TypeValueTable) { unsafe { let type_data = Self::type_data(); let parent_iface = type_data.as_ref().parent_interface::() as *const gobject_ffi::GTypePluginClass; let f = (*parent_iface) .complete_type_info .expect("no parent \"complete_type_info\" implementation"); let info = TypeInfo::default(); let value_table = TypeValueTable::default(); f( self.obj().unsafe_cast_ref::().to_glib_none().0, type_.into_glib(), info.as_ptr(), value_table.as_ptr(), ); (info, value_table) } } fn parent_complete_interface_info( &self, instance_type: Type, interface_type: Type, ) -> InterfaceInfo { let info = InterfaceInfo::default(); unsafe { let type_data = Self::type_data(); let parent_iface = type_data.as_ref().parent_interface::() as *const gobject_ffi::GTypePluginClass; let f = (*parent_iface) .complete_interface_info .expect("no parent \"complete_interface_info\" implementation"); f( self.obj().unsafe_cast_ref::().to_glib_none().0, instance_type.into_glib(), interface_type.into_glib(), info.as_ptr(), ) } info } } unsafe impl IsImplementable for TypePlugin { fn interface_init(iface: &mut Interface) { let iface = iface.as_mut(); iface.use_plugin = Some(use_plugin::); iface.unuse_plugin = Some(unuse_plugin::); iface.complete_type_info = Some(complete_type_info::); iface.complete_interface_info = Some(complete_interface_info::); } } unsafe extern "C" fn use_plugin(type_plugin: *mut gobject_ffi::GTypePlugin) { let instance = &*(type_plugin as *mut T::Instance); let imp = instance.imp(); imp.use_plugin(); } unsafe extern "C" fn unuse_plugin(type_plugin: *mut gobject_ffi::GTypePlugin) { let instance = &*(type_plugin as *mut T::Instance); let imp = instance.imp(); imp.unuse_plugin(); } unsafe extern "C" fn complete_type_info( type_plugin: *mut gobject_ffi::GTypePlugin, gtype: ffi::GType, info_ptr: *mut gobject_ffi::GTypeInfo, value_table_ptr: *mut gobject_ffi::GTypeValueTable, ) { assert!(!info_ptr.is_null()); assert!(!value_table_ptr.is_null()); let instance = &*(type_plugin as *mut T::Instance); let imp = instance.imp(); let type_ = Type::from_glib(gtype); let info = TypeInfo::from_glib_ptr_borrow_mut(info_ptr); let value_table = TypeValueTable::from_glib_ptr_borrow_mut(value_table_ptr); let (info_, value_table_) = imp.complete_type_info(type_); *info = info_; *value_table = value_table_; } unsafe extern "C" fn complete_interface_info( type_plugin: *mut gobject_ffi::GTypePlugin, instance_gtype: ffi::GType, interface_gtype: ffi::GType, info_ptr: *mut gobject_ffi::GInterfaceInfo, ) { assert!(!info_ptr.is_null()); let instance = &*(type_plugin as *mut T::Instance); let imp = instance.imp(); let instance_type = Type::from_glib(instance_gtype); let interface_type = Type::from_glib(interface_gtype); let info = InterfaceInfo::from_glib_ptr_borrow_mut(info_ptr); let info_ = imp.complete_interface_info(instance_type, interface_type); *info = info_; } pub trait TypePluginRegisterImpl: ObjectImpl + TypePluginImpl { fn add_dynamic_interface( &self, _instance_type: Type, _interface_type: Type, _interface_info: &InterfaceInfo, ) { unimplemented!() } fn register_dynamic_enum( &self, _name: &str, _const_static_values: &'static EnumValues, ) -> Type { unimplemented!() } fn register_dynamic_flags( &self, _name: &str, _const_static_values: &'static FlagsValues, ) -> Type { unimplemented!() } fn register_dynamic_type( &self, _parent_type: Type, _type_name: &str, _type_info: &TypeInfo, _flags: TypeFlags, ) -> Type { unimplemented!() } } #[cfg(test)] mod tests { use crate::{self as glib, prelude::TypePluginExt}; use super::*; mod imp { use super::*; #[derive(Default)] pub struct SimplePlugin { type_info: std::cell::Cell>, } #[crate::object_subclass] impl ObjectSubclass for SimplePlugin { const NAME: &'static str = "SimplePlugin"; type Type = super::SimplePlugin; type Interfaces = (TypePlugin,); } impl ObjectImpl for SimplePlugin {} impl TypePluginImpl for SimplePlugin { fn use_plugin(&self) { // registers types on implementation load SimplePluginType::on_implementation_load(self.obj().as_ref()); } fn unuse_plugin(&self) { // unregisters types on implementation unload SimplePluginType::on_implementation_unload(self.obj().as_ref()); } fn complete_type_info(&self, _type_: Type) -> (TypeInfo, TypeValueTable) { assert!(self.type_info.get().is_some()); // returns type info (self.type_info.get().unwrap(), TypeValueTable::default()) } } impl TypePluginRegisterImpl for SimplePlugin { fn register_dynamic_type( &self, parent_type: Type, type_name: &str, type_info: &TypeInfo, flags: TypeFlags, ) -> Type { let type_ = Type::from_name(type_name).unwrap_or_else(|| { Type::register_dynamic( parent_type, type_name, self.obj().upcast_ref::(), flags, ) }); if type_.is_valid() { // save type info self.type_info.set(Some(*type_info)); } type_ } } #[derive(Default)] pub struct SimplePluginType; #[crate::object_subclass] #[object_subclass_dynamic(plugin_type = super::SimplePlugin)] impl ObjectSubclass for SimplePluginType { const NAME: &'static str = "SimplePluginType"; type Type = super::SimplePluginType; } impl ObjectImpl for SimplePluginType {} } crate::wrapper! { pub struct SimplePlugin(ObjectSubclass) @implements TypePlugin; } crate::wrapper! { pub struct SimplePluginType(ObjectSubclass); } #[test] fn test_plugin() { assert!(!imp::SimplePluginType::type_().is_valid()); let simple_plugin = crate::Object::new::(); // simulates the GLib type system to use the plugin. TypePluginExt::use_(&simple_plugin); assert!(imp::SimplePluginType::type_().is_valid()); TypePluginExt::unuse(&simple_plugin); } } glib-0.20.9/src/subclass/types.rs000064400000000000000000001300771046102023000147610ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! Module that contains the basic infrastructure for subclassing `GObject`. use std::{any::Any, collections::BTreeMap, marker, mem, ptr}; use super::{interface::ObjectInterface, SignalId}; use crate::{ ffi, gobject_ffi, object::{IsClass, IsInterface, ObjectSubclassIs, ParentClassIs}, prelude::*, translate::*, Closure, InterfaceInfo, Object, Type, TypeFlags, TypeInfo, Value, }; // rustdoc-stripper-ignore-next /// A newly registered `glib::Type` that is currently still being initialized. /// /// This allows running additional type-setup functions. #[derive(Debug, PartialEq, Eq)] pub struct InitializingType(pub(crate) Type, pub(crate) marker::PhantomData<*const T>); impl IntoGlib for InitializingType { type GlibType = ffi::GType; #[inline] fn into_glib(self) -> ffi::GType { self.0.into_glib() } } // rustdoc-stripper-ignore-next /// Struct used for the instance private data of the GObject. struct PrivateStruct { imp: T, instance_data: Option>>, } // rustdoc-stripper-ignore-next /// Trait implemented by structs that implement a `GObject` C instance struct. /// /// The struct must be `#[repr(C)]` and have the parent type's instance struct /// as the first field. /// /// See [`basic::InstanceStruct`] for a basic implementation of this that can /// be used most of the time and should only not be used if additional fields are /// required in the instance struct. /// /// [`basic::InstanceStruct`]: ../basic/struct.InstanceStruct.html pub unsafe trait InstanceStruct: Sized + 'static { // rustdoc-stripper-ignore-next /// Corresponding object subclass type for this instance struct. type Type: ObjectSubclass; // rustdoc-stripper-ignore-next /// Instance specific initialization. /// /// This is automatically called during instance initialization and must call `instance_init()` /// of the parent class. #[inline] fn instance_init(&mut self) { unsafe { let obj = from_glib_borrow::<_, Object>(self as *mut _ as *mut gobject_ffi::GObject); let obj = Borrowed::new(obj.into_inner().unsafe_cast()); let mut obj = InitializingObject(obj); <::ParentType as IsSubclassable>::instance_init( &mut obj, ); } } } // rustdoc-stripper-ignore-next /// Trait implemented by any type implementing `InstanceStruct` to return the implementation, private Rust struct. pub unsafe trait InstanceStructExt: InstanceStruct { // rustdoc-stripper-ignore-next /// Returns the implementation for from this instance struct, that /// is the implementor of [`ObjectImpl`] or subtraits. /// /// [`ObjectImpl`]: ../object/trait.ObjectImpl.html #[doc(alias = "get_impl")] fn imp(&self) -> &Self::Type; // rustdoc-stripper-ignore-next /// Returns the class struct for this specific instance. #[doc(alias = "get_class")] fn class(&self) -> &::Class; } // rustdoc-stripper-ignore-next /// Offset `ptr` by `offset` *bytes* and cast the result to `*const U`. /// /// The result must be a correctly aligned pointer to a valid value of type `U`. /// /// # Panics: /// /// This function panics if debug assertions are enabled if adding `offset` causes `ptr` to /// overflow or if the resulting pointer is not correctly aligned. #[inline] fn offset_ptr_by_bytes(ptr: *const T, offset: isize) -> *const U { // FIXME: Use `ptr::expose_addr()` once stable let ptr = ptr as usize; let ptr = if offset < 0 { ptr - (-offset) as usize } else { ptr + offset as usize }; debug_assert_eq!(ptr & (mem::align_of::() - 1), 0); ptr as *const U } // rustdoc-stripper-ignore-next /// Offset `ptr` by `offset` *bytes* and cast the result to `*mut U`. /// /// The result must be a correctly aligned pointer to a valid value of type `U`. /// /// # Panics: /// /// This function panics if debug assertions are enabled if adding `offset` causes `ptr` to /// overflow or if the resulting pointer is not correctly aligned. #[inline] fn offset_ptr_by_bytes_mut(ptr: *mut T, offset: isize) -> *mut U { // FIXME: Use `ptr::expose_addr()` once stable let ptr = ptr as usize; let ptr = if offset < 0 { ptr - (-offset) as usize } else { ptr + offset as usize }; debug_assert_eq!(ptr & (mem::align_of::() - 1), 0); ptr as *mut U } unsafe impl InstanceStructExt for T { #[inline] fn imp(&self) -> &Self::Type { unsafe { let data = Self::Type::type_data(); let private_offset = data.as_ref().impl_offset(); let imp = offset_ptr_by_bytes::(self, private_offset); &*imp } } #[inline] fn class(&self) -> &::Class { unsafe { &**(self as *const _ as *const *const ::Class) } } } // rustdoc-stripper-ignore-next /// Trait implemented by any type implementing `ObjectSubclassIs` to return the implementation, private Rust struct. pub trait ObjectSubclassIsExt: ObjectSubclassIs { // rustdoc-stripper-ignore-next /// Returns the implementation (the private Rust struct) of this class instance fn imp(&self) -> &Self::Subclass; } impl, S: ObjectSubclass> ObjectSubclassIsExt for T { #[inline] fn imp(&self) -> &T::Subclass { T::Subclass::from_obj(self) } } // rustdoc-stripper-ignore-next /// Trait implemented by structs that implement a `GObject` C class struct. /// /// The struct must be `#[repr(C)]` and have the parent type's class struct /// as the first field. /// /// See [`basic::ClassStruct`] for a basic implementation of this that can /// be used most of the time and should only not be used if additional fields are /// required in the class struct, e.g. for declaring new virtual methods. /// /// [`basic::ClassStruct`]: ../basic/struct.ClassStruct.html pub unsafe trait ClassStruct: Sized + 'static { // rustdoc-stripper-ignore-next /// Corresponding object subclass type for this class struct. type Type: ObjectSubclass; // rustdoc-stripper-ignore-next /// Override the vfuncs of all parent types. /// /// This is automatically called during type initialization. #[inline] fn class_init(&mut self) { unsafe { let base = &mut *(self as *mut _ as *mut crate::Class<::ParentType>); <::ParentType as IsSubclassable>::class_init( base, ); } } } // rustdoc-stripper-ignore-next /// Trait for subclassable class structs. pub unsafe trait IsSubclassable: IsSubclassableDefault { // rustdoc-stripper-ignore-next /// Override the virtual methods of this class for the given subclass and do other class /// initialization. /// /// This is automatically called during type initialization and must call `class_init()` of the /// parent class. #[inline] fn class_init(class: &mut crate::Class) { Self::default_class_init(class); } // rustdoc-stripper-ignore-next /// Instance specific initialization. /// /// This is automatically called during instance initialization and must call `instance_init()` /// of the parent class. #[inline] fn instance_init(instance: &mut InitializingObject) { Self::default_instance_init(instance); } } // FIXME: It should be possible to make implemented for all instances of `IsSubclassable` // with specialization, and make it private. #[doc(hidden)] pub trait IsSubclassableDefault: IsClass { fn default_class_init(class: &mut crate::Class); fn default_instance_init(instance: &mut InitializingObject); } impl + ParentClassIs> IsSubclassableDefault for U where U::Parent: IsSubclassable, { #[inline] fn default_class_init(class: &mut crate::Class) { U::Parent::class_init(class); } #[inline] fn default_instance_init(instance: &mut InitializingObject) { U::Parent::instance_init(instance); } } impl IsSubclassableDefault for Object { #[inline] fn default_class_init(_class: &mut crate::Class) {} #[inline] fn default_instance_init(_instance: &mut InitializingObject) {} } pub trait IsSubclassableExt: IsClass + ParentClassIs { fn parent_class_init(class: &mut crate::Class) where Self::Parent: IsSubclassable; fn parent_instance_init(instance: &mut InitializingObject) where Self::Parent: IsSubclassable; } impl IsSubclassableExt for U { #[inline] fn parent_class_init(class: &mut crate::Class) where U::Parent: IsSubclassable, { Self::Parent::class_init(class); } #[inline] fn parent_instance_init(instance: &mut InitializingObject) where U::Parent: IsSubclassable, { Self::Parent::instance_init(instance); } } // rustdoc-stripper-ignore-next /// Trait implemented by structs that implement a `GTypeInterface` C class struct. /// /// This must only be implemented on `#[repr(C)]` structs and have an interface /// that inherits from `gobject_ffi::GTypeInterface` as the first field. pub unsafe trait InterfaceStruct: Sized + 'static where Self: Copy, { // rustdoc-stripper-ignore-next /// Corresponding object interface type for this class struct. type Type: ObjectInterface; // rustdoc-stripper-ignore-next /// Set up default implementations for interface vfuncs. /// /// This is automatically called during type initialization. #[inline] fn interface_init(&mut self) {} } // rustdoc-stripper-ignore-next /// Trait for implementable interfaces. pub unsafe trait IsImplementable: IsInterface { // rustdoc-stripper-ignore-next /// Override the virtual methods of this interface for the given subclass and do other /// interface initialization. /// /// This is automatically called during type initialization. fn interface_init(_iface: &mut crate::Interface) {} // rustdoc-stripper-ignore-next /// Instance specific initialization. /// /// This is automatically called during instance initialization. fn instance_init(_instance: &mut InitializingObject) {} } unsafe extern "C" fn interface_init>( iface: ffi::gpointer, _iface_data: ffi::gpointer, ) where ::GlibClassType: Copy, { let iface = &mut *(iface as *mut crate::Interface); let mut data = T::type_data(); if data.as_ref().parent_ifaces.is_none() { data.as_mut().parent_ifaces = Some(BTreeMap::default()); } { let copy = Box::new(*iface.as_ref()); data.as_mut() .parent_ifaces .as_mut() .unwrap() .insert(A::static_type(), Box::into_raw(copy) as ffi::gpointer); } A::interface_init(iface); } // rustdoc-stripper-ignore-next /// Trait for a type list of interfaces. pub trait InterfaceList { // rustdoc-stripper-ignore-next /// Returns the list of types and corresponding interface infos for this list. fn iface_infos() -> Vec<(Type, InterfaceInfo)>; // rustdoc-stripper-ignore-next /// Runs `instance_init` on each of the `IsImplementable` items. fn instance_init(_instance: &mut InitializingObject); } impl InterfaceList for () { fn iface_infos() -> Vec<(Type, InterfaceInfo)> { vec![] } #[inline] fn instance_init(_instance: &mut InitializingObject) {} } impl> InterfaceList for (A,) where ::GlibClassType: Copy, { fn iface_infos() -> Vec<(Type, InterfaceInfo)> { vec![( A::static_type(), InterfaceInfo(gobject_ffi::GInterfaceInfo { interface_init: Some(interface_init::), ..InterfaceInfo::default().0 }), )] } #[inline] fn instance_init(instance: &mut InitializingObject) { A::instance_init(instance); } } // Generates all the InterfaceList impls for interface_lists of arbitrary sizes based on a list of type // parameters like A B C. It would generate the impl then for (A, B) and (A, B, C). macro_rules! interface_list_trait( ($name1:ident, $name2: ident, $($name:ident),*) => ( interface_list_trait!(__impl $name1, $name2; $($name),*); ); (__impl $($name:ident),+; $name1:ident, $($name2:ident),*) => ( interface_list_trait_impl!($($name),+); interface_list_trait!(__impl $($name),+ , $name1; $($name2),*); ); (__impl $($name:ident),+; $name1:ident) => ( interface_list_trait_impl!($($name),+); interface_list_trait_impl!($($name),+, $name1); ); ); // Generates the impl block for InterfaceList on interface_lists or arbitrary sizes based on its // arguments. Takes a list of type parameters as parameters, e.g. A B C // and then implements the trait on (A, B, C). macro_rules! interface_list_trait_impl( ($($name:ident),+) => ( impl),+> InterfaceList for ( $($name),+ ) where $(<$name as ObjectType>::GlibClassType: Copy),+ { fn iface_infos() -> Vec<(Type, InterfaceInfo)> { vec![ $( ( $name::static_type(), InterfaceInfo(gobject_ffi::GInterfaceInfo { interface_init: Some(interface_init::), interface_finalize: None, interface_data: ptr::null_mut(), }), ) ),+ ] } #[inline] fn instance_init(instance: &mut InitializingObject) { $( $name::instance_init(instance); )+ } } ); ); interface_list_trait!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S); /// Type-specific data that is filled in during type creation. pub struct TypeData { type_: Type, parent_class: ffi::gpointer, parent_ifaces: Option>, class_data: Option>>, private_offset: isize, private_imp_offset: isize, } unsafe impl Send for TypeData {} unsafe impl Sync for TypeData {} impl TypeData { pub const fn new() -> Self { Self { type_: Type::INVALID, parent_class: ::std::ptr::null_mut(), parent_ifaces: None, class_data: None, private_offset: 0, private_imp_offset: 0, } } // rustdoc-stripper-ignore-next /// Returns the type ID. #[inline] #[doc(alias = "get_type")] pub fn type_(&self) -> Type { self.type_ } // rustdoc-stripper-ignore-next /// Returns a pointer to the native parent class. /// /// This is used for chaining up to the parent class' implementation /// of virtual methods. #[doc(alias = "get_parent_class")] #[inline] pub fn parent_class(&self) -> ffi::gpointer { debug_assert!(!self.parent_class.is_null()); self.parent_class } // rustdoc-stripper-ignore-next /// Returns a pointer to the native parent interface struct for interface `type_`. /// /// This is used for chaining up to the parent interface's implementation /// of virtual methods. /// /// # Panics /// /// This function panics if the type to which the `TypeData` belongs does not implement the /// given interface or was not registered yet. #[doc(alias = "get_parent_interface")] pub fn parent_interface(&self) -> ffi::gpointer { match self.parent_ifaces { None => unreachable!("No parent interfaces"), Some(ref parent_ifaces) => *parent_ifaces .get(&I::static_type()) .expect("Parent interface not found"), } } // rustdoc-stripper-ignore-next /// Returns a pointer to the class implementation specific data. /// /// This is used for class implementations to store additional data. #[doc(alias = "get_class_data")] pub fn class_data(&self, type_: Type) -> Option<&T> { match self.class_data { None => None, Some(ref data) => data.get(&type_).and_then(|ptr| ptr.downcast_ref()), } } // rustdoc-stripper-ignore-next /// Gets a mutable reference of the class implementation specific data. /// /// # Safety /// /// This can only be used while the type is being initialized. #[doc(alias = "get_class_data_mut")] pub unsafe fn class_data_mut( &mut self, type_: Type, ) -> Option<&mut T> { match self.class_data { None => None, Some(ref mut data) => data.get_mut(&type_).and_then(|v| v.downcast_mut()), } } // rustdoc-stripper-ignore-next /// Sets class specific implementation data. /// /// # Safety /// /// This can only be used while the type is being initialized. /// /// # Panics /// /// If the class_data already contains a data for the specified `type_`. pub unsafe fn set_class_data(&mut self, type_: Type, data: T) { if self.class_data.is_none() { self.class_data = Some(BTreeMap::default()); } if let Some(ref mut class_data) = self.class_data { assert!( class_data.get(&type_).is_none(), "The class_data already contains a key for {type_}", ); class_data.insert(type_, Box::new(data)); } } // rustdoc-stripper-ignore-next /// Returns the offset of the private implementation struct in bytes relative to the beginning /// of the instance struct. #[doc(alias = "get_impl_offset")] #[inline] pub fn impl_offset(&self) -> isize { self.private_offset + self.private_imp_offset } } impl Default for TypeData { fn default() -> Self { Self::new() } } // rustdoc-stripper-ignore-next /// Type methods required for an [`ObjectSubclass`] implementation. /// /// This is usually generated by the [`#[object_subclass]`](crate::object_subclass) attribute macro. pub unsafe trait ObjectSubclassType { // rustdoc-stripper-ignore-next /// Storage for the type-specific data used during registration. fn type_data() -> ptr::NonNull; // rustdoc-stripper-ignore-next /// Returns the `glib::Type` ID of the subclass. /// /// This will register the type with the type system on the first call. #[doc(alias = "get_type")] fn type_() -> Type; } // rustdoc-stripper-ignore-next /// The central trait for subclassing a `GObject` type. /// /// Links together the type name, parent type and the instance and /// class structs for type registration and allows subclasses to /// hook into various steps of the type registration and initialization. /// /// See [`register_type`] for registering an implementation of this trait /// with the type system. /// /// [`register_type`]: fn.register_type.html pub trait ObjectSubclass: ObjectSubclassType + Sized + 'static { // rustdoc-stripper-ignore-next /// `GObject` type name. /// /// This must be unique in the whole process. const NAME: &'static str; // rustdoc-stripper-ignore-next /// 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; // rustdoc-stripper-ignore-next /// Allow name conflicts for this class. /// /// By default, trying to register a type with a name that was registered before will panic. If /// this is set to `true` then a new name will be selected by appending a counter. /// /// This is useful for defining new types in Rust library crates that might be linked multiple /// times in the same process. /// /// A consequence of setting this to `true` is that it's not guaranteed that /// `glib::Type::from_name(Self::NAME).unwrap() == Self::type_()`. /// /// Note that this is not allowed for dynamic types. If a dynamic type is registered and a type /// with that name exists already, it is assumed that they're the same. /// /// Optional. const ALLOW_NAME_CONFLICT: bool = false; // rustdoc-stripper-ignore-next /// Wrapper around this subclass defined with `wrapper!` type Type: ObjectType + ObjectSubclassIs + FromGlibPtrFull<*mut ::GlibType> + FromGlibPtrBorrow<*mut ::GlibType> + FromGlibPtrNone<*mut ::GlibType>; // rustdoc-stripper-ignore-next /// Parent Rust type to inherit from. type ParentType: IsSubclassable + FromGlibPtrFull<*mut ::GlibType> + FromGlibPtrBorrow<*mut ::GlibType> + FromGlibPtrNone<*mut ::GlibType>; // rustdoc-stripper-ignore-next /// List of interfaces implemented by this type. type Interfaces: InterfaceList; // rustdoc-stripper-ignore-next /// The C instance struct. /// /// See [`basic::InstanceStruct`] for an basic instance struct that should be /// used in most cases. /// /// [`basic::InstanceStruct`]: ../basic/struct.InstanceStruct.html // TODO: Should default to basic::InstanceStruct once associated // type defaults are stabilized https://github.com/rust-lang/rust/issues/29661 type Instance: InstanceStruct; // rustdoc-stripper-ignore-next /// The C class struct. /// /// See [`basic::ClassStruct`] for an basic class struct that should be /// used in most cases. /// /// [`basic::ClassStruct`]: ../basic/struct.ClassStruct.html // TODO: Should default to basic::ClassStruct once associated // type defaults are stabilized https://github.com/rust-lang/rust/issues/29661 type Class: ClassStruct; // rustdoc-stripper-ignore-next /// 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 #[inline] fn type_init(_type_: &mut InitializingType) {} /// Class initialization. /// // rustdoc-stripper-ignore-next /// This is called after `type_init` and before the first instance /// of the subclass is created. Subclasses can use this to do class- /// specific initialization, e.g. for registering signals on the class /// or calling class methods. /// /// Optional #[inline] fn class_init(_klass: &mut Self::Class) {} // rustdoc-stripper-ignore-next /// Constructor. /// /// This is called during object instantiation before further subclasses /// are initialized, and should return a new instance of the subclass /// private struct. /// /// Optional, either implement this or `with_class()`. fn new() -> Self { unimplemented!(); } // rustdoc-stripper-ignore-next /// 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()`. #[inline] fn with_class(_klass: &Self::Class) -> Self { Self::new() } // rustdoc-stripper-ignore-next /// Performs additional instance initialization. /// /// Called just after `with_class()`. At this point the initialization has not completed yet, so /// only a limited set of operations is safe (see `InitializingObject`). #[inline] fn instance_init(_obj: &InitializingObject) {} } // rustdoc-stripper-ignore-next /// Extension methods for all `ObjectSubclass` impls. pub trait ObjectSubclassExt: ObjectSubclass { // rustdoc-stripper-ignore-next /// Returns the corresponding object instance. #[doc(alias = "get_instance")] #[deprecated = "Use obj() instead"] fn instance(&self) -> crate::BorrowedObject; // rustdoc-stripper-ignore-next /// Returns the implementation from an instance. #[deprecated = "Use from_obj() instead"] fn from_instance(obj: &Self::Type) -> &Self; // rustdoc-stripper-ignore-next /// Returns the corresponding object instance. /// /// Shorter alias for `instance()`. #[doc(alias = "get_instance")] fn obj(&self) -> crate::BorrowedObject; // rustdoc-stripper-ignore-next /// Returns the implementation from an instance. /// /// Shorter alias for `from_instance()`. fn from_obj(obj: &Self::Type) -> &Self; // rustdoc-stripper-ignore-next /// Returns a new reference-counted wrapper around `self`. fn ref_counted(&self) -> super::ObjectImplRef; // rustdoc-stripper-ignore-next /// Returns a pointer to the instance implementation specific data. /// /// This is used for the subclassing infrastructure to store additional instance data. #[doc(alias = "get_instance_data")] fn instance_data(&self, type_: Type) -> Option<&U>; } impl ObjectSubclassExt for T { #[inline] fn instance(&self) -> crate::BorrowedObject { self.obj() } #[inline] fn from_instance(obj: &Self::Type) -> &Self { Self::from_obj(obj) } #[inline] fn obj(&self) -> crate::BorrowedObject { unsafe { let data = Self::type_data(); let type_ = data.as_ref().type_(); debug_assert!(type_.is_valid()); let offset = -data.as_ref().impl_offset(); let ptr = offset_ptr_by_bytes::::GlibType>(self, offset); // The object might just be finalized, and in that case it's unsafe to access // it and use any API on it. This can only happen from inside the Drop impl // of Self. debug_assert_ne!((*(ptr as *const gobject_ffi::GObject)).ref_count, 0); crate::BorrowedObject::new(mut_override(ptr)) } } #[inline] fn from_obj(obj: &Self::Type) -> &Self { unsafe { let ptr = obj.as_ptr() as *const Self::Instance; (*ptr).imp() } } #[inline] fn ref_counted(&self) -> super::ObjectImplRef { super::ObjectImplRef::new(self) } #[inline] fn instance_data(&self, type_: Type) -> Option<&U> { unsafe { let type_data = Self::type_data(); let self_type_ = type_data.as_ref().type_(); debug_assert!(self_type_.is_valid()); let offset = -type_data.as_ref().private_imp_offset; let ptr = offset_ptr_by_bytes::>(self, offset); let priv_ = &*ptr; match priv_.instance_data { None => None, Some(ref data) => data.get(&type_).and_then(|ptr| ptr.downcast_ref()), } } } } // rustdoc-stripper-ignore-next /// Helper trait for macros to access a subclass or its wrapper. pub trait FromObject { type FromObjectType; fn from_object(obj: &Self::FromObjectType) -> &Self; } // rustdoc-stripper-ignore-next /// An object that is currently being initialized. /// /// Binding crates should use traits for adding methods to this struct. Only methods explicitly safe /// to call during `instance_init()` should be added. pub struct InitializingObject(Borrowed); impl InitializingObject { // rustdoc-stripper-ignore-next /// Returns a reference to the object. /// /// # Safety /// /// The returned object has not been completely initialized at this point. Use of the object /// should be restricted to methods that are explicitly documented to be safe to call during /// `instance_init()`. #[inline] pub unsafe fn as_ref(&self) -> &T::Type { &self.0 } // rustdoc-stripper-ignore-next /// Returns a pointer to the object. /// /// # Safety /// /// The returned object has not been completely initialized at this point. Use of the object /// should be restricted to methods that are explicitly documented to be safe to call during /// `instance_init()`. #[inline] pub fn as_ptr(&self) -> *mut T::Type { self.0.as_ptr() as *const T::Type as *mut T::Type } // rustdoc-stripper-ignore-next /// Sets instance specific implementation data. /// /// # Panics /// /// If the instance_data already contains a data for the specified `type_`. pub fn set_instance_data(&mut self, type_: Type, data: U) { unsafe { let type_data = T::type_data(); let self_type_ = type_data.as_ref().type_(); debug_assert!(self_type_.is_valid()); let offset = type_data.as_ref().private_offset; let ptr = offset_ptr_by_bytes_mut::< <::Type as ObjectType>::GlibType, PrivateStruct, >(self.0.as_ptr(), offset); let priv_ = &mut *ptr; if priv_.instance_data.is_none() { priv_.instance_data = Some(BTreeMap::default()); } if let Some(ref mut instance_data) = priv_.instance_data { assert!( instance_data.get(&type_).is_none(), "The class_data already contains a key for {type_}", ); instance_data.insert(type_, Box::new(data)); } } } } unsafe extern "C" fn class_init( klass: ffi::gpointer, _klass_data: ffi::gpointer, ) { let mut data = T::type_data(); // We have to update the private struct offset once the class is actually // being initialized. let mut private_offset = data.as_ref().private_offset as i32; gobject_ffi::g_type_class_adjust_private_offset(klass, &mut private_offset); data.as_mut().private_offset = private_offset as isize; // Set trampolines for the basic GObject virtual methods. { let gobject_klass = &mut *(klass as *mut gobject_ffi::GObjectClass); gobject_klass.finalize = Some(finalize::); } // And finally peek the parent class struct (containing the parent class' // implementations of virtual methods for chaining up), and call the subclass' // class initialization function. { let klass = &mut *(klass as *mut T::Class); let parent_class = gobject_ffi::g_type_class_peek_parent(klass as *mut _ as ffi::gpointer) as *mut ::GlibClassType; debug_assert!(!parent_class.is_null()); data.as_mut().parent_class = parent_class as ffi::gpointer; klass.class_init(); T::class_init(klass); } } unsafe extern "C" fn instance_init( obj: *mut gobject_ffi::GTypeInstance, klass: ffi::gpointer, ) { // Get offset to the storage of our private struct, create it // and actually store it in that place. let mut data = T::type_data(); let private_offset = data.as_mut().private_offset; let priv_ptr = offset_ptr_by_bytes_mut::>( obj, private_offset, ); assert!( priv_ptr as usize & (mem::align_of::>() - 1) == 0, "Private instance data has higher alignment requirements ({}) than \ the allocation from GLib. If alignment of more than {} bytes \ is required, store the corresponding data separately on the heap.", mem::align_of::>(), 2 * mem::size_of::(), ); let klass = &*(klass as *const T::Class); let imp = T::with_class(klass); ptr::write( priv_ptr, PrivateStruct { imp, instance_data: None, }, ); // Any additional instance initialization. T::Instance::instance_init(&mut *(obj as *mut _)); let obj = from_glib_borrow::<_, Object>(obj.cast()); let obj = Borrowed::new(obj.into_inner().unsafe_cast()); let mut obj = InitializingObject(obj); T::Interfaces::instance_init(&mut obj); T::instance_init(&obj); } unsafe extern "C" fn finalize(obj: *mut gobject_ffi::GObject) { // Retrieve the private struct and drop it for freeing all associated memory. let mut data = T::type_data(); let private_offset = data.as_mut().private_offset; let priv_ptr = offset_ptr_by_bytes_mut::>(obj, private_offset); ptr::drop_in_place(ptr::addr_of_mut!((*priv_ptr).imp)); ptr::drop_in_place(ptr::addr_of_mut!((*priv_ptr).instance_data)); // Chain up to the parent class' finalize implementation, if any. let parent_class = &*(data.as_ref().parent_class() as *const gobject_ffi::GObjectClass); if let Some(ref func) = parent_class.finalize { func(obj); } } // rustdoc-stripper-ignore-next /// Register a `glib::Type` ID for `T`. /// /// This must be called only once and will panic on a second call. /// /// The [`object_subclass!`] macro will create a `type_()` function around this, which will /// ensure that it's only ever called once. /// /// [`object_subclass!`]: ../../macro.object_subclass.html pub fn register_type() -> Type { // GLib aligns the type private data to two gsizes, so we can't safely store any type there that // requires a bigger alignment. assert!( mem::align_of::() <= 2 * mem::size_of::(), "Alignment {} of type not supported, bigger than {}", mem::align_of::(), 2 * mem::size_of::(), ); unsafe { use std::ffi::CString; let type_name = if T::ALLOW_NAME_CONFLICT { let mut i = 0; loop { let type_name = CString::new(if i == 0 { T::NAME.to_string() } else { format!("{}-{}", T::NAME, i) }) .unwrap(); if gobject_ffi::g_type_from_name(type_name.as_ptr()) == gobject_ffi::G_TYPE_INVALID { break type_name; } i += 1; } } else { let type_name = CString::new(T::NAME).unwrap(); assert_eq!( gobject_ffi::g_type_from_name(type_name.as_ptr()), gobject_ffi::G_TYPE_INVALID, "Type {} has already been registered", type_name.to_str().unwrap() ); type_name }; let type_ = Type::from_glib(gobject_ffi::g_type_register_static_simple( ::static_type().into_glib(), type_name.as_ptr(), mem::size_of::() as u32, Some(class_init::), mem::size_of::() as u32, Some(instance_init::), if T::ABSTRACT { gobject_ffi::G_TYPE_FLAG_ABSTRACT } else { 0 }, )); assert!(type_.is_valid()); let mut data = T::type_data(); data.as_mut().type_ = type_; let private_offset = gobject_ffi::g_type_add_instance_private( type_.into_glib(), mem::size_of::>(), ); data.as_mut().private_offset = private_offset as isize; // Get the offset from PrivateStruct to the imp field in it. This has to go through // some hoops because Rust doesn't have an offsetof operator yet. data.as_mut().private_imp_offset = { // Must not be a dangling pointer so let's create some uninitialized memory let priv_ = mem::MaybeUninit::>::uninit(); let ptr = priv_.as_ptr(); let imp_ptr = ptr::addr_of!((*ptr).imp); (imp_ptr as isize) - (ptr as isize) }; let iface_types = T::Interfaces::iface_infos(); for (iface_type, iface_info) in iface_types { gobject_ffi::g_type_add_interface_static( type_.into_glib(), iface_type.into_glib(), iface_info.as_ptr(), ); } T::type_init(&mut InitializingType::(type_, marker::PhantomData)); type_ } } // rustdoc-stripper-ignore-next /// Registers a `glib::Type` ID for `T` as a dynamic type. /// /// An object subclass must be explicitly registered as a dynamic type when the /// system loads the implementation by calling [`TypePluginImpl::use_`] or more /// specifically [`TypeModuleImpl::load`]. Therefore, unlike for object /// subclasses registered as static types, object subclasses registered as /// dynamic types can be registered several times. /// /// The [`object_subclass_dynamic!`] macro helper attribute will create /// `register_type()` and `on_implementation_load()` functions around this, /// which will ensure that the function is called when necessary. /// /// [`object_subclass_dynamic!`]: ../../../glib_macros/attr.object_subclass.html /// [`TypePluginImpl::use_`]: ../type_plugin/trait.TypePluginImpl.html#method.use_ /// [`TypeModuleImpl::load`]: ../type_module/trait.TypeModuleImpl.html#method.load pub fn register_dynamic_type( type_plugin: &P, ) -> Type { // GLib aligns the type private data to two gsizes, so we can't safely store any type there that // requires a bigger alignment. assert!( mem::align_of::() <= 2 * mem::size_of::(), "Alignment {} of type not supported, bigger than {}", mem::align_of::(), 2 * mem::size_of::(), ); unsafe { use std::ffi::CString; let type_name = CString::new(T::NAME).unwrap(); let already_registered = gobject_ffi::g_type_from_name(type_name.as_ptr()) != gobject_ffi::G_TYPE_INVALID; let type_info = TypeInfo(gobject_ffi::GTypeInfo { class_size: mem::size_of::() as u16, class_init: Some(class_init::), instance_size: mem::size_of::() as u16, instance_init: Some(instance_init::), ..TypeInfo::default().0 }); // registers the type within the `type_plugin` let type_ = type_plugin.register_dynamic_type( ::static_type(), type_name.to_str().unwrap(), &type_info, if T::ABSTRACT { TypeFlags::ABSTRACT } else { TypeFlags::NONE }, ); assert!(type_.is_valid()); let mut data = T::type_data(); data.as_mut().type_ = type_; let private_offset = mem::size_of::>(); data.as_mut().private_offset = private_offset as isize; // gets the offset from PrivateStruct to the imp field in it. This has to go through // some hoops because Rust doesn't have an offsetof operator yet. data.as_mut().private_imp_offset = { // Must not be a dangling pointer so let's create some uninitialized memory let priv_ = mem::MaybeUninit::>::uninit(); let ptr = priv_.as_ptr(); let imp_ptr = ptr::addr_of!((*ptr).imp); (imp_ptr as isize) - (ptr as isize) }; let plugin_ptr = type_plugin.as_ref().to_glib_none().0; let iface_types = T::Interfaces::iface_infos(); for (iface_type, iface_info) in iface_types { match gobject_ffi::g_type_get_plugin(iface_type.into_glib()) { // if interface type's plugin is null or is different to the `type_plugin`, // then interface can only be added as if the type was static iface_plugin if iface_plugin != plugin_ptr => { // but adding interface to a static type can be done only once if !already_registered { gobject_ffi::g_type_add_interface_static( type_.into_glib(), iface_type.into_glib(), iface_info.as_ptr(), ); } } // else interface can be added and registered to live in the `type_plugin` _ => type_plugin.add_dynamic_interface(type_, iface_type, &iface_info), } } T::type_init(&mut InitializingType::(type_, marker::PhantomData)); type_ } } pub(crate) unsafe fn signal_override_class_handler( name: &str, type_: ffi::GType, class_handler: F, ) where F: Fn(&super::SignalClassHandlerToken, &[Value]) -> Option + Send + Sync + 'static, { let (signal_id, _) = SignalId::parse_name(name, from_glib(type_), false) .unwrap_or_else(|| panic!("Signal '{name}' not found")); let query = signal_id.query(); let return_type = query.return_type(); let class_handler = Closure::new(move |values| { let instance = gobject_ffi::g_value_get_object(values[0].to_glib_none().0); let res = class_handler( &super::SignalClassHandlerToken( instance as *mut _, return_type.into(), values.as_ptr(), ), values, ); if return_type == Type::UNIT { if let Some(ref v) = res { panic!( "Signal has no return value but class handler returned a value of type {}", v.type_() ); } } else { match res { None => { panic!("Signal has a return value but class handler returned none"); } Some(ref v) => { assert!( v.type_().is_a(return_type.into()), "Signal has a return type of {} but class handler returned {}", Type::from(return_type), v.type_() ); } } } res }); gobject_ffi::g_signal_override_class_closure( signal_id.into_glib(), type_, class_handler.to_glib_none().0, ); } pub(crate) unsafe fn signal_chain_from_overridden( instance: *mut gobject_ffi::GTypeInstance, token: &super::SignalClassHandlerToken, values: &[Value], ) -> Option { assert_eq!(instance, token.0); assert_eq!( values.as_ptr(), token.2, "Arguments must be forwarded without changes when chaining up" ); let mut result = Value::from_type_unchecked(token.1); gobject_ffi::g_signal_chain_from_overridden( values.as_ptr() as *mut Value as *mut gobject_ffi::GValue, result.to_glib_none_mut().0, ); Some(result).filter(|r| r.type_().is_valid() && r.type_() != Type::UNIT) } glib-0.20.9/src/thread_guard.rs000064400000000000000000000064621046102023000144270ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ mem, ptr, sync::atomic::{AtomicUsize, Ordering}, }; fn next_thread_id() -> usize { static COUNTER: AtomicUsize = AtomicUsize::new(0); COUNTER.fetch_add(1, Ordering::SeqCst) } // rustdoc-stripper-ignore-next /// Returns a unique ID for the current thread. /// /// Actual thread IDs can be reused by the OS once the old thread finished. /// This works around ambiguity created by ID reuse by using a separate TLS counter for threads. pub fn thread_id() -> usize { thread_local!(static THREAD_ID: usize = next_thread_id()); THREAD_ID.with(|&x| x) } // rustdoc-stripper-ignore-next /// Thread guard that only gives access to the contained value on the thread it was created on. pub struct ThreadGuard { thread_id: usize, value: T, } impl ThreadGuard { // rustdoc-stripper-ignore-next /// Create a new thread guard around `value`. /// /// The thread guard ensures that access to the value is only allowed from the thread it was /// created on, and otherwise panics. /// /// The thread guard implements the `Send` trait even if the contained value does not. #[inline] pub fn new(value: T) -> Self { Self { thread_id: thread_id(), value, } } // rustdoc-stripper-ignore-next /// Return a reference to the contained value from the thread guard. /// /// # Panics /// /// This function panics if called from a different thread than where the thread guard was /// created. #[inline] pub fn get_ref(&self) -> &T { assert!( self.thread_id == thread_id(), "Value accessed from different thread than where it was created" ); &self.value } // rustdoc-stripper-ignore-next /// Return a mutable reference to the contained value from the thread guard. /// /// # Panics /// /// This function panics if called from a different thread than where the thread guard was /// created. #[inline] pub fn get_mut(&mut self) -> &mut T { assert!( self.thread_id == thread_id(), "Value accessed from different thread than where it was created" ); &mut self.value } // rustdoc-stripper-ignore-next /// Return the contained value from the thread guard. /// /// # Panics /// /// This function panics if called from a different thread than where the thread guard was /// created. #[inline] pub fn into_inner(self) -> T { assert!( self.thread_id == thread_id(), "Value accessed from different thread than where it was created" ); unsafe { ptr::read(&mem::ManuallyDrop::new(self).value) } } // rustdoc-stripper-ignore-next /// Returns `true` if the current thread owns the value, i.e. it can be accessed safely. #[inline] pub fn is_owner(&self) -> bool { self.thread_id == thread_id() } } impl Drop for ThreadGuard { #[inline] fn drop(&mut self) { assert!( self.thread_id == thread_id(), "Value dropped on a different thread than where it was created" ); } } unsafe impl Send for ThreadGuard {} unsafe impl Sync for ThreadGuard {} glib-0.20.9/src/thread_pool.rs000064400000000000000000000171151046102023000142730ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{future::Future, panic, ptr}; use futures_channel::oneshot; use crate::{ffi, translate::*}; #[derive(Debug)] #[doc(alias = "GThreadPool")] pub struct ThreadPool(ptr::NonNull); unsafe impl Send for ThreadPool {} unsafe impl Sync for ThreadPool {} // rustdoc-stripper-ignore-next /// A handle to a thread running on a [`ThreadPool`]. /// /// Like [`std::thread::JoinHandle`] for a GLib thread. The return value from the task can be /// retrieved by calling [`ThreadHandle::join`]. Dropping the handle "detaches" the thread, /// allowing it to complete but discarding the return value. #[derive(Debug)] pub struct ThreadHandle { rx: std::sync::mpsc::Receiver>, } impl ThreadHandle { // rustdoc-stripper-ignore-next /// Waits for the associated thread to finish. /// /// Blocks until the associated thread returns. Returns `Ok` with the value returned from the /// thread, or `Err` if the thread panicked. This function will return immediately if the /// associated thread has already finished. #[inline] pub fn join(self) -> std::thread::Result { self.rx.recv().unwrap() } } impl ThreadPool { #[doc(alias = "g_thread_pool_new")] pub fn shared(max_threads: Option) -> Result { unsafe { let mut err = ptr::null_mut(); let pool = ffi::g_thread_pool_new( Some(spawn_func), ptr::null_mut(), max_threads.map(|v| v as i32).unwrap_or(-1), ffi::GFALSE, &mut err, ); if pool.is_null() { Err(from_glib_full(err)) } else { Ok(ThreadPool(ptr::NonNull::new_unchecked(pool))) } } } #[doc(alias = "g_thread_pool_new")] pub fn exclusive(max_threads: u32) -> Result { unsafe { let mut err = ptr::null_mut(); let pool = ffi::g_thread_pool_new( Some(spawn_func), ptr::null_mut(), max_threads as i32, ffi::GTRUE, &mut err, ); if pool.is_null() { Err(from_glib_full(err)) } else { Ok(ThreadPool(ptr::NonNull::new_unchecked(pool))) } } } #[doc(alias = "g_thread_pool_push")] pub fn push T + Send + 'static>( &self, func: F, ) -> Result, crate::Error> { let (tx, rx) = std::sync::mpsc::sync_channel(1); unsafe { let func: Box = Box::new(move || { let _ = tx.send(panic::catch_unwind(panic::AssertUnwindSafe(func))); }); let func = Box::new(func); let mut err = ptr::null_mut(); let func = Box::into_raw(func); let ret: bool = from_glib(ffi::g_thread_pool_push( self.0.as_ptr(), func as *mut _, &mut err, )); if ret { Ok(ThreadHandle { rx }) } else { let _ = Box::from_raw(func); Err(from_glib_full(err)) } } } pub fn push_future T + Send + 'static>( &self, func: F, ) -> Result> + Send + Sync + 'static, crate::Error> { let (sender, receiver) = oneshot::channel(); self.push(move || { let _ = sender.send(panic::catch_unwind(panic::AssertUnwindSafe(func))); })?; Ok(async move { receiver.await.expect("Dropped before executing") }) } #[doc(alias = "g_thread_pool_set_max_threads")] pub fn set_max_threads(&self, max_threads: Option) -> Result<(), crate::Error> { unsafe { let mut err = ptr::null_mut(); let ret: bool = from_glib(ffi::g_thread_pool_set_max_threads( self.0.as_ptr(), max_threads.map(|v| v as i32).unwrap_or(-1), &mut err, )); if ret { Ok(()) } else { Err(from_glib_full(err)) } } } #[doc(alias = "g_thread_pool_get_max_threads")] #[doc(alias = "get_max_threads")] pub fn max_threads(&self) -> Option { unsafe { let max_threads = ffi::g_thread_pool_get_max_threads(self.0.as_ptr()); if max_threads == -1 { None } else { Some(max_threads as u32) } } } #[doc(alias = "g_thread_pool_get_num_threads")] #[doc(alias = "get_num_threads")] pub fn num_threads(&self) -> u32 { unsafe { ffi::g_thread_pool_get_num_threads(self.0.as_ptr()) } } #[doc(alias = "g_thread_pool_unprocessed")] #[doc(alias = "get_unprocessed")] pub fn unprocessed(&self) -> u32 { unsafe { ffi::g_thread_pool_unprocessed(self.0.as_ptr()) } } #[doc(alias = "g_thread_pool_set_max_unused_threads")] pub fn set_max_unused_threads(max_threads: Option) { unsafe { ffi::g_thread_pool_set_max_unused_threads(max_threads.map(|v| v as i32).unwrap_or(-1)) } } #[doc(alias = "g_thread_pool_get_max_unused_threads")] #[doc(alias = "get_max_unused_threads")] pub fn max_unused_threads() -> Option { unsafe { let max_unused_threads = ffi::g_thread_pool_get_max_unused_threads(); if max_unused_threads == -1 { None } else { Some(max_unused_threads as u32) } } } #[doc(alias = "g_thread_pool_get_num_unused_threads")] #[doc(alias = "get_num_unused_threads")] pub fn num_unused_threads() -> u32 { unsafe { ffi::g_thread_pool_get_num_unused_threads() } } #[doc(alias = "g_thread_pool_stop_unused_threads")] pub fn stop_unused_threads() { unsafe { ffi::g_thread_pool_stop_unused_threads(); } } #[doc(alias = "g_thread_pool_set_max_idle_time")] pub fn set_max_idle_time(max_idle_time: u32) { unsafe { ffi::g_thread_pool_set_max_idle_time(max_idle_time) } } #[doc(alias = "g_thread_pool_get_max_idle_time")] #[doc(alias = "get_max_idle_time")] pub fn max_idle_time() -> u32 { unsafe { ffi::g_thread_pool_get_max_idle_time() } } } impl Drop for ThreadPool { #[inline] fn drop(&mut self) { unsafe { ffi::g_thread_pool_free(self.0.as_ptr(), ffi::GFALSE, ffi::GTRUE); } } } unsafe extern "C" fn spawn_func(func: ffi::gpointer, _data: ffi::gpointer) { let func: Box> = Box::from_raw(func as *mut _); func() } #[cfg(test)] mod tests { use super::*; #[test] fn test_push() { use std::sync::mpsc; let p = ThreadPool::exclusive(1).unwrap(); let (sender, receiver) = mpsc::channel(); let handle = p .push(move || { sender.send(true).unwrap(); 123 }) .unwrap(); assert_eq!(handle.join().unwrap(), 123); assert_eq!(receiver.recv(), Ok(true)); } #[test] fn test_push_future() { let c = crate::MainContext::new(); let p = ThreadPool::shared(None).unwrap(); let fut = p.push_future(|| true).unwrap(); let res = c.block_on(fut); assert!(res.unwrap()); } } glib-0.20.9/src/time_span.rs000064400000000000000000000052651046102023000137550ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::{ffi, translate::*}; // rustdoc-stripper-ignore-next /// A value representing an interval of time, in microseconds. #[doc(alias = "GTimeSpan")] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct TimeSpan(pub i64); impl FromGlib for TimeSpan { #[inline] unsafe fn from_glib(v: i64) -> TimeSpan { TimeSpan(v) } } impl IntoGlib for TimeSpan { type GlibType = i64; #[inline] fn into_glib(self) -> i64 { self.0 } } impl TimeSpan { // rustdoc-stripper-ignore-next /// Create a new timespan from microseconds. pub fn from_microseconds(v: i64) -> TimeSpan { TimeSpan(v) } // rustdoc-stripper-ignore-next /// Create a new timespan from milliseconds. pub fn from_milliseconds(v: i64) -> TimeSpan { TimeSpan(v * ffi::G_TIME_SPAN_MILLISECOND) } // rustdoc-stripper-ignore-next /// Create a new timespan from seconds. pub fn from_seconds(v: i64) -> TimeSpan { TimeSpan(v * ffi::G_TIME_SPAN_SECOND) } // rustdoc-stripper-ignore-next /// Create a new timespan from minutes. pub fn from_minutes(v: i64) -> TimeSpan { TimeSpan(v * ffi::G_TIME_SPAN_MINUTE) } // rustdoc-stripper-ignore-next /// Create a new timespan from hours. pub fn from_hours(v: i64) -> TimeSpan { TimeSpan(v * ffi::G_TIME_SPAN_HOUR) } // rustdoc-stripper-ignore-next /// Create a new timespan from days. pub fn from_days(v: i64) -> TimeSpan { TimeSpan(v * ffi::G_TIME_SPAN_DAY) } // rustdoc-stripper-ignore-next /// Return the full number of microseconds in this `TimeSpan`. pub fn as_microseconds(self) -> i64 { self.0 } // rustdoc-stripper-ignore-next /// Return the full number of milliseconds in this `TimeSpan`. pub fn as_milliseconds(self) -> i64 { self.0 / ffi::G_TIME_SPAN_MILLISECOND } // rustdoc-stripper-ignore-next /// Return the full number of seconds in this `TimeSpan`. pub fn as_seconds(self) -> i64 { self.0 / ffi::G_TIME_SPAN_SECOND } // rustdoc-stripper-ignore-next /// Return the full number of minutes in this `TimeSpan`. pub fn as_minutes(self) -> i64 { self.0 / ffi::G_TIME_SPAN_MINUTE } // rustdoc-stripper-ignore-next /// Return the full number of hours in this `TimeSpan`. pub fn as_hours(self) -> i64 { self.0 / ffi::G_TIME_SPAN_HOUR } // rustdoc-stripper-ignore-next /// Return the full number of days in this `TimeSpan`. pub fn as_days(self) -> i64 { self.0 / ffi::G_TIME_SPAN_DAY } } glib-0.20.9/src/time_zone.rs000064400000000000000000000010021046102023000137500ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::translate::*; use crate::{TimeType, TimeZone}; impl TimeZone { #[doc(alias = "g_time_zone_adjust_time")] pub fn adjust_time(&self, type_: TimeType, mut time: i64) -> (i32, i64) { unsafe { let res = crate::ffi::g_time_zone_adjust_time( self.to_glib_none().0, type_.into_glib(), &mut time, ); (res, time) } } } glib-0.20.9/src/translate.rs000064400000000000000000002714651046102023000140020ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! Translation between GLib/GLib-based FFI types and their Rust counterparts. //! //! This module allows library bindings authors to decouple type translation //! logic and use unified idioms at FFI boundaries. It also implements //! translation of GLib core data types. //! //! `FromGlib`, `from_glib` and `IntoGlib` translate simple types like `bool`. //! //! ```ignore //! pub fn set_accept_focus(&self, accept_focus: bool) { //! unsafe { gdk::ffi::gdk_window_set_accept_focus(self.pointer, accept_focus.into_glib()) } //! } //! //! pub fn get_accept_focus(&self) -> bool { //! unsafe { from_glib(gdk::ffi::gdk_window_get_accept_focus(self.pointer)) } //! } //! ``` //! //! Implementing [`OptionIntoGlib`] on a Rust type `T` allows specifying a sentinel to indicate //! a `None` value and auto-implementing [`FromGlib`] for `Option`, which would not be //! possible in dependent crates due to the [orphan rule](https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type). //! In the example below, [`IntoGlib`] is auto-implemented for `Option`. //! //! ``` //! # use glib::translate::*; //! struct SpecialU32(u32); //! impl IntoGlib for SpecialU32 { //! type GlibType = libc::c_uint; //! fn into_glib(self) -> libc::c_uint { //! self.0 as libc::c_uint //! } //! } //! impl OptionIntoGlib for SpecialU32 { //! const GLIB_NONE: Self::GlibType = 0xFFFFFF; //! } //! ``` //! //! In order to auto-implement [`FromGlib`] for `Option`, proceed as follows: //! //! ``` //! # use glib::translate::*; //! # struct SpecialU32(u32); //! # impl IntoGlib for SpecialU32 { //! # type GlibType = libc::c_uint; //! # fn into_glib(self) -> libc::c_uint { //! # self.0 as libc::c_uint //! # } //! # } //! # impl OptionIntoGlib for SpecialU32 { //! # const GLIB_NONE: Self::GlibType = 0xFFFFFF; //! # } //! impl TryFromGlib for SpecialU32 { //! type Error = GlibNoneError; //! unsafe fn try_from_glib(val: libc::c_uint) -> Result { //! if val == SpecialU32::GLIB_NONE { //! return Err(GlibNoneError); //! } //! Ok(SpecialU32(val as u32)) //! } //! } //! ``` //! //! The [`TryFromGlib`] trait can also be implemented when the Glib type range is larger than the //! target Rust type's range. In the example below, the Rust type `U32` can be built from a signed //! [`libc::c_long`], which means that the negative range is not valid. //! //! ``` //! # use std::convert::TryFrom; //! # use std::num::TryFromIntError; //! # use glib::translate::*; //! struct U32(u32); //! impl TryFromGlib for U32 { //! type Error = TryFromIntError; //! unsafe fn try_from_glib(val: libc::c_long) -> Result { //! Ok(U32(u32::try_from(val)?)) //! } //! } //! ``` //! //! Finally, you can define [`TryFromGlib`] with both `None` and `Invalid` alternatives by setting //! the associated `type Error = GlibNoneOrInvalidError` (where `I` is the `Error` type //! when the value is invalid), which results in auto-implementing [`FromGlib`] for //! `Result, I>`. //! //! `ToGlibPtr`, `FromGlibPtrNone`, `FromGlibPtrFull` and `FromGlibPtrBorrow` work on `gpointer`s //! and ensure correct ownership of values //! according to [Glib ownership transfer rules](https://gi.readthedocs.io/en/latest/annotations/giannotations.html). //! //! `FromGlibPtrNone` and `FromGlibPtrFull` //! must be called on values obtained from C, //! according to their `transfer` annotations. //! They acquire non-gobject types, //! as well as turning floating references to strong ones, //! which are the only ones properly handled by the Rust bindings. //! //! For more information about floating references, please refer to the "Floating references" section //! of [the gobject reference](https://docs.gtk.org/gobject/floating-refs.html). //! //! ```ignore //! fn get_title(&self) -> Option { //! unsafe { //! let title = gtk::ffi::gtk_window_get_title(self.pointer); //! from_glib_none(title) //! } //! } //! fn create_bool(value: gboolean) -> Variant { //! unsafe { //! let variant = ffi::g_variant_new_boolean(value); //! // g_variant_new_boolean has `transfer none` //! from_glib_none(variant) //! } //! } //! ``` //! //! Letting the foreign library borrow pointers from the Rust side often //! requires having a temporary variable of an intermediate type (e.g. `CString`). //! A `Stash` contains the temporary storage and a pointer into it that //! is valid for the lifetime of the `Stash`. As the lifetime of the `Stash` returned //! from `to_glib_none` is at least the enclosing statement, you can avoid explicitly //! binding the stash in most cases and just take the pointer out of it: //! //! ```ignore //! pub fn set_icon_name(&self, name: &str) { //! unsafe { //! gdk::ffi::gdk_window_set_icon_name(self.pointer, name.to_glib_none().0) //! } //! } //! ``` #[cfg(not(windows))] use std::os::unix::prelude::*; use std::{ borrow::Cow, char, cmp::Ordering, collections::HashMap, error::Error, ffi::{CStr, CString, OsStr, OsString}, fmt, marker::PhantomData, mem, path::{Path, PathBuf}, ptr, }; pub use crate::collections::{ptr_slice::IntoPtrSlice, strv::IntoStrV}; use crate::ffi; pub use crate::gstring::{IntoGStr, IntoOptionalGStr}; use libc::{c_char, size_t}; // rustdoc-stripper-ignore-next /// 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 } } // rustdoc-stripper-ignore-next /// Overrides pointer mutability. /// /// Use when the C API should be specifying a const pointer but doesn't. #[inline] pub fn mut_override(ptr: *const T) -> *mut T { ptr as *mut T } // rustdoc-stripper-ignore-next /// Overrides pointer constness. /// /// Use when the C API need const pointer, but function with `IsA` constraint, /// that usually don't have const pointer conversion. #[inline] pub fn const_override(ptr: *mut T) -> *const T { ptr as *const T } // rustdoc-stripper-ignore-next /// A trait for creating an uninitialized value. Handy for receiving outparams. pub trait Uninitialized { // Returns an uninitialized value. unsafe fn uninitialized() -> Self; } // rustdoc-stripper-ignore-next /// Returns an uninitialized value. #[inline] pub unsafe fn uninitialized() -> T { T::uninitialized() } // rustdoc-stripper-ignore-next /// Helper type that stores temporary values used for translation. /// /// `P` is the foreign type pointer and the first element of the tuple. /// /// `T` is the Rust type that is translated. /// /// The second element of the tuple is the temporary storage defined /// by the implementation of `ToGlibPtr

for T` /// /// Say you want to pass a `*mut GdkWindowAttr` to a foreign function. The `Stash` /// will own a `GdkWindowAttr` and a `CString` that `GdkWindowAttr::title` points into. /// /// ```ignore /// impl <'a> ToGlibPtr<'a, *mut ffi::GdkWindowAttr> for WindowAttr { /// type Storage = (Box, Stash<'a, *const c_char, Option>); /// /// fn to_glib_none(&'a self) -> Stash<*mut ffi::GdkWindowAttr, WindowAttr> { /// let title = self.title.to_glib_none(); /// /// let mut attrs = Box::new(ffi::GdkWindowAttr { /// title: title.0, /// // .... /// }); /// /// Stash(&mut *attrs, (attrs, title)) /// } /// } /// ``` pub struct Stash<'a, P: Copy, T: ?Sized + ToGlibPtr<'a, P>>( pub P, pub >::Storage, ); pub struct StashMut<'a, P: Copy, T: ?Sized>(pub P, pub >::Storage) where T: ToGlibPtrMut<'a, P>; // rustdoc-stripper-ignore-next /// Wrapper around values representing borrowed C memory. /// /// This is returned by `from_glib_borrow()` and ensures that the wrapped value /// is never dropped when going out of scope. /// /// Borrowed values must never be passed by value or mutable reference to safe Rust code and must /// not leave the C scope in which they are valid. #[derive(Debug)] pub struct Borrowed(mem::ManuallyDrop); impl Borrowed { // rustdoc-stripper-ignore-next /// Creates a new borrowed value. #[inline] pub fn new(val: T) -> Self { Self(mem::ManuallyDrop::new(val)) } // rustdoc-stripper-ignore-next /// Extracts the contained value. /// /// # Safety /// /// The returned value must never be dropped and instead has to be passed to `mem::forget()` or /// be directly wrapped in `mem::ManuallyDrop` or another `Borrowed` wrapper. #[inline] pub unsafe fn into_inner(self) -> T { mem::ManuallyDrop::into_inner(self.0) } } impl AsRef for Borrowed { #[inline] fn as_ref(&self) -> &T { &self.0 } } impl std::ops::Deref for Borrowed { type Target = T; #[inline] fn deref(&self) -> &T { &self.0 } } // rustdoc-stripper-ignore-next /// Unsafe variant of the `From` trait. pub trait UnsafeFrom { // rustdoc-stripper-ignore-next /// # Safety /// /// It is the responsibility of the caller to ensure *all* invariants of /// the `T` hold before this is called, and that after conversion /// to assume nothing other than the invariants of the output. Implementors /// of this must ensure that the invariants of the output type hold. unsafe fn unsafe_from(t: T) -> Self; } // rustdoc-stripper-ignore-next /// Translate a simple type. pub trait IntoGlib { type GlibType: Copy; fn into_glib(self) -> Self::GlibType; } impl IntoGlib for bool { type GlibType = ffi::gboolean; #[inline] fn into_glib(self) -> ffi::gboolean { if self { ffi::GTRUE } else { ffi::GFALSE } } } impl IntoGlib for char { type GlibType = u32; #[inline] fn into_glib(self) -> u32 { self as u32 } } unsafe impl TransparentType for char { type GlibType = u32; } impl IntoGlib for Option { type GlibType = u32; #[inline] fn into_glib(self) -> u32 { self.as_ref().map(|&c| c as u32).unwrap_or(0) } } impl IntoGlib for Ordering { type GlibType = i32; #[inline] fn into_glib(self) -> i32 { match self { Ordering::Less => -1, Ordering::Equal => 0, Ordering::Greater => 1, } } } impl IntoGlib for Result where G: Copy, O: IntoGlib + TryFromGlib, E: IntoGlib, { type GlibType = G; #[inline] fn into_glib(self) -> Self::GlibType { match self { Ok(ok) => ok.into_glib(), Err(err) => err.into_glib(), } } } // rustdoc-stripper-ignore-next /// A Rust type `T` for which `Option` translates to the same glib type as T. pub trait OptionIntoGlib: IntoGlib { const GLIB_NONE: Self::GlibType; } impl IntoGlib for Option { type GlibType = T::GlibType; #[inline] fn into_glib(self) -> Self::GlibType { match self { Some(t) => t.into_glib(), None => T::GLIB_NONE, } } } // rustdoc-stripper-ignore-next /// 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 GlibPtrDefault for &T { type GlibType = ::GlibType; } // rustdoc-stripper-ignore-next /// Translate to a pointer. pub trait ToGlibPtr<'a, P: Copy> { type Storage; // rustdoc-stripper-ignore-next /// 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>; // rustdoc-stripper-ignore-next /// 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!(); } // rustdoc-stripper-ignore-next /// Transfer: full. /// /// We transfer the ownership to the foreign library. fn to_glib_full(&self) -> P { unimplemented!(); } } // rustdoc-stripper-ignore-next /// Translate to a pointer with a mutable borrow. pub trait ToGlibPtrMut<'a, P: Copy> { type Storage; // rustdoc-stripper-ignore-next /// Transfer: none. /// /// The pointer in the `Stash` is only valid for the lifetime of the `Stash`. #[allow(clippy::wrong_self_convention)] fn to_glib_none_mut(&'a mut self) -> StashMut<'a, P, Self>; } 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() } } #[doc(hidden)] #[derive(Debug)] pub enum CowStash { Borrowed(B), Owned(O), } impl<'a, P: Ptr, T> ToGlibPtr<'a, P> for Cow<'a, T> where T: ToOwned + ?Sized + ToGlibPtr<'a, P>, T::Owned: ToGlibPtr<'a, P>, { type Storage = CowStash>::Storage>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, P, Self> { match self { Cow::Borrowed(v) => { let s = v.to_glib_none(); Stash(s.0, CowStash::Borrowed(s.1)) } Cow::Owned(v) => { let s = v.to_glib_none(); Stash(s.0, CowStash::Owned(s.1)) } } } #[inline] fn to_glib_full(&self) -> P { match self { Cow::Borrowed(v) => v.to_glib_full(), Cow::Owned(v) => v.to_glib_full(), } } } impl<'a> ToGlibPtr<'a, *const c_char> for str { type Storage = Cow<'static, [u8]>; fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> { static EMPTY_STRING: &[u8] = &[0]; let bytes = if self.is_empty() { Cow::Borrowed(EMPTY_STRING) } else { if cfg!(debug_assertions) { crate::GStr::check_interior_nuls(self).unwrap(); } let mut bytes = Vec::with_capacity(self.len() + 1); unsafe { ptr::copy_nonoverlapping(self.as_ptr(), bytes.as_mut_ptr(), self.len()); bytes.as_mut_ptr().add(self.len()).write(0); bytes.set_len(self.len() + 1); } Cow::Owned(bytes) }; Stash(bytes.as_ptr() as *const c_char, bytes) } #[inline] fn to_glib_full(&self) -> *const c_char { if cfg!(debug_assertions) { crate::GStr::check_interior_nuls(self).unwrap(); } unsafe { ffi::g_strndup(self.as_ptr() as *const c_char, self.len() as size_t) as *const c_char } } } impl<'a> ToGlibPtr<'a, *mut c_char> for str { type Storage = Cow<'static, [u8]>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> { let s = ToGlibPtr::<*const c_char>::to_glib_none(self); Stash(s.0 as *mut _, s.1) } #[inline] fn to_glib_full(&self) -> *mut c_char { ToGlibPtr::<*const c_char>::to_glib_full(self) as *mut _ } } impl<'a> ToGlibPtr<'a, *const c_char> for String { type Storage = Cow<'static, [u8]>; #[inline] fn to_glib_none(&self) -> Stash<'a, *const c_char, String> { let s = ToGlibPtr::to_glib_none(self.as_str()); Stash(s.0, s.1) } #[inline] fn to_glib_full(&self) -> *const c_char { ToGlibPtr::to_glib_full(self.as_str()) } } impl<'a> ToGlibPtr<'a, *mut c_char> for String { type Storage = Cow<'static, [u8]>; #[inline] fn to_glib_none(&self) -> Stash<'a, *mut c_char, String> { let s = ToGlibPtr::to_glib_none(self.as_str()); Stash(s.0, s.1) } #[inline] fn to_glib_full(&self) -> *mut c_char { ToGlibPtr::to_glib_full(self.as_str()) } } impl<'a> ToGlibPtr<'a, *const c_char> for CStr { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> { Stash(self.as_ptr(), PhantomData) } #[inline] fn to_glib_full(&self) -> *const c_char { unsafe { ffi::g_strndup( self.as_ptr() as *const c_char, self.to_bytes().len() as size_t, ) as *const c_char } } } impl<'a> ToGlibPtr<'a, *mut c_char> for CStr { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> { Stash(self.as_ptr() as *mut c_char, PhantomData) } #[inline] fn to_glib_full(&self) -> *mut c_char { unsafe { ffi::g_strndup( self.as_ptr() as *const c_char, self.to_bytes().len() as size_t, ) as *mut c_char } } } impl<'a> ToGlibPtr<'a, *const c_char> for CString { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const c_char, Self> { Stash(self.as_ptr(), PhantomData) } #[inline] fn to_glib_full(&self) -> *const c_char { unsafe { ffi::g_strndup( self.as_ptr() as *const c_char, self.as_bytes().len() as size_t, ) as *const c_char } } } impl<'a> ToGlibPtr<'a, *mut c_char> for CString { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut c_char, Self> { Stash(self.as_ptr() as *mut c_char, PhantomData) } #[inline] fn to_glib_full(&self) -> *mut c_char { unsafe { ffi::g_strndup( self.as_ptr() as *const c_char, self.as_bytes().len() as size_t, ) as *mut c_char } } } // rustdoc-stripper-ignore-next /// Translate to a pointer. pub trait IntoGlibPtr { // rustdoc-stripper-ignore-next /// Transfer: full. #[allow(clippy::wrong_self_convention)] unsafe fn into_glib_ptr(self) -> P; } impl> IntoGlibPtr

for Option { #[inline] unsafe fn into_glib_ptr(self) -> P { self.map_or(Ptr::from::<()>(ptr::null_mut()), |s| { IntoGlibPtr::into_glib_ptr(s) }) } } impl GlibPtrDefault for str { type GlibType = *mut c_char; } impl GlibPtrDefault for String { type GlibType = *mut c_char; } #[cfg(not(windows))] pub(crate) 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)] pub(crate) 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))] pub(crate) 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)] pub(crate) 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) } #[inline] fn to_glib_full(&self) -> *mut c_char { let tmp = path_to_c(self); unsafe { ffi::g_strdup(tmp.as_ptr()) } } } 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) } #[inline] fn to_glib_full(&self) -> *mut c_char { let tmp = path_to_c(self); unsafe { ffi::g_strdup(tmp.as_ptr()) } } } 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) } #[inline] fn to_glib_full(&self) -> *mut c_char { let tmp = os_str_to_c(self); unsafe { ffi::g_strdup(tmp.as_ptr()) } } } 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) } #[inline] fn to_glib_full(&self) -> *mut c_char { let tmp = os_str_to_c(self); unsafe { ffi::g_strdup(tmp.as_ptr()) } } } impl GlibPtrDefault for OsStr { type GlibType = *mut c_char; } impl GlibPtrDefault for OsString { type GlibType = *mut c_char; } pub trait ToGlibContainerFromSlice<'a, P> where Self: Sized, { type Storage; #[allow(clippy::wrong_self_convention)] fn to_glib_none_from_slice(t: &'a [Self]) -> (P, Self::Storage); #[allow(clippy::wrong_self_convention)] fn to_glib_container_from_slice(t: &'a [Self]) -> (P, Self::Storage); #[allow(clippy::wrong_self_convention)] fn to_glib_full_from_slice(t: &[Self]) -> P; } macro_rules! impl_to_glib_container_from_slice_fundamental { ($name:ty) => { impl<'a> ToGlibContainerFromSlice<'a, *mut $name> for $name { type Storage = std::marker::PhantomData<&'a [$name]>; #[inline] fn to_glib_none_from_slice(t: &'a [$name]) -> (*mut $name, Self::Storage) { (t.as_ptr() as *mut $name, std::marker::PhantomData) } #[inline] fn to_glib_container_from_slice(t: &'a [$name]) -> (*mut $name, Self::Storage) { ( ToGlibContainerFromSlice::to_glib_full_from_slice(t), std::marker::PhantomData, ) } #[inline] fn to_glib_full_from_slice(t: &[$name]) -> *mut $name { if t.len() == 0 { return ptr::null_mut(); } unsafe { let res = ffi::g_malloc(mem::size_of_val(t)) as *mut $name; ptr::copy_nonoverlapping(t.as_ptr(), res, t.len()); res } } } }; } impl_to_glib_container_from_slice_fundamental!(u8); impl_to_glib_container_from_slice_fundamental!(i8); impl_to_glib_container_from_slice_fundamental!(u16); impl_to_glib_container_from_slice_fundamental!(i16); impl_to_glib_container_from_slice_fundamental!(u32); impl_to_glib_container_from_slice_fundamental!(i32); impl_to_glib_container_from_slice_fundamental!(u64); impl_to_glib_container_from_slice_fundamental!(i64); impl_to_glib_container_from_slice_fundamental!(f32); impl_to_glib_container_from_slice_fundamental!(f64); macro_rules! impl_to_glib_container_from_slice_string { ($name:ty, $ffi_name:ty) => { impl<'a> ToGlibContainerFromSlice<'a, *mut $ffi_name> for $name { type Storage = (Vec>, Option>); fn to_glib_none_from_slice(t: &'a [$name]) -> (*mut $ffi_name, Self::Storage) { let v: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect(); let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect(); v_ptr.push(ptr::null_mut() as $ffi_name); (v_ptr.as_ptr() as *mut $ffi_name, (v, Some(v_ptr))) } fn to_glib_container_from_slice(t: &'a [$name]) -> (*mut $ffi_name, Self::Storage) { let v: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect(); let v_ptr = unsafe { let v_ptr = ffi::g_malloc(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); } ptr::write(v_ptr.add(t.len()), ptr::null_mut()); v_ptr }; (v_ptr, (v, None)) } fn to_glib_full_from_slice(t: &[$name]) -> *mut $ffi_name { unsafe { let v_ptr = ffi::g_malloc(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()); } ptr::write(v_ptr.add(t.len()), ptr::null_mut()); v_ptr } } } impl<'a> ToGlibContainerFromSlice<'a, *const $ffi_name> for $name { type Storage = (Vec>, Option>); fn to_glib_none_from_slice(t: &'a [$name]) -> (*const $ffi_name, Self::Storage) { let v: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect(); let mut v_ptr: Vec<_> = v.iter().map(|s| s.0).collect(); v_ptr.push(ptr::null_mut() as $ffi_name); (v_ptr.as_ptr() as *const $ffi_name, (v, Some(v_ptr))) } fn to_glib_container_from_slice(t: &'a [$name]) -> (*const $ffi_name, Self::Storage) { let v: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect(); let v_ptr = unsafe { let v_ptr = ffi::g_malloc(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); } ptr::write(v_ptr.add(t.len()), ptr::null_mut()); v_ptr as *const $ffi_name }; (v_ptr, (v, None)) } fn to_glib_full_from_slice(t: &[$name]) -> *const $ffi_name { unsafe { let v_ptr = ffi::g_malloc(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()); } ptr::write(v_ptr.add(t.len()), ptr::null_mut()); v_ptr as *const $ffi_name } } } }; } impl_to_glib_container_from_slice_string!(&'a str, *mut c_char); impl_to_glib_container_from_slice_string!(&'a str, *const c_char); impl_to_glib_container_from_slice_string!(String, *mut c_char); impl_to_glib_container_from_slice_string!(String, *const c_char); impl_to_glib_container_from_slice_string!(&'a Path, *mut c_char); impl_to_glib_container_from_slice_string!(&'a Path, *const c_char); impl_to_glib_container_from_slice_string!(PathBuf, *mut c_char); impl_to_glib_container_from_slice_string!(PathBuf, *const c_char); impl_to_glib_container_from_slice_string!(&'a OsStr, *mut c_char); impl_to_glib_container_from_slice_string!(&'a OsStr, *const c_char); impl_to_glib_container_from_slice_string!(OsString, *mut c_char); impl_to_glib_container_from_slice_string!(OsString, *const c_char); impl_to_glib_container_from_slice_string!(&'a CStr, *mut c_char); impl_to_glib_container_from_slice_string!(&'a CStr, *const c_char); impl_to_glib_container_from_slice_string!(CString, *mut c_char); impl_to_glib_container_from_slice_string!(CString, *const c_char); impl_to_glib_container_from_slice_string!(crate::GString, *mut c_char); impl_to_glib_container_from_slice_string!(crate::GString, *const c_char); impl<'a, T> ToGlibContainerFromSlice<'a, *mut ffi::GList> for T where T: GlibPtrDefault + ToGlibPtr<'a, ::GlibType>, { type Storage = ( Option, Vec::GlibType, T>>, ); #[inline] fn to_glib_none_from_slice(t: &'a [T]) -> (*mut ffi::GList, Self::Storage) { let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect(); let mut list: *mut ffi::GList = ptr::null_mut(); unsafe { for stash in &stash_vec { list = ffi::g_list_prepend(list, Ptr::to(stash.0)); } } let stash = (ptr::NonNull::new(list).map(List), stash_vec); (list, stash) } #[inline] fn to_glib_container_from_slice(t: &'a [T]) -> (*mut ffi::GList, Self::Storage) { let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect(); let mut list: *mut ffi::GList = ptr::null_mut(); unsafe { for stash in &stash_vec { list = ffi::g_list_prepend(list, Ptr::to(stash.0)); } } (list, (None, stash_vec)) } #[inline] fn to_glib_full_from_slice(t: &[T]) -> *mut ffi::GList { let mut list: *mut ffi::GList = ptr::null_mut(); unsafe { for ptr in t.iter().rev().map(ToGlibPtr::to_glib_full) { list = ffi::g_list_prepend(list, Ptr::to(ptr)); } } list } } impl<'a, T> ToGlibContainerFromSlice<'a, *const ffi::GList> for T where T: GlibPtrDefault + ToGlibPtr<'a, ::GlibType>, { type Storage = ( Option, Vec::GlibType, T>>, ); #[inline] fn to_glib_none_from_slice(t: &'a [T]) -> (*const ffi::GList, Self::Storage) { let (list, stash) = ToGlibContainerFromSlice::<*mut ffi::GList>::to_glib_none_from_slice(t); (list as *const ffi::GList, stash) } #[inline] fn to_glib_container_from_slice(_t: &'a [T]) -> (*const ffi::GList, Self::Storage) { unimplemented!() } #[inline] fn to_glib_full_from_slice(_t: &[T]) -> *const ffi::GList { unimplemented!() } } #[doc(alias = "GList")] pub struct List(ptr::NonNull); impl Drop for List { #[inline] fn drop(&mut self) { unsafe { ffi::g_list_free(self.0.as_ptr()) } } } impl<'a, T> ToGlibContainerFromSlice<'a, *mut ffi::GSList> for &'a T where T: GlibPtrDefault + ToGlibPtr<'a, ::GlibType>, { type Storage = ( Option, Vec::GlibType, &'a T>>, ); #[inline] fn to_glib_none_from_slice(t: &'a [&'a T]) -> (*mut ffi::GSList, Self::Storage) { let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect(); let mut list: *mut ffi::GSList = ptr::null_mut(); unsafe { for stash in &stash_vec { list = ffi::g_slist_prepend(list, Ptr::to(stash.0)); } } let stash = (ptr::NonNull::new(list).map(SList), stash_vec); (list, stash) } #[inline] fn to_glib_container_from_slice(t: &'a [&'a T]) -> (*mut ffi::GSList, Self::Storage) { let stash_vec: Vec<_> = t.iter().rev().map(ToGlibPtr::to_glib_none).collect(); let mut list: *mut ffi::GSList = ptr::null_mut(); unsafe { for stash in &stash_vec { list = ffi::g_slist_prepend(list, Ptr::to(stash.0)); } } (list, (None, stash_vec)) } #[inline] fn to_glib_full_from_slice(t: &[&'a T]) -> *mut ffi::GSList { let mut list: *mut ffi::GSList = ptr::null_mut(); unsafe { for ptr in t.iter().rev().map(ToGlibPtr::to_glib_full) { list = ffi::g_slist_prepend(list, Ptr::to(ptr)); } } list } } impl<'a, T> ToGlibContainerFromSlice<'a, *const ffi::GSList> for &'a T where T: GlibPtrDefault + ToGlibPtr<'a, ::GlibType>, { type Storage = ( Option, Vec::GlibType, &'a T>>, ); #[inline] fn to_glib_none_from_slice(t: &'a [&'a T]) -> (*const ffi::GSList, Self::Storage) { let (list, stash) = ToGlibContainerFromSlice::<*mut ffi::GSList>::to_glib_none_from_slice(t); (list as *const ffi::GSList, stash) } #[inline] fn to_glib_container_from_slice(_t: &'a [&'a T]) -> (*const ffi::GSList, Self::Storage) { unimplemented!() } #[inline] fn to_glib_full_from_slice(_t: &[&'a T]) -> *const ffi::GSList { unimplemented!() } } #[doc(alias = "GSList")] pub struct SList(ptr::NonNull); impl Drop for SList { #[inline] fn drop(&mut self) { unsafe { ffi::g_slist_free(self.0.as_ptr()) } } } impl<'a, P: Ptr, T: ToGlibContainerFromSlice<'a, P>> ToGlibPtr<'a, P> for [T] { type Storage = T::Storage; #[inline] fn to_glib_none(&'a self) -> Stash<'a, P, Self> { let result = ToGlibContainerFromSlice::to_glib_none_from_slice(self); Stash(result.0, result.1) } #[inline] fn to_glib_container(&'a self) -> Stash<'a, P, Self> { let result = ToGlibContainerFromSlice::to_glib_container_from_slice(self); Stash(result.0, result.1) } #[inline] fn to_glib_full(&self) -> P { ToGlibContainerFromSlice::to_glib_full_from_slice(self) } } #[allow(clippy::implicit_hasher)] impl<'a> ToGlibPtr<'a, *mut ffi::GHashTable> for HashMap { type Storage = HashTable; #[inline] fn to_glib_none(&self) -> Stash<'a, *mut ffi::GHashTable, Self> { let ptr = self.to_glib_full(); Stash(ptr, HashTable(unsafe { ptr::NonNull::new_unchecked(ptr) })) } #[inline] fn to_glib_full(&self) -> *mut ffi::GHashTable { unsafe { let ptr = ffi::g_hash_table_new_full( Some(ffi::g_str_hash), Some(ffi::g_str_equal), Some(ffi::g_free), Some(ffi::g_free), ); for (k, v) in self { let k: *mut c_char = k.to_glib_full(); let v: *mut c_char = v.to_glib_full(); ffi::g_hash_table_insert(ptr, k as *mut _, v as *mut _); } ptr } } } #[doc(alias = "GHashTable")] pub struct HashTable(ptr::NonNull); impl Drop for HashTable { #[inline] fn drop(&mut self) { unsafe { ffi::g_hash_table_unref(self.0.as_ptr()) } } } #[doc(alias = "GPtrArray")] pub struct PtrArray(ptr::NonNull); impl Drop for PtrArray { #[inline] fn drop(&mut self) { unsafe { ffi::g_ptr_array_unref(self.0.as_ptr()); } } } impl<'a, T> ToGlibContainerFromSlice<'a, *mut ffi::GPtrArray> for T where T: GlibPtrDefault + ToGlibPtr<'a, ::GlibType>, { type Storage = ( Option, Vec::GlibType, T>>, ); #[inline] fn to_glib_none_from_slice(t: &'a [T]) -> (*mut ffi::GPtrArray, Self::Storage) { let stash_vec: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect(); let arr = unsafe { ffi::g_ptr_array_sized_new(t.len() as _) }; unsafe { for stash in &stash_vec { ffi::g_ptr_array_add(arr, Ptr::to(stash.0)); } } ( arr, ( Some(PtrArray(unsafe { ptr::NonNull::new_unchecked(arr) })), stash_vec, ), ) } #[inline] fn to_glib_container_from_slice(t: &'a [T]) -> (*mut ffi::GPtrArray, Self::Storage) { let stash_vec: Vec<_> = t.iter().map(ToGlibPtr::to_glib_none).collect(); let arr = unsafe { ffi::g_ptr_array_sized_new(t.len() as _) }; unsafe { for stash in &stash_vec { ffi::g_ptr_array_add(arr, Ptr::to(stash.0)); } } (arr, (None, stash_vec)) } #[inline] fn to_glib_full_from_slice(t: &[T]) -> *mut ffi::GPtrArray { let arr = unsafe { ffi::g_ptr_array_sized_new(t.len() as _) }; unsafe { for ptr in t.iter().map(ToGlibPtr::to_glib_full) { ffi::g_ptr_array_add(arr, Ptr::to(ptr)); } } arr } } impl<'a, T> ToGlibContainerFromSlice<'a, *const ffi::GPtrArray> for T where T: GlibPtrDefault + ToGlibPtr<'a, ::GlibType>, { type Storage = ( Option, Vec::GlibType, T>>, ); #[inline] fn to_glib_none_from_slice(t: &'a [T]) -> (*const ffi::GPtrArray, Self::Storage) { let (arr, stash) = ToGlibContainerFromSlice::<*mut ffi::GPtrArray>::to_glib_none_from_slice(t); (arr as *const ffi::GPtrArray, stash) } #[inline] fn to_glib_container_from_slice(_t: &'a [T]) -> (*const ffi::GPtrArray, Self::Storage) { unimplemented!() } #[inline] fn to_glib_full_from_slice(_t: &[T]) -> *const ffi::GPtrArray { unimplemented!() } } // rustdoc-stripper-ignore-next /// Translate a simple type. pub trait FromGlib: Sized { unsafe fn from_glib(val: G) -> Self; } // rustdoc-stripper-ignore-next /// Translate a simple type. #[inline] pub unsafe fn from_glib>(val: G) -> T { FromGlib::from_glib(val) } impl FromGlib for bool { #[inline] unsafe fn from_glib(val: ffi::gboolean) -> Self { val != ffi::GFALSE } } impl FromGlib for Ordering { #[inline] unsafe fn from_glib(val: i32) -> Self { val.cmp(&0) } } // rustdoc-stripper-ignore-next /// Translate from a Glib type which can result in an undefined and/or invalid value. pub trait TryFromGlib: Sized { type Error; unsafe fn try_from_glib(val: G) -> Result; } // rustdoc-stripper-ignore-next /// Translate from a Glib type which can result in an undefined and/or invalid value. #[inline] pub unsafe fn try_from_glib>( val: G, ) -> Result>::Error> { TryFromGlib::try_from_glib(val) } // rustdoc-stripper-ignore-next /// Error type for [`TryFromGlib`] when the Glib value is None. #[derive(Debug, PartialEq, Eq)] pub struct GlibNoneError; impl fmt::Display for GlibNoneError { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "glib value is None") } } impl std::error::Error for GlibNoneError {} impl> FromGlib for Option { #[inline] unsafe fn from_glib(val: G) -> Self { T::try_from_glib(val).ok() } } // rustdoc-stripper-ignore-next /// Error type for [`TryFromGlib`] when the Glib value can be None or invalid. #[derive(Debug, Eq, PartialEq)] pub enum GlibNoneOrInvalidError { Invalid(I), None, } impl GlibNoneOrInvalidError { // rustdoc-stripper-ignore-next /// Builds the `None` variant. #[inline] pub fn none() -> Self { Self::None } // rustdoc-stripper-ignore-next /// Returns `true` if `self` is the `None` variant. #[inline] pub fn is_none(&self) -> bool { matches!(self, Self::None) } // rustdoc-stripper-ignore-next /// Returns `true` if `self` is the `Invalid` variant. #[inline] pub fn is_invalid(&self) -> bool { matches!(self, Self::Invalid(_)) } } impl From for GlibNoneOrInvalidError { #[inline] fn from(invalid: I) -> Self { Self::Invalid(invalid) } } impl fmt::Display for GlibNoneOrInvalidError { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Invalid(err) => { write!(fmt, "glib value is invalid: ")?; fmt::Display::fmt(err, fmt) } Self::None => write!(fmt, "glib value is None"), } } } impl Error for GlibNoneOrInvalidError {} impl>> FromGlib for Result, I> { #[inline] unsafe fn from_glib(val: G) -> Self { match T::try_from_glib(val) { Ok(value) => Ok(Some(value)), Err(GlibNoneOrInvalidError::None) => Ok(None), Err(GlibNoneOrInvalidError::Invalid(err)) => Err(err), } } } // rustdoc-stripper-ignore-next /// Translate from a pointer type which is annotated with `transfer none`. /// The resulting value is referenced at least once, by the bindings. /// /// This is suitable for floating references, which become strong references. /// It is also suitable for acquiring non-gobject values, like `gchar*`. /// /// /// # Safety /// /// The implementation of this trait should acquire a reference to the value /// in a way appropriate to the type, /// e.g. by increasing the reference count or copying. /// Values obtained using this trait must be properly released on `drop()` /// by the implementing type. /// /// For more information, refer to module level documentation. pub trait FromGlibPtrNone: Sized { // rustdoc-stripper-ignore-next /// # Safety /// /// See trait level [notes on safety](#safety_points) unsafe fn from_glib_none(ptr: P) -> Self; } // rustdoc-stripper-ignore-next /// Translate from a pointer type which is annotated with `transfer full`. /// This transfers the ownership of the value to the Rust side. /// /// Because ownership can only be transferred if something is already referenced, /// this is unsuitable for floating references. /// /// /// # Safety /// /// The implementation of this trait should not alter the reference count /// or make copies of the underlying value. /// Values obtained using this trait must be properly released on `drop()` /// by the implementing type. /// /// For more information, refer to module level documentation. pub trait FromGlibPtrFull: Sized { // rustdoc-stripper-ignore-next /// # Safety /// /// See trait level [notes on safety](#safety_points) unsafe fn from_glib_full(ptr: P) -> Self; } // rustdoc-stripper-ignore-next /// Translate from a pointer type by borrowing, without affecting the refcount. /// /// The purpose of this trait is to access values inside callbacks /// without changing their reference status. /// The obtained borrow must not be accessed outside of the scope of the callback, /// and called procedures must not store any references to the underlying data. /// Safe Rust code must never obtain a mutable Rust reference. /// /// /// # Safety /// /// The implementation of this trait as well as the returned type /// must satisfy the same constraints together. /// They must not take ownership of the underlying value, copy it, /// and should not change its reference count. /// If it does, it must properly release obtained references. /// /// The returned value, when dropped, /// must leave the underlying value in the same state /// as before from_glib_borrow was called: /// - it must not be dropped, /// - it must be the same type of reference, e.g. still floating. /// /// For more information, refer to module level documentation. pub trait FromGlibPtrBorrow: Sized { // rustdoc-stripper-ignore-next /// # Safety /// /// See trait level [notes on safety](#safety_points) unsafe fn from_glib_borrow(_ptr: P) -> Borrowed { unimplemented!(); } } // rustdoc-stripper-ignore-next /// Translate from a pointer type, transfer: none. /// /// See [`FromGlibPtrNone`](trait.FromGlibPtrNone.html). #[inline] pub unsafe fn from_glib_none>(ptr: P) -> T { FromGlibPtrNone::from_glib_none(ptr) } // rustdoc-stripper-ignore-next /// Translate from a pointer type, transfer: full (assume ownership). /// /// See [`FromGlibPtrFull`](trait.FromGlibPtrFull.html). #[inline] pub unsafe fn from_glib_full>(ptr: P) -> T { FromGlibPtrFull::from_glib_full(ptr) } // rustdoc-stripper-ignore-next /// Translate from a pointer type, borrowing the pointer. /// /// See [`FromGlibPtrBorrow`](trait.FromGlibPtrBorrow.html). #[inline] pub unsafe fn from_glib_borrow>(ptr: P) -> Borrowed { FromGlibPtrBorrow::from_glib_borrow(ptr) } impl> FromGlibPtrNone

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

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

for Option { #[inline] unsafe fn from_glib_full(ptr: P) -> Option { if ptr.is_null() { None } else { Some(from_glib_full(ptr)) } } } impl FromGlibPtrNone<*const c_char> for String { #[inline] unsafe fn from_glib_none(ptr: *const c_char) -> Self { debug_assert!(!ptr.is_null()); Self::from_utf8_lossy(CStr::from_ptr(ptr).to_bytes()).into_owned() } } // TODO: Deprecate this impl FromGlibPtrFull<*const c_char> for String { #[inline] unsafe fn from_glib_full(ptr: *const c_char) -> Self { let res = from_glib_none(ptr); ffi::g_free(ptr as *mut _); res } } // TODO: Deprecate this impl FromGlibPtrNone<*mut c_char> for String { #[inline] unsafe fn from_glib_none(ptr: *mut c_char) -> Self { debug_assert!(!ptr.is_null()); Self::from_utf8_lossy(CStr::from_ptr(ptr).to_bytes()).into_owned() } } // TODO: Deprecate this impl FromGlibPtrFull<*mut c_char> for String { #[inline] unsafe fn from_glib_full(ptr: *mut c_char) -> Self { let res = from_glib_none(ptr); ffi::g_free(ptr as *mut _); res } } #[cfg(not(windows))] pub(crate) unsafe fn c_to_path_buf(ptr: *const c_char) -> PathBuf { debug_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)] pub(crate) unsafe fn c_to_path_buf(ptr: *const c_char) -> PathBuf { debug_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))] pub(crate) unsafe fn c_to_os_string(ptr: *const c_char) -> OsString { debug_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)] pub(crate) unsafe fn c_to_os_string(ptr: *const c_char) -> OsString { debug_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 { debug_assert!(!ptr.is_null()); c_to_path_buf(ptr) } } impl FromGlibPtrFull<*const c_char> for PathBuf { #[inline] unsafe fn from_glib_full(ptr: *const c_char) -> Self { let res = from_glib_none(ptr); ffi::g_free(ptr as *mut _); res } } impl FromGlibPtrNone<*mut c_char> for PathBuf { #[inline] unsafe fn from_glib_none(ptr: *mut c_char) -> Self { debug_assert!(!ptr.is_null()); c_to_path_buf(ptr) } } impl FromGlibPtrFull<*mut c_char> for PathBuf { #[inline] unsafe fn from_glib_full(ptr: *mut c_char) -> Self { let res = from_glib_none(ptr); ffi::g_free(ptr as *mut _); res } } #[cfg(not(windows))] pub(crate) unsafe fn c_to_path_buf_num(ptr: *const c_char, num: usize) -> PathBuf { debug_assert!(!ptr.is_null()); let slice = std::slice::from_raw_parts(ptr as *const u8, num); OsString::from_vec(slice.to_vec()).into() } #[cfg(windows)] pub(crate) unsafe fn c_to_path_buf_num(ptr: *const c_char, num: usize) -> PathBuf { debug_assert!(!ptr.is_null()); let slice = std::slice::from_raw_parts(ptr as *const u8, num); String::from_utf8(slice.into()) .expect("Invalid, non-UTF8 path") .into() } #[doc(hidden)] impl FromGlibContainer<*const c_char, *const i8> for PathBuf { unsafe fn from_glib_none_num(ptr: *const i8, num: usize) -> Self { c_to_path_buf_num(ptr as *const _, num) } unsafe fn from_glib_container_num(ptr: *const i8, num: usize) -> Self { c_to_path_buf_num(ptr as *const _, num) } unsafe fn from_glib_full_num(ptr: *const i8, num: usize) -> Self { let res = c_to_path_buf_num(ptr as *const _, num); ffi::g_free(ptr as *mut _); res } } #[doc(hidden)] impl FromGlibContainer<*const c_char, *mut i8> for PathBuf { unsafe fn from_glib_none_num(ptr: *mut i8, num: usize) -> Self { FromGlibContainer::from_glib_none_num(ptr as *const i8, num) } unsafe fn from_glib_container_num(ptr: *mut i8, num: usize) -> Self { FromGlibContainer::from_glib_container_num(ptr as *const i8, num) } unsafe fn from_glib_full_num(ptr: *mut i8, num: usize) -> Self { FromGlibContainer::from_glib_full_num(ptr as *const i8, num) } } #[doc(hidden)] impl FromGlibContainer<*const c_char, *const u8> for PathBuf { unsafe fn from_glib_none_num(ptr: *const u8, num: usize) -> Self { FromGlibContainer::from_glib_none_num(ptr as *const i8, num) } unsafe fn from_glib_container_num(ptr: *const u8, num: usize) -> Self { FromGlibContainer::from_glib_container_num(ptr as *const i8, num) } unsafe fn from_glib_full_num(ptr: *const u8, num: usize) -> Self { FromGlibContainer::from_glib_full_num(ptr as *const i8, num) } } #[doc(hidden)] impl FromGlibContainer<*const c_char, *mut u8> for PathBuf { unsafe fn from_glib_none_num(ptr: *mut u8, num: usize) -> Self { FromGlibContainer::from_glib_none_num(ptr as *const i8, num) } unsafe fn from_glib_container_num(ptr: *mut u8, num: usize) -> Self { FromGlibContainer::from_glib_container_num(ptr as *const i8, num) } unsafe fn from_glib_full_num(ptr: *mut u8, num: usize) -> Self { FromGlibContainer::from_glib_full_num(ptr as *const i8, num) } } impl FromGlibPtrNone<*const c_char> for OsString { #[inline] unsafe fn from_glib_none(ptr: *const c_char) -> Self { debug_assert!(!ptr.is_null()); c_to_os_string(ptr) } } impl FromGlibPtrFull<*const c_char> for OsString { #[inline] unsafe fn from_glib_full(ptr: *const c_char) -> Self { let res = from_glib_none(ptr); ffi::g_free(ptr as *mut _); res } } impl FromGlibPtrNone<*mut c_char> for OsString { #[inline] unsafe fn from_glib_none(ptr: *mut c_char) -> Self { debug_assert!(!ptr.is_null()); c_to_os_string(ptr) } } impl FromGlibPtrFull<*mut c_char> for OsString { #[inline] unsafe fn from_glib_full(ptr: *mut c_char) -> Self { let res = from_glib_none(ptr); ffi::g_free(ptr as *mut _); res } } /// Translate from a container. pub trait FromGlibContainer: Sized { /// Transfer: none. /// /// `num` is the advised number of elements. unsafe fn from_glib_none_num(ptr: P, num: usize) -> Self; /// Transfer: container. /// /// `num` is the advised number of elements. unsafe fn from_glib_container_num(ptr: P, num: usize) -> Self; /// Transfer: full. /// /// `num` is the advised number of elements. unsafe fn from_glib_full_num(ptr: P, num: usize) -> Self; } /// Translate from a container of pointers. pub trait FromGlibPtrContainer: FromGlibContainer + Sized { /// Transfer: none. unsafe fn from_glib_none(ptr: PP) -> Self; /// Transfer: container. unsafe fn from_glib_container(ptr: PP) -> Self; /// Transfer: full. unsafe fn from_glib_full(ptr: PP) -> Self; } pub unsafe fn c_ptr_array_len(mut ptr: *const P) -> usize { let mut len = 0; if !ptr.is_null() { while !(*ptr).is_null() { len += 1; ptr = ptr.offset(1); } } len } pub trait FromGlibContainerAsVec where Self: Sized, { unsafe fn from_glib_none_num_as_vec(ptr: P, num: usize) -> Vec; unsafe fn from_glib_container_num_as_vec(ptr: P, num: usize) -> Vec; unsafe fn from_glib_full_num_as_vec(ptr: P, num: usize) -> Vec; } pub trait FromGlibPtrArrayContainerAsVec: FromGlibContainerAsVec where Self: Sized, { unsafe fn from_glib_none_as_vec(ptr: PP) -> Vec; unsafe fn from_glib_container_as_vec(ptr: PP) -> Vec; unsafe fn from_glib_full_as_vec(ptr: PP) -> Vec; } impl FromGlibContainerAsVec for bool { unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::gboolean, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::::with_capacity(num); let res_ptr = res.as_mut_ptr(); for i in 0..num { *res_ptr.add(i) = from_glib(ptr::read(ptr.add(i))); } res.set_len(num); res } unsafe fn from_glib_container_num_as_vec(_: *const ffi::gboolean, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } unsafe fn from_glib_full_num_as_vec(_: *const ffi::gboolean, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } } impl FromGlibContainerAsVec for bool { unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::gboolean, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num) } unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::gboolean, num: usize) -> Vec { let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut ffi::gboolean, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num) } } macro_rules! impl_from_glib_container_as_vec_fundamental { ($name:ty) => { unsafe impl TransparentType for $name { type GlibType = $name; } 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); let res_ptr = res.as_mut_ptr(); std::ptr::copy_nonoverlapping(ptr, res_ptr, num); res.set_len(num); res } unsafe fn from_glib_container_num_as_vec(_: *const $name, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } unsafe fn from_glib_full_num_as_vec(_: *const $name, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } } impl FromGlibContainerAsVec<$name, *mut $name> for $name { unsafe fn from_glib_none_num_as_vec(ptr: *mut $name, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num) } unsafe fn from_glib_container_num_as_vec(ptr: *mut $name, num: usize) -> Vec { let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut $name, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num) } } }; } impl_from_glib_container_as_vec_fundamental!(u8); impl_from_glib_container_as_vec_fundamental!(i8); impl_from_glib_container_as_vec_fundamental!(u16); impl_from_glib_container_as_vec_fundamental!(i16); impl_from_glib_container_as_vec_fundamental!(u32); impl_from_glib_container_as_vec_fundamental!(i32); impl_from_glib_container_as_vec_fundamental!(u64); impl_from_glib_container_as_vec_fundamental!(i64); impl_from_glib_container_as_vec_fundamental!(f32); impl_from_glib_container_as_vec_fundamental!(f64); macro_rules! impl_from_glib_container_as_vec_string { ($name:ty, $ffi_name:ty) => { impl FromGlibContainerAsVec<$ffi_name, *const $ffi_name> for $name { unsafe fn from_glib_none_num_as_vec(ptr: *const $ffi_name, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::::with_capacity(num); let res_ptr = res.as_mut_ptr(); for i in 0..num { std::ptr::write( res_ptr.add(i), from_glib_none(ptr::read(ptr.add(i)) as $ffi_name), ); } res.set_len(num); res } unsafe fn from_glib_container_num_as_vec(_: *const $ffi_name, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } unsafe fn from_glib_full_num_as_vec(_: *const $ffi_name, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } } impl FromGlibContainerAsVec<$ffi_name, *mut $ffi_name> for $name { unsafe fn from_glib_none_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num) } unsafe fn from_glib_container_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec { let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut $ffi_name, num: usize) -> Vec { if num == 0 || ptr.is_null() { ffi::g_free(ptr as *mut _); return Vec::new(); } let mut res = Vec::::with_capacity(num); let res_ptr = res.as_mut_ptr(); for i in 0..num { std::ptr::write( res_ptr.add(i), from_glib_full(ptr::read(ptr.add(i)) as $ffi_name), ); } res.set_len(num); ffi::g_free(ptr as *mut _); res } } impl FromGlibPtrArrayContainerAsVec<$ffi_name, *mut $ffi_name> for $name { unsafe fn from_glib_none_as_vec(ptr: *mut $ffi_name) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr)) } unsafe fn from_glib_container_as_vec(ptr: *mut $ffi_name) -> Vec { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, c_ptr_array_len(ptr)) } unsafe fn from_glib_full_as_vec(ptr: *mut $ffi_name) -> Vec { FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr)) } } impl FromGlibPtrArrayContainerAsVec<$ffi_name, *const $ffi_name> for $name { unsafe fn from_glib_none_as_vec(ptr: *const $ffi_name) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, c_ptr_array_len(ptr)) } unsafe fn from_glib_container_as_vec(ptr: *const $ffi_name) -> Vec { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, c_ptr_array_len(ptr)) } unsafe fn from_glib_full_as_vec(ptr: *const $ffi_name) -> Vec { FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, c_ptr_array_len(ptr)) } } }; } // TODO: Deprecate this impl_from_glib_container_as_vec_string!(String, *const c_char); impl_from_glib_container_as_vec_string!(String, *mut c_char); impl_from_glib_container_as_vec_string!(PathBuf, *const c_char); impl_from_glib_container_as_vec_string!(PathBuf, *mut c_char); impl_from_glib_container_as_vec_string!(OsString, *const c_char); impl_from_glib_container_as_vec_string!(OsString, *mut c_char); impl> FromGlibContainer for Vec { unsafe fn from_glib_none_num(ptr: PP, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num) } unsafe fn from_glib_container_num(ptr: PP, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num) } unsafe fn from_glib_full_num(ptr: PP, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, num) } } impl> FromGlibPtrContainer for Vec { unsafe fn from_glib_none(ptr: PP) -> Vec { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr) } unsafe fn from_glib_container(ptr: PP) -> Vec { FromGlibPtrArrayContainerAsVec::from_glib_container_as_vec(ptr) } unsafe fn from_glib_full(ptr: PP) -> Vec { FromGlibPtrArrayContainerAsVec::from_glib_full_as_vec(ptr) } } impl FromGlibContainerAsVec<::GlibType, *mut ffi::GSList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_num_as_vec(mut ptr: *mut ffi::GSList, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for _ in 0..num { if ptr.is_null() { break; } let item_ptr: ::GlibType = Ptr::from((*ptr).data); if !item_ptr.is_null() { res.push(from_glib_none(item_ptr)); } ptr = (*ptr).next; } res } unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GSList, num: usize) -> Vec { let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); ffi::g_slist_free(ptr); res } unsafe fn from_glib_full_num_as_vec(mut ptr: *mut ffi::GSList, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let orig_ptr = ptr; let mut res = Vec::with_capacity(num); for _ in 0..num { if ptr.is_null() { break; } let item_ptr: ::GlibType = Ptr::from((*ptr).data); if !item_ptr.is_null() { res.push(from_glib_full(item_ptr)); } ptr = (*ptr).next; } ffi::g_slist_free(orig_ptr); res } } impl FromGlibPtrArrayContainerAsVec<::GlibType, *mut ffi::GSList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_as_vec(mut ptr: *mut ffi::GSList) -> Vec { let mut res = Vec::new(); while !ptr.is_null() { let item_ptr: ::GlibType = Ptr::from((*ptr).data); if !item_ptr.is_null() { res.push(from_glib_none(item_ptr)); } ptr = (*ptr).next; } res } unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GSList) -> Vec { let res = FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr); ffi::g_slist_free(ptr); res } unsafe fn from_glib_full_as_vec(mut ptr: *mut ffi::GSList) -> Vec { let orig_ptr = ptr; let mut res = Vec::new(); while !ptr.is_null() { let item_ptr: ::GlibType = Ptr::from((*ptr).data); if !item_ptr.is_null() { res.push(from_glib_full(item_ptr)); } ptr = (*ptr).next; } ffi::g_slist_free(orig_ptr); res } } impl FromGlibContainerAsVec<::GlibType, *mut ffi::GList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_num_as_vec(mut ptr: *mut ffi::GList, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); for _ in 0..num { if ptr.is_null() { break; } let item_ptr: ::GlibType = Ptr::from((*ptr).data); if !item_ptr.is_null() { res.push(from_glib_none(item_ptr)); } ptr = (*ptr).next; } res } unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GList, num: usize) -> Vec { let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); ffi::g_list_free(ptr); res } unsafe fn from_glib_full_num_as_vec(mut ptr: *mut ffi::GList, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let orig_ptr = ptr; let mut res = Vec::with_capacity(num); for _ in 0..num { if ptr.is_null() { break; } let item_ptr: ::GlibType = Ptr::from((*ptr).data); if !item_ptr.is_null() { res.push(from_glib_full(item_ptr)); } ptr = (*ptr).next; } ffi::g_list_free(orig_ptr); res } } impl FromGlibPtrArrayContainerAsVec<::GlibType, *mut ffi::GList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_as_vec(mut ptr: *mut ffi::GList) -> Vec { let mut res = Vec::new(); while !ptr.is_null() { let item_ptr: ::GlibType = Ptr::from((*ptr).data); if !item_ptr.is_null() { res.push(from_glib_none(item_ptr)); } ptr = (*ptr).next; } res } unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GList) -> Vec { let res = FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr); ffi::g_list_free(ptr); res } unsafe fn from_glib_full_as_vec(mut ptr: *mut ffi::GList) -> Vec { let orig_ptr = ptr; let mut res = Vec::new(); while !ptr.is_null() { let item_ptr: ::GlibType = Ptr::from((*ptr).data); if !item_ptr.is_null() { res.push(from_glib_full(item_ptr)); } ptr = (*ptr).next; } ffi::g_list_free(orig_ptr); res } } impl FromGlibContainerAsVec<::GlibType, *const ffi::GList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GList, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(mut_override(ptr), num) } unsafe fn from_glib_container_num_as_vec(_: *const ffi::GList, _: usize) -> Vec { // Can't really free a *const unimplemented!() } unsafe fn from_glib_full_num_as_vec(_: *const ffi::GList, _: usize) -> Vec { // Can't really free a *const unimplemented!() } } impl FromGlibPtrArrayContainerAsVec<::GlibType, *const ffi::GList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_as_vec(ptr: *const ffi::GList) -> Vec { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(mut_override(ptr)) } unsafe fn from_glib_container_as_vec(_: *const ffi::GList) -> Vec { // Can't really free a *const unimplemented!() } unsafe fn from_glib_full_as_vec(_: *const ffi::GList) -> Vec { // Can't really free a *const unimplemented!() } } impl FromGlibContainerAsVec<::GlibType, *const ffi::GSList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GSList, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(mut_override(ptr), num) } unsafe fn from_glib_container_num_as_vec(_: *const ffi::GSList, _: usize) -> Vec { // Can't really free a *const unimplemented!() } unsafe fn from_glib_full_num_as_vec(_: *const ffi::GSList, _: usize) -> Vec { // Can't really free a *const unimplemented!() } } impl FromGlibPtrArrayContainerAsVec<::GlibType, *const ffi::GSList> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_as_vec(ptr: *const ffi::GSList) -> Vec { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(mut_override(ptr)) } unsafe fn from_glib_container_as_vec(_: *const ffi::GSList) -> Vec { // Can't really free a *const unimplemented!() } unsafe fn from_glib_full_as_vec(_: *const ffi::GSList) -> Vec { // Can't really free a *const unimplemented!() } } #[allow(clippy::implicit_hasher)] impl FromGlibContainer<*const c_char, *mut ffi::GHashTable> for HashMap { unsafe fn from_glib_none_num(ptr: *mut ffi::GHashTable, _: usize) -> Self { FromGlibPtrContainer::from_glib_none(ptr) } unsafe fn from_glib_container_num(ptr: *mut ffi::GHashTable, _: usize) -> Self { FromGlibPtrContainer::from_glib_full(ptr) } unsafe fn from_glib_full_num(ptr: *mut ffi::GHashTable, _: usize) -> Self { FromGlibPtrContainer::from_glib_full(ptr) } } #[allow(clippy::implicit_hasher)] impl FromGlibPtrContainer<*const c_char, *mut ffi::GHashTable> for HashMap { unsafe fn from_glib_none(ptr: *mut ffi::GHashTable) -> Self { unsafe extern "C" fn read_string_hash_table( key: ffi::gpointer, value: ffi::gpointer, hash_map: ffi::gpointer, ) { let key: String = from_glib_none(key as *const c_char); let value: String = from_glib_none(value as *const c_char); let hash_map: &mut HashMap = &mut *(hash_map as *mut HashMap); hash_map.insert(key, value); } let mut map = HashMap::with_capacity(ffi::g_hash_table_size(ptr) as usize); ffi::g_hash_table_foreach( ptr, Some(read_string_hash_table), &mut map as *mut HashMap as *mut _, ); map } unsafe fn from_glib_container(ptr: *mut ffi::GHashTable) -> Self { FromGlibPtrContainer::from_glib_full(ptr) } unsafe fn from_glib_full(ptr: *mut ffi::GHashTable) -> Self { let map = FromGlibPtrContainer::from_glib_none(ptr); ffi::g_hash_table_unref(ptr); map } } impl FromGlibContainerAsVec<::GlibType, *mut ffi::GPtrArray> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::GPtrArray, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let pdata = (*ptr).pdata; debug_assert!((*ptr).len as usize >= num); let mut res = Vec::with_capacity(num); for i in 0..num { let item_ptr: ::GlibType = Ptr::from(ptr::read(pdata.add(i))); if !item_ptr.is_null() { res.push(from_glib_none(item_ptr)); } } res } unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GPtrArray, num: usize) -> Vec { let res = FromGlibContainer::from_glib_none_num(ptr, num); if !ptr.is_null() { ffi::g_ptr_array_unref(ptr); } res } unsafe fn from_glib_full_num_as_vec(ptr: *mut ffi::GPtrArray, num: usize) -> Vec { if ptr.is_null() { return Vec::new(); } if num == 0 { ffi::g_ptr_array_unref(ptr); return Vec::new(); } let pdata = (*ptr).pdata; debug_assert!((*ptr).len as usize >= num); let mut res = Vec::with_capacity(num); for i in 0..num { let item_ptr: ::GlibType = Ptr::from(ptr::read(pdata.add(i))); if !item_ptr.is_null() { res.push(from_glib_none(item_ptr)); } } ffi::g_ptr_array_unref(ptr); res } } impl FromGlibPtrArrayContainerAsVec<::GlibType, *mut ffi::GPtrArray> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_as_vec(ptr: *mut ffi::GPtrArray) -> Vec { let num = (*ptr).len as usize; FromGlibContainer::from_glib_none_num(ptr, num) } unsafe fn from_glib_container_as_vec(ptr: *mut ffi::GPtrArray) -> Vec { let num = (*ptr).len as usize; FromGlibContainer::from_glib_container_num(ptr, num) } unsafe fn from_glib_full_as_vec(ptr: *mut ffi::GPtrArray) -> Vec { let num = (*ptr).len as usize; FromGlibContainer::from_glib_full_num(ptr, num) } } impl FromGlibContainerAsVec<::GlibType, *const ffi::GPtrArray> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GPtrArray, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(mut_override(ptr), num) } unsafe fn from_glib_container_num_as_vec(_: *const ffi::GPtrArray, _: usize) -> Vec { // Can't really free a *const unimplemented!() } unsafe fn from_glib_full_num_as_vec(_: *const ffi::GPtrArray, _: usize) -> Vec { // Can't really free a *const unimplemented!() } } impl FromGlibPtrArrayContainerAsVec<::GlibType, *const ffi::GPtrArray> for T where T: GlibPtrDefault + FromGlibPtrNone<::GlibType> + FromGlibPtrFull<::GlibType>, { unsafe fn from_glib_none_as_vec(ptr: *const ffi::GPtrArray) -> Vec { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(mut_override(ptr)) } unsafe fn from_glib_container_as_vec(_: *const ffi::GPtrArray) -> Vec { // Can't really free a *const unimplemented!() } unsafe fn from_glib_full_as_vec(_: *const ffi::GPtrArray) -> Vec { // Can't really free a *const unimplemented!() } } /// Trait for types that have the same memory representation as a pointer to their FFI type. /// /// Values of types implementing this trait can be transmuted to pointers of the FFI type, /// references to pointers of pointers to the FFI type. pub unsafe trait TransparentPtrType: Clone + Sized + GlibPtrDefault {} /// Trait for types that have the same memory representation as their FFI type. /// /// Values of types implementing this trait can be transmuted directly to the FFI type, references /// to pointers to the FFI type. pub unsafe trait TransparentType: Clone + Sized { type GlibType; } unsafe impl TransparentType for T { type GlibType = ::GlibType; } #[cfg(test)] mod tests { use std::{collections::HashMap, fs}; use tempfile::tempdir; use super::*; use crate::{FileTest, GString}; #[test] fn boolean() { assert_eq!(true.into_glib(), ffi::GTRUE); assert_eq!(false.into_glib(), ffi::GFALSE); assert!(unsafe { bool::from_glib(ffi::GTRUE) }); assert!(!unsafe { bool::from_glib(ffi::GFALSE) }); assert!(unsafe { bool::from_glib(42) }); } #[test] fn ordering() { assert_eq!(Ordering::Less.into_glib(), -1); assert_eq!(Ordering::Equal.into_glib(), 0); assert_eq!(Ordering::Greater.into_glib(), 1); assert_eq!(Ordering::Less, unsafe { Ordering::from_glib(-42) }); assert_eq!(Ordering::Less, unsafe { Ordering::from_glib(-1) }); assert_eq!(Ordering::Equal, unsafe { Ordering::from_glib(0) }); assert_eq!(Ordering::Greater, unsafe { Ordering::from_glib(1) }); assert_eq!(Ordering::Greater, unsafe { Ordering::from_glib(42) }); } #[test] fn string() { let s = "ABC"; let owned = "ABC".to_string(); let cstring = CString::new("ABC").unwrap(); let stash = s.to_glib_none(); assert_eq!(unsafe { CStr::from_ptr(stash.0) }, cstring.as_c_str()); let stash = owned.to_glib_none(); assert_eq!(unsafe { CStr::from_ptr(stash.0) }, cstring.as_c_str()); let ptr: *mut c_char = s.to_glib_full(); assert_eq!(unsafe { CStr::from_ptr(ptr) }, cstring.as_c_str()); unsafe { ffi::g_free(ptr as *mut _); } let ptr: *mut c_char = owned.to_glib_full(); assert_eq!(unsafe { CStr::from_ptr(ptr) }, cstring.as_c_str()); assert_eq!(s, unsafe { String::from_glib_none(ptr) }); assert_eq!(owned, unsafe { String::from_glib_full(ptr) }); } #[test] fn string_hash_map() { let mut map = HashMap::new(); map.insert("A".into(), "1".into()); map.insert("B".into(), "2".into()); map.insert("C".into(), "3".into()); let ptr: *mut ffi::GHashTable = map.to_glib_full(); let map = unsafe { HashMap::from_glib_full(ptr) }; assert_eq!(map.get("A"), Some(&"1".into())); assert_eq!(map.get("B"), Some(&"2".into())); assert_eq!(map.get("C"), Some(&"3".into())); } #[test] fn string_array() { let v = vec!["A".to_string(), "B".to_string(), "C".to_string()]; let stash = v.to_glib_none(); let ptr: *mut *mut c_char = stash.0; let ptr_copy = unsafe { ffi::g_strdupv(ptr) }; let actual: Vec = unsafe { FromGlibPtrContainer::from_glib_full(ptr_copy) }; assert_eq!(v, actual); } #[test] fn gstring_array() { let v = vec!["A".to_string(), "B".to_string(), "C".to_string()]; let stash = v.to_glib_none(); let ptr: *mut *mut c_char = stash.0; let ptr_copy = unsafe { ffi::g_strdupv(ptr) }; let actual: Vec = unsafe { FromGlibPtrContainer::from_glib_full(ptr_copy) }; assert_eq!(v, actual); } #[test] fn ptr_array() { let strings = &["A", "B", "C"]; let (ptr, _stash) = ToGlibContainerFromSlice::<*mut ffi::GPtrArray>::to_glib_none_from_slice(strings); let v: Vec = unsafe { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr) }; assert_eq!(&v, strings); } #[test] #[cfg(not(target_os = "macos"))] fn test_paths() { let tmp_dir = tempdir().unwrap(); // Test if passing paths to GLib and getting them back // gives us useful results let dir_1 = tmp_dir.path().join("abcd"); fs::create_dir(&dir_1).unwrap(); assert_eq!(crate::path_get_basename(&dir_1), Path::new("abcd")); assert_eq!( crate::path_get_basename(dir_1.canonicalize().unwrap()), Path::new("abcd") ); // This currently fails on Windows because C:\\Users\\runneradmin // gets shortened to C:\\Users\\RUNNER~1 #[cfg(not(windows))] assert_eq!( crate::path_get_dirname(dir_1.canonicalize().unwrap()), tmp_dir.path() ); assert!(crate::file_test( &dir_1, FileTest::EXISTS | FileTest::IS_DIR )); assert!(crate::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!(crate::path_get_basename(&dir_2), Path::new("øäöü")); assert_eq!( crate::path_get_basename(dir_2.canonicalize().unwrap()), Path::new("øäöü") ); // This currently fails on Windows because C:\\Users\\runneradmin // gets shortened to C:\\Users\\RUNNER~1 #[cfg(not(windows))] assert_eq!( crate::path_get_dirname(dir_2.canonicalize().unwrap()), tmp_dir.path() ); assert!(crate::file_test( &dir_2, FileTest::EXISTS | FileTest::IS_DIR )); assert!(crate::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!(crate::path_get_basename(&dir_1), Path::new("abcd")); assert_eq!( crate::path_get_basename(dir_1.canonicalize().unwrap()), Path::new("abcd") ); assert_eq!( crate::path_get_dirname(dir_1.canonicalize().unwrap()), tmp_dir ); assert!(crate::file_test( &dir_1, FileTest::EXISTS | FileTest::IS_DIR )); assert!(crate::file_test( &dir_1.canonicalize().unwrap(), FileTest::EXISTS | FileTest::IS_DIR )); } #[test] fn none_value() { const CLONG_NONE: libc::c_long = -1; #[derive(Debug, PartialEq, Eq)] struct SpecialU32(u32); impl IntoGlib for SpecialU32 { type GlibType = libc::c_uint; fn into_glib(self) -> libc::c_uint { self.0 as libc::c_uint } } impl OptionIntoGlib for SpecialU32 { const GLIB_NONE: Self::GlibType = CLONG_NONE as libc::c_uint; } assert_eq!(SpecialU32(0).into_glib(), 0); assert_eq!(SpecialU32(42).into_glib(), 42); assert_eq!(Some(SpecialU32(0)).into_glib(), 0); assert_eq!(Some(SpecialU32(42)).into_glib(), 42); assert_eq!( Option::None::.into_glib(), SpecialU32::GLIB_NONE ); impl TryFromGlib for SpecialU32 { type Error = GlibNoneError; #[allow(clippy::unnecessary_cast)] unsafe fn try_from_glib(val: libc::c_uint) -> Result { if val == SpecialU32::GLIB_NONE { return Err(GlibNoneError); } Ok(SpecialU32(val as u32)) } } assert_eq!(unsafe { SpecialU32::try_from_glib(0) }, Ok(SpecialU32(0))); assert_eq!(unsafe { SpecialU32::try_from_glib(42) }, Ok(SpecialU32(42))); assert_eq!( unsafe { SpecialU32::try_from_glib(SpecialU32::GLIB_NONE) }, Err(GlibNoneError) ); assert_eq!( unsafe { Option::::from_glib(0) }, Some(SpecialU32(0)) ); assert_eq!( unsafe { Option::::from_glib(42) }, Some(SpecialU32(42)) ); assert!(unsafe { Option::::from_glib(SpecialU32::GLIB_NONE) }.is_none()); } #[test] fn invalid_value() { use std::num::TryFromIntError; #[derive(Debug, PartialEq, Eq)] struct U32(u32); impl TryFromGlib for U32 { type Error = TryFromIntError; unsafe fn try_from_glib(val: libc::c_long) -> Result { Ok(U32(u32::try_from(val)?)) } } assert_eq!(unsafe { U32::try_from_glib(0) }, Ok(U32(0))); assert_eq!(unsafe { U32::try_from_glib(42) }, Ok(U32(42))); assert!(unsafe { U32::try_from_glib(-1) }.is_err()); assert!(unsafe { U32::try_from_glib(-42) }.is_err()); } #[test] fn none_or_invalid_value() { use std::num::TryFromIntError; #[derive(Debug, PartialEq, Eq)] struct SpecialU32(u32); impl IntoGlib for SpecialU32 { type GlibType = libc::c_long; fn into_glib(self) -> libc::c_long { self.0 as libc::c_long } } impl OptionIntoGlib for SpecialU32 { const GLIB_NONE: Self::GlibType = -1; } assert_eq!(SpecialU32(0).into_glib(), 0); assert_eq!(SpecialU32(42).into_glib(), 42); assert_eq!(Some(SpecialU32(42)).into_glib(), 42); assert_eq!( Option::None::.into_glib(), SpecialU32::GLIB_NONE ); impl TryFromGlib for SpecialU32 { type Error = GlibNoneOrInvalidError; unsafe fn try_from_glib( val: libc::c_long, ) -> Result> { if val == SpecialU32::GLIB_NONE { return Err(GlibNoneOrInvalidError::None); } Ok(SpecialU32(u32::try_from(val)?)) } } assert_eq!(unsafe { SpecialU32::try_from_glib(0) }, Ok(SpecialU32(0))); assert_eq!(unsafe { SpecialU32::try_from_glib(42) }, Ok(SpecialU32(42))); assert!(unsafe { SpecialU32::try_from_glib(SpecialU32::GLIB_NONE) } .unwrap_err() .is_none()); assert!(unsafe { SpecialU32::try_from_glib(-42) } .unwrap_err() .is_invalid()); assert_eq!( unsafe { Result::, _>::from_glib(0) }, Ok(Some(SpecialU32(0))) ); assert_eq!( unsafe { Result::, _>::from_glib(42) }, Ok(Some(SpecialU32(42))) ); assert_eq!( unsafe { Result::, _>::from_glib(SpecialU32::GLIB_NONE) }, Ok(None) ); assert!(unsafe { Result::, _>::from_glib(-42) }.is_err()); } } glib-0.20.9/src/types.rs000064400000000000000000000463311046102023000131410ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! Runtime type information. use std::{ fmt, marker::PhantomData, mem, num::{NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU32, NonZeroU64, NonZeroU8}, path::{Path, PathBuf}, ptr, }; use crate::{ffi, gobject_ffi, prelude::*, translate::*, Slice, TypeFlags, TypePlugin}; // rustdoc-stripper-ignore-next /// A GLib or GLib-based library type #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GType")] #[repr(transparent)] pub struct Type(ffi::GType); unsafe impl TransparentType for Type { type GlibType = ffi::GType; } impl Type { // rustdoc-stripper-ignore-next /// An invalid `Type` used as error return value in some functions #[doc(alias = "G_TYPE_INVALID")] pub const INVALID: Self = Self(gobject_ffi::G_TYPE_INVALID); // rustdoc-stripper-ignore-next /// The fundamental type corresponding to the unit type `()` #[doc(alias = "G_TYPE_NONE")] pub const UNIT: Self = Self(gobject_ffi::G_TYPE_NONE); // rustdoc-stripper-ignore-next /// The fundamental type corresponding to `i8` #[doc(alias = "G_TYPE_CHAR")] pub const I8: Self = Self(gobject_ffi::G_TYPE_CHAR); // rustdoc-stripper-ignore-next /// The fundamental type corresponding to `u8` #[doc(alias = "G_TYPE_UCHAR")] pub const U8: Self = Self(gobject_ffi::G_TYPE_UCHAR); // rustdoc-stripper-ignore-next /// The fundamental type corresponding to `bool` #[doc(alias = "G_TYPE_BOOLEAN")] pub const BOOL: Self = Self(gobject_ffi::G_TYPE_BOOLEAN); // rustdoc-stripper-ignore-next /// The fundamental type corresponding to `i32` #[doc(alias = "G_TYPE_INT")] pub const I32: Self = Self(gobject_ffi::G_TYPE_INT); // rustdoc-stripper-ignore-next /// The fundamental type corresponding to `u32` #[doc(alias = "G_TYPE_UINT")] pub const U32: Self = Self(gobject_ffi::G_TYPE_UINT); // rustdoc-stripper-ignore-next /// The fundamental type corresponding to C `long` #[doc(alias = "G_TYPE_LONG")] pub const I_LONG: Self = Self(gobject_ffi::G_TYPE_LONG); // rustdoc-stripper-ignore-next /// The fundamental type corresponding to C `unsigned long` #[doc(alias = "G_TYPE_ULONG")] pub const U_LONG: Self = Self(gobject_ffi::G_TYPE_ULONG); // rustdoc-stripper-ignore-next /// The fundamental type corresponding to `i64` #[doc(alias = "G_TYPE_INT64")] pub const I64: Self = Self(gobject_ffi::G_TYPE_INT64); // rustdoc-stripper-ignore-next /// The fundamental type corresponding to `u64` #[doc(alias = "G_TYPE_UINT64")] pub const U64: Self = Self(gobject_ffi::G_TYPE_UINT64); // rustdoc-stripper-ignore-next /// The fundamental type corresponding to `f32` #[doc(alias = "G_TYPE_FLOAT")] pub const F32: Self = Self(gobject_ffi::G_TYPE_FLOAT); // rustdoc-stripper-ignore-next /// The fundamental type corresponding to `f64` #[doc(alias = "G_TYPE_DOUBLE")] pub const F64: Self = Self(gobject_ffi::G_TYPE_DOUBLE); // rustdoc-stripper-ignore-next /// The fundamental type corresponding to `String` #[doc(alias = "G_TYPE_STRING")] pub const STRING: Self = Self(gobject_ffi::G_TYPE_STRING); // rustdoc-stripper-ignore-next /// The fundamental type corresponding to a pointer #[doc(alias = "G_TYPE_POINTER")] pub const POINTER: Self = Self(gobject_ffi::G_TYPE_POINTER); // rustdoc-stripper-ignore-next /// The fundamental type of GVariant #[doc(alias = "G_TYPE_VARIANT")] pub const VARIANT: Self = Self(gobject_ffi::G_TYPE_VARIANT); // rustdoc-stripper-ignore-next /// The fundamental type from which all interfaces are derived #[doc(alias = "G_TYPE_INTERFACE")] pub const INTERFACE: Self = Self(gobject_ffi::G_TYPE_INTERFACE); // rustdoc-stripper-ignore-next /// The fundamental type from which all enumeration types are derived #[doc(alias = "G_TYPE_ENUM")] pub const ENUM: Self = Self(gobject_ffi::G_TYPE_ENUM); // rustdoc-stripper-ignore-next /// The fundamental type from which all flags types are derived #[doc(alias = "G_TYPE_FLAGS")] pub const FLAGS: Self = Self(gobject_ffi::G_TYPE_FLAGS); // rustdoc-stripper-ignore-next /// The fundamental type from which all boxed types are derived #[doc(alias = "G_TYPE_BOXED")] pub const BOXED: Self = Self(gobject_ffi::G_TYPE_BOXED); // rustdoc-stripper-ignore-next /// The fundamental type from which all `GParamSpec` types are derived #[doc(alias = "G_TYPE_PARAM")] pub const PARAM_SPEC: Self = Self(gobject_ffi::G_TYPE_PARAM); // rustdoc-stripper-ignore-next /// The fundamental type from which all objects are derived #[doc(alias = "G_TYPE_OBJECT")] pub const OBJECT: Self = Self(gobject_ffi::G_TYPE_OBJECT); #[doc(alias = "g_type_name")] pub fn name<'a>(self) -> &'a str { match self.into_glib() { gobject_ffi::G_TYPE_INVALID => "", x => unsafe { let ptr = gobject_ffi::g_type_name(x); std::ffi::CStr::from_ptr(ptr).to_str().unwrap() }, } } #[doc(alias = "g_type_qname")] pub fn qname(self) -> crate::Quark { match self.into_glib() { gobject_ffi::G_TYPE_INVALID => crate::Quark::from_str(""), x => unsafe { from_glib(gobject_ffi::g_type_qname(x)) }, } } #[doc(alias = "g_type_is_a")] #[inline] pub fn is_a(self, other: Self) -> bool { unsafe { from_glib(gobject_ffi::g_type_is_a( self.into_glib(), other.into_glib(), )) } } #[doc(alias = "g_type_parent")] pub fn parent(self) -> Option { unsafe { let parent: Self = from_glib(gobject_ffi::g_type_parent(self.into_glib())); Some(parent).filter(|t| t.is_valid()) } } #[doc(alias = "g_type_children")] pub fn children(self) -> Slice { unsafe { let mut n_children = 0u32; let children = gobject_ffi::g_type_children(self.into_glib(), &mut n_children); Slice::from_glib_full_num(children, n_children as usize) } } #[doc(alias = "g_type_interfaces")] pub fn interfaces(self) -> Slice { unsafe { let mut n_interfaces = 0u32; let interfaces = gobject_ffi::g_type_interfaces(self.into_glib(), &mut n_interfaces); Slice::from_glib_full_num(interfaces, n_interfaces as usize) } } #[doc(alias = "g_type_interface_prerequisites")] pub fn interface_prerequisites(self) -> Slice { unsafe { match self { t if !t.is_a(Self::INTERFACE) => Slice::from_glib_full_num(ptr::null_mut(), 0), _ => { let mut n_prereqs = 0u32; let prereqs = gobject_ffi::g_type_interface_prerequisites( self.into_glib(), &mut n_prereqs, ); Slice::from_glib_full_num(prereqs, n_prereqs as usize) } } } } #[doc(alias = "g_type_from_name")] pub fn from_name(name: impl IntoGStr) -> Option { unsafe { let type_ = name.run_with_gstr(|name| { Self::from_glib(gobject_ffi::g_type_from_name(name.as_ptr())) }); Some(type_).filter(|t| t.is_valid()) } } #[doc(alias = "g_type_get_plugin")] pub fn plugin(self) -> Option { unsafe { let plugin_ptr = gobject_ffi::g_type_get_plugin(self.into_glib()); if plugin_ptr.is_null() { None } else { Some(TypePlugin::from_glib_none(plugin_ptr)) } } } #[doc(alias = "g_type_register_dynamic")] pub fn register_dynamic( parent_type: Self, name: impl IntoGStr, plugin: &TypePlugin, flags: TypeFlags, ) -> Self { unsafe { name.run_with_gstr(|name| { Self::from_glib(gobject_ffi::g_type_register_dynamic( parent_type.into_glib(), name.as_ptr(), plugin.as_ptr(), flags.into_glib(), )) }) } } #[doc(alias = "g_type_add_interface_dynamic")] pub fn add_interface_dynamic(self, interface_type: Self, plugin: &TypePlugin) { unsafe { gobject_ffi::g_type_add_interface_dynamic( self.into_glib(), interface_type.into_glib(), plugin.as_ptr(), ); } } // rustdoc-stripper-ignore-next /// Checks that the type is not [`INVALID`](Self::INVALID) #[inline] pub fn is_valid(self) -> bool { self != Self::INVALID } } impl fmt::Debug for Type { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.name()) } } impl fmt::Display for Type { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.name()) } } // rustdoc-stripper-ignore-next /// Types that are supported by GLib dynamic typing. pub trait StaticType { // rustdoc-stripper-ignore-next /// Returns the type identifier of `Self`. fn static_type() -> Type; } impl StaticType for Type { #[doc(alias = "g_gtype_get_type")] #[inline] fn static_type() -> Type { unsafe { from_glib(gobject_ffi::g_gtype_get_type()) } } } pub trait StaticTypeExt { // rustdoc-stripper-ignore-next /// Ensures that the type has been registered with the type system. #[doc(alias = "g_type_ensure")] fn ensure_type(); } impl StaticTypeExt for T { #[inline] fn ensure_type() { T::static_type(); } } #[doc(hidden)] impl crate::value::ValueType for Type { type Type = Type; } #[doc(hidden)] unsafe impl<'a> crate::value::FromValue<'a> for Type { type Checker = crate::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a crate::Value) -> Self { from_glib(gobject_ffi::g_value_get_gtype(value.to_glib_none().0)) } } #[doc(hidden)] impl crate::value::ToValue for Type { #[inline] fn to_value(&self) -> crate::Value { unsafe { let mut value = crate::Value::from_type_unchecked(Type::static_type()); gobject_ffi::g_value_set_gtype(value.to_glib_none_mut().0, self.into_glib()); value } } #[inline] fn value_type(&self) -> crate::Type { Type::static_type() } } #[doc(hidden)] impl From for crate::Value { #[inline] fn from(t: Type) -> Self { crate::value::ToValue::to_value(&t) } } impl StaticType for &'_ T { #[inline] fn static_type() -> Type { T::static_type() } } impl StaticType for &'_ mut T { #[inline] fn static_type() -> Type { T::static_type() } } macro_rules! builtin { ($name:ty, $val:ident) => { impl StaticType for $name { #[inline] fn static_type() -> Type { Type::$val } } }; } // rustdoc-stripper-ignore-next /// A GLib pointer /// /// A raw untyped pointer equivalent to [`*mut Pointee`](Pointee). pub type Pointer = ffi::gpointer; // rustdoc-stripper-ignore-next /// The target of a [Pointer] /// /// # Examples /// /// ``` /// use glib::prelude::*; /// use glib::types::{Pointee, Pointer}; /// use std::ptr::NonNull; /// /// let pointer = NonNull::::dangling(); /// let value = pointer.to_value(); /// assert!(value.is::()); /// assert_eq!(value.get(), Ok(pointer.as_ptr())); /// ``` pub type Pointee = libc::c_void; impl StaticType for ptr::NonNull { #[inline] fn static_type() -> Type { Pointer::static_type() } } #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ILong(pub libc::c_long); impl std::ops::Deref for ILong { type Target = libc::c_long; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } impl std::ops::DerefMut for ILong { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl From for ILong { #[inline] fn from(v: libc::c_long) -> ILong { ILong(v) } } impl From for libc::c_long { #[inline] fn from(v: ILong) -> libc::c_long { v.0 } } impl PartialEq for ILong { #[inline] fn eq(&self, other: &libc::c_long) -> bool { &self.0 == other } } impl PartialEq for libc::c_long { #[inline] fn eq(&self, other: &ILong) -> bool { self == &other.0 } } impl PartialOrd for ILong { #[inline] fn partial_cmp(&self, other: &libc::c_long) -> Option { self.0.partial_cmp(other) } } impl PartialOrd for libc::c_long { #[inline] fn partial_cmp(&self, other: &ILong) -> Option { self.partial_cmp(&other.0) } } #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ULong(pub libc::c_ulong); impl std::ops::Deref for ULong { type Target = libc::c_ulong; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } impl std::ops::DerefMut for ULong { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl From for ULong { #[inline] fn from(v: libc::c_ulong) -> ULong { ULong(v) } } impl From for libc::c_ulong { #[inline] fn from(v: ULong) -> libc::c_ulong { v.0 } } impl PartialEq for ULong { #[inline] fn eq(&self, other: &libc::c_ulong) -> bool { &self.0 == other } } impl PartialEq for libc::c_ulong { #[inline] fn eq(&self, other: &ULong) -> bool { self == &other.0 } } impl PartialOrd for ULong { #[inline] fn partial_cmp(&self, other: &libc::c_ulong) -> Option { self.0.partial_cmp(other) } } impl PartialOrd for libc::c_ulong { #[inline] fn partial_cmp(&self, other: &ULong) -> Option { self.partial_cmp(&other.0) } } builtin!(bool, BOOL); builtin!(i8, I8); builtin!(NonZeroI8, I8); builtin!(u8, U8); builtin!(NonZeroU8, U8); builtin!(i32, I32); builtin!(NonZeroI32, I32); builtin!(u32, U32); builtin!(NonZeroU32, U32); builtin!(i64, I64); builtin!(NonZeroI64, I64); builtin!(u64, U64); builtin!(NonZeroU64, U64); builtin!(ILong, I_LONG); builtin!(ULong, U_LONG); builtin!(f32, F32); builtin!(f64, F64); builtin!(str, STRING); builtin!(String, STRING); builtin!(PathBuf, STRING); builtin!(Path, STRING); builtin!(Pointer, POINTER); impl StaticType for [&'_ str] { #[inline] fn static_type() -> Type { unsafe { from_glib(ffi::g_strv_get_type()) } } } impl StaticType for Vec { #[inline] fn static_type() -> Type { unsafe { from_glib(ffi::g_strv_get_type()) } } } impl StaticType for () { #[inline] fn static_type() -> Type { Type::UNIT } } #[inline] pub unsafe fn instance_of(ptr: ffi::gconstpointer) -> bool { from_glib(gobject_ffi::g_type_check_instance_is_a( ptr as *mut _, ::static_type().into_glib(), )) } impl FromGlib for Type { #[inline] unsafe fn from_glib(val: ffi::GType) -> Self { Self(val) } } impl IntoGlib for Type { type GlibType = ffi::GType; #[inline] fn into_glib(self) -> ffi::GType { self.0 } } impl<'a> ToGlibContainerFromSlice<'a, *mut ffi::GType> for Type { type Storage = PhantomData<&'a [Type]>; #[inline] fn to_glib_none_from_slice(t: &'a [Type]) -> (*mut ffi::GType, Self::Storage) { (t.as_ptr() as *mut ffi::GType, PhantomData) } #[inline] fn to_glib_container_from_slice(t: &'a [Type]) -> (*mut ffi::GType, Self::Storage) { (Self::to_glib_full_from_slice(t), PhantomData) } fn to_glib_full_from_slice(t: &[Type]) -> *mut ffi::GType { if t.is_empty() { return ptr::null_mut(); } unsafe { let res = ffi::g_malloc(mem::size_of::() * (t.len() + 1)) as *mut ffi::GType; std::ptr::copy_nonoverlapping(t.as_ptr() as *const ffi::GType, res, t.len()); *res.add(t.len()) = 0; res } } } impl FromGlibContainerAsVec for Type { unsafe fn from_glib_none_num_as_vec(ptr: *const ffi::GType, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::::with_capacity(num); let res_ptr = res.as_mut_ptr() as *mut ffi::GType; std::ptr::copy_nonoverlapping(ptr, res_ptr, num); res.set_len(num); res } unsafe fn from_glib_container_num_as_vec(_: *const ffi::GType, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } unsafe fn from_glib_full_num_as_vec(_: *const ffi::GType, _: usize) -> Vec { // Can't really free a *const unimplemented!(); } } impl FromGlibContainerAsVec for Type { unsafe fn from_glib_none_num_as_vec(ptr: *mut ffi::GType, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *const _, num) } unsafe fn from_glib_container_num_as_vec(ptr: *mut ffi::GType, num: usize) -> Vec { let res = FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut ffi::GType, num: usize) -> Vec { FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, num) } } #[cfg(test)] mod tests { use std::collections::{BTreeSet, HashSet}; use super::*; use crate::InitiallyUnowned; #[test] fn invalid() { let invalid = Type::INVALID; assert_eq!(invalid.name(), ""); assert_eq!(invalid.qname(), crate::Quark::from_str("")); assert!(invalid.is_a(Type::INVALID)); assert!(!invalid.is_a(Type::STRING)); assert_eq!(invalid.parent(), None); assert!(invalid.children().is_empty()); assert!(invalid.interfaces().is_empty()); assert!(invalid.interface_prerequisites().is_empty()); assert!(!invalid.is_valid()); dbg!(&invalid); } #[test] fn hash() { // Get this first so the type is registered let iu_type = InitiallyUnowned::static_type(); let set = Type::OBJECT .children() .iter() .copied() .collect::>(); assert!(set.contains(&iu_type)); } #[test] fn ord() { // Get this first so the type is registered let iu_type = InitiallyUnowned::static_type(); assert!(Type::OBJECT < iu_type); let set = Type::OBJECT .children() .iter() .copied() .collect::>(); assert!(set.contains(&iu_type)); } } glib-0.20.9/src/unichar.rs000064400000000000000000000173011046102023000134210ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::mem::MaybeUninit; use crate::{ ffi, translate::{from_glib, IntoGlib, UnsafeFrom}, UnicodeBreakType, UnicodeScript, UnicodeType, }; mod sealed { pub trait Sealed {} impl Sealed for char {} } impl UnsafeFrom for char { #[inline] unsafe fn unsafe_from(t: u32) -> Self { debug_assert!( char::try_from(t).is_ok(), "glib returned an invalid Unicode codepoint" ); unsafe { char::from_u32_unchecked(t) } } } // rustdoc-stripper-ignore-next /// The kind of decomposition to perform #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] pub enum DecompositionKind { // rustdoc-stripper-ignore-next /// Compatibility decomposition Compatibility, // rustdoc-stripper-ignore-next /// Canonical decomposition Canonical, } // rustdoc-stripper-ignore-next /// The result of a single step of the Unicode canonical decomposition algorithm #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] pub enum CharacterDecomposition { // rustdoc-stripper-ignore-next /// The character could not be decomposed further NoDecomposition, // rustdoc-stripper-ignore-next // A 'singleton' decomposition, which means the character was replaced by another Singleton(char), // rustdoc-stripper-ignore-next /// The first character may decompose further, but the second cannot Pair(char, char), } // rustdoc-stripper-ignore-next /// This trait provides access to Unicode character classification and manipulations functions /// provided by GLib that do not exist in the standard library #[doc(alias = "g_unichar")] pub trait Unichar: sealed::Sealed + Copy + Into + UnsafeFrom { #[doc(alias = "g_unichar_type")] #[doc(alias = "unichar_type")] #[inline] fn unicode_type(self) -> UnicodeType { unsafe { from_glib(ffi::g_unichar_type(self.into())) } } #[doc(alias = "g_unichar_break_type")] #[doc(alias = "unichar_break_type")] #[inline] fn break_type(self) -> UnicodeBreakType { unsafe { from_glib(ffi::g_unichar_break_type(self.into())) } } #[doc(alias = "g_unichar_get_script")] #[doc(alias = "unichar_get_script")] #[inline] fn script(self) -> UnicodeScript { unsafe { from_glib(ffi::g_unichar_get_script(self.into())) } } #[doc(alias = "g_unichar_combining_class")] #[doc(alias = "unichar_combining_class")] #[inline] fn combining_class(self) -> u8 { // UAX #44 § 5.7.4: The character property invariants regarding Canonical_Combining_Class // guarantee that [...] all values used will be in the range 0..254. // So this cast is fine unsafe { ffi::g_unichar_combining_class(self.into()) as u8 } } #[doc(alias = "g_unichar_ismark")] #[doc(alias = "unichar_ismark")] #[inline] fn is_mark(self) -> bool { unsafe { from_glib(ffi::g_unichar_ismark(self.into())) } } #[doc(alias = "g_unichar_isgraph")] #[doc(alias = "unichar_isgraph")] #[inline] fn is_graphical(self) -> bool { unsafe { from_glib(ffi::g_unichar_isgraph(self.into())) } } #[doc(alias = "g_unichar_ispunct")] #[doc(alias = "unichar_ispunct")] #[inline] fn is_punctuation(self) -> bool { unsafe { from_glib(ffi::g_unichar_ispunct(self.into())) } } #[doc(alias = "g_unichar_istitle")] #[doc(alias = "unichar_istitle")] #[inline] fn is_titlecase(self) -> bool { unsafe { from_glib(ffi::g_unichar_istitle(self.into())) } } #[doc(alias = "g_unichar_isdefined")] #[doc(alias = "unichar_isdefined")] #[inline] fn is_defined(self) -> bool { unsafe { from_glib(ffi::g_unichar_isdefined(self.into())) } } #[doc(alias = "g_unichar_iswide")] #[doc(alias = "unichar_iswide")] #[inline] fn is_wide(self) -> bool { unsafe { from_glib(ffi::g_unichar_iswide(self.into())) } } #[doc(alias = "g_unichar_iswide_cjk")] #[doc(alias = "unichar_iswide_cjk")] #[inline] fn is_wide_cjk(self) -> bool { unsafe { from_glib(ffi::g_unichar_iswide_cjk(self.into())) } } #[doc(alias = "g_unichar_iszerowidth")] #[doc(alias = "unichar_iszerowidth")] #[inline] fn is_zero_width(self) -> bool { unsafe { from_glib(ffi::g_unichar_iszerowidth(self.into())) } } #[doc(alias = "g_unichar_totitle")] #[doc(alias = "unichar_totitle")] #[inline] fn to_titlecase(self) -> Self { unsafe { Self::unsafe_from(ffi::g_unichar_totitle(self.into())) } } #[doc(alias = "g_unichar_get_mirror_char")] #[doc(alias = "unichar_get_mirror_char")] #[inline] fn mirror_char(self) -> Option { // SAFETY: If g_unichar_get_mirror_char returns true, it will initialize `mirrored` unsafe { let mut mirrored = MaybeUninit::uninit(); let res = from_glib(ffi::g_unichar_get_mirror_char( self.into(), mirrored.as_mut_ptr(), )); if res { Some(Self::unsafe_from(mirrored.assume_init())) } else { None } } } #[doc(alias = "g_unichar_fully_decompose")] #[doc(alias = "unichar_fully_decompose")] #[inline] fn fully_decompose(self, decomposition_kind: DecompositionKind) -> Vec { let compat = match decomposition_kind { DecompositionKind::Compatibility => true, DecompositionKind::Canonical => false, }; let buffer_len = ffi::G_UNICHAR_MAX_DECOMPOSITION_LENGTH as usize; // SAFETY: We assume glib only ever writes valid Unicode codepoints in the provided buffer // and that it does not lie about the unsafe { let mut buffer = Vec::::with_capacity(buffer_len); let decomposition_length = ffi::g_unichar_fully_decompose( self.into(), compat.into_glib(), buffer.as_mut_ptr().cast(), buffer_len, ); debug_assert!(decomposition_length <= buffer_len); buffer.set_len(decomposition_length); buffer } } #[doc(alias = "g_unichar_decompose")] #[doc(alias = "unichar_decompose")] #[inline] fn decompose(self) -> CharacterDecomposition { // SAFETY: `a` and `b` will always be init after the g_unichar_decompose call returns unsafe { let mut a = MaybeUninit::uninit(); let mut b = MaybeUninit::uninit(); let res = from_glib(ffi::g_unichar_decompose( self.into(), a.as_mut_ptr(), b.as_mut_ptr(), )); if res { let (a, b) = (a.assume_init(), b.assume_init()); if b == 0 { CharacterDecomposition::Singleton(char::unsafe_from(a)) } else { CharacterDecomposition::Pair(char::unsafe_from(a), char::unsafe_from(b)) } } else { CharacterDecomposition::NoDecomposition } } } #[doc(alias = "g_unichar_compose")] #[doc(alias = "unichar_compose")] #[inline] fn compose(a: char, b: char) -> Option { // SAFETY: If g_unichar_compose returns true, it will initialize `out` unsafe { let mut out = MaybeUninit::uninit(); let res = from_glib(ffi::g_unichar_compose(a.into(), b.into(), out.as_mut_ptr())); if res { Some(Self::unsafe_from(out.assume_init())) } else { None } } } } impl Unichar for char {} glib-0.20.9/src/unicollate.rs000064400000000000000000000115171046102023000141320ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::ffi; // rustdoc-stripper-ignore-next /// A `CollationKey` allows ordering strings using the linguistically correct rules for the current locale. #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct CollationKey(crate::Slice); impl> From for CollationKey { // rustdoc-stripper-ignore-next /// Converts a string into a `CollationKey` that can be compared with other /// collation keys produced by the same function using `std::cmp::Ordering::cmp()`. #[doc(alias = "g_utf8_collate_key")] fn from(s: T) -> Self { let s = s.as_ref(); let key = unsafe { let ptr = ffi::g_utf8_collate_key(s.as_ptr() as *const _, s.len() as isize); let len = libc::strlen(ptr); crate::Slice::from_glib_full_num(ptr as *mut u8, len) }; Self(key) } } // rustdoc-stripper-ignore-next /// A `FilenameCollationKey` allows ordering file names using the linguistically correct rules for the current locale. /// Compared to `CollationKey`, filename collation keys take into consideration dots and other characters /// commonly found in file names. #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct FilenameCollationKey(crate::Slice); impl> From for FilenameCollationKey { // rustdoc-stripper-ignore-next /// Converts a string into a `FilenameCollationKey` that can be compared with other /// collation keys produced by the same function using `std::cmp::Ordering::cmp()`. #[doc(alias = "g_utf8_collate_key_for_filename")] fn from(s: T) -> Self { let s = s.as_ref(); let key = unsafe { let ptr = ffi::g_utf8_collate_key_for_filename(s.as_ptr() as *const _, s.len() as isize); let len = libc::strlen(ptr); crate::Slice::from_glib_full_num(ptr as *mut u8, len) }; Self(key) } } #[cfg(test)] mod tests { use super::*; #[test] fn collate() { let mut unsorted = vec![ String::from("bcd"), String::from("cde"), String::from("abc"), ]; let sorted = vec![ String::from("abc"), String::from("bcd"), String::from("cde"), ]; unsorted.sort_by(|s1, s2| CollationKey::from(&s1).cmp(&CollationKey::from(&s2))); assert_eq!(unsorted, sorted); } #[test] fn collate_non_ascii() { let mut unsorted = vec![ String::from("猫の手も借りたい"), String::from("日本語は難しい"), String::from("ありがとう"), ]; let sorted = vec![ String::from("ありがとう"), String::from("日本語は難しい"), String::from("猫の手も借りたい"), ]; unsorted.sort_by(|s1, s2| CollationKey::from(&s1).cmp(&CollationKey::from(&s2))); assert_eq!(unsorted, sorted); } #[test] fn collate_filenames() { let mut unsorted = vec![ String::from("bcd.a"), String::from("cde.b"), String::from("abc.c"), ]; let sorted = vec![ String::from("abc.c"), String::from("bcd.a"), String::from("cde.b"), ]; unsorted.sort_by(|s1, s2| { FilenameCollationKey::from(&s1).cmp(&FilenameCollationKey::from(&s2)) }); assert_eq!(unsorted, sorted); } #[test] fn collate_filenames_non_ascii() { let mut unsorted = vec![ String::from("猫の手も借りたい.foo"), String::from("日本語は難しい.bar"), String::from("ありがとう.baz"), ]; let sorted = vec![ String::from("ありがとう.baz"), String::from("日本語は難しい.bar"), String::from("猫の手も借りたい.foo"), ]; unsorted.sort_by(|s1, s2| { FilenameCollationKey::from(&s1).cmp(&FilenameCollationKey::from(&s2)) }); assert_eq!(unsorted, sorted); } #[test] fn collate_filenames_from_path() { use std::path::PathBuf; let mut unsorted = vec![ PathBuf::from("猫の手も借りたい.foo"), PathBuf::from("日本語は難しい.bar"), PathBuf::from("ありがとう.baz"), ]; let sorted = vec![ PathBuf::from("ありがとう.baz"), PathBuf::from("日本語は難しい.bar"), PathBuf::from("猫の手も借りたい.foo"), ]; unsorted.sort_by(|s1, s2| { FilenameCollationKey::from(&s1.to_string_lossy()) .cmp(&FilenameCollationKey::from(&s2.to_string_lossy())) }); assert_eq!(unsorted, sorted); } } glib-0.20.9/src/utils.rs000064400000000000000000000206541046102023000131350ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ ffi::{OsStr, OsString}, mem, ptr, }; use crate::{ffi, translate::*, GString}; // rustdoc-stripper-ignore-next /// Same as [`get_prgname()`]. /// /// [`get_prgname()`]: fn.get_prgname.html #[doc(alias = "get_program_name")] #[inline] pub fn program_name() -> Option { prgname() } #[doc(alias = "g_get_prgname")] #[doc(alias = "get_prgname")] #[inline] pub fn prgname() -> Option { unsafe { from_glib_none(ffi::g_get_prgname()) } } // rustdoc-stripper-ignore-next /// Same as [`set_prgname()`]. /// /// [`set_prgname()`]: fn.set_prgname.html #[inline] pub fn set_program_name(name: Option) { set_prgname(name) } #[doc(alias = "g_set_prgname")] #[inline] pub fn set_prgname(name: Option) { name.run_with_gstr(|name| unsafe { ffi::g_set_prgname(name.to_glib_none().0) }) } #[doc(alias = "g_environ_getenv")] pub fn environ_getenv>(envp: &[OsString], variable: K) -> Option { unsafe { from_glib_none(ffi::g_environ_getenv( envp.to_glib_none().0, variable.as_ref().to_glib_none().0, )) } } #[doc(alias = "g_mkstemp")] pub fn mkstemp>(tmpl: P) -> i32 { unsafe { // NOTE: This modifies the string in place, which is fine here because // to_glib_none() will create a temporary, NUL-terminated copy of the string. ffi::g_mkstemp(tmpl.as_ref().to_glib_none().0) } } #[doc(alias = "g_mkstemp_full")] pub fn mkstemp_full(tmpl: impl AsRef, flags: i32, mode: i32) -> i32 { unsafe { // NOTE: This modifies the string in place, which is fine here because // to_glib_none() will create a temporary, NUL-terminated copy of the string. ffi::g_mkstemp_full(tmpl.as_ref().to_glib_none().0, flags, mode) } } #[doc(alias = "g_mkdtemp")] pub fn mkdtemp(tmpl: impl AsRef) -> Option { unsafe { // NOTE: This modifies the string in place and returns it but does not free it // if it returns NULL. let tmpl = tmpl.as_ref().to_glib_full(); let res = ffi::g_mkdtemp(tmpl); if res.is_null() { ffi::g_free(tmpl as ffi::gpointer); None } else { from_glib_full(res) } } } #[doc(alias = "g_mkdtemp_full")] pub fn mkdtemp_full(tmpl: impl AsRef, mode: i32) -> Option { unsafe { // NOTE: This modifies the string in place and returns it but does not free it // if it returns NULL. let tmpl = tmpl.as_ref().to_glib_full(); let res = ffi::g_mkdtemp_full(tmpl, mode); if res.is_null() { ffi::g_free(tmpl as ffi::gpointer); None } else { from_glib_full(res) } } } #[doc(alias = "g_file_get_contents")] pub fn file_get_contents( filename: impl AsRef, ) -> Result, crate::Error> { unsafe { let mut contents = ptr::null_mut(); let mut length = mem::MaybeUninit::uninit(); let mut error = ptr::null_mut(); let _ = ffi::g_file_get_contents( filename.as_ref().to_glib_none().0, &mut contents, length.as_mut_ptr(), &mut error, ); if error.is_null() { Ok(crate::Slice::from_glib_full_num( contents, length.assume_init() as _, )) } else { Err(from_glib_full(error)) } } } pub fn is_canonical_pspec_name(name: &str) -> bool { name.as_bytes().iter().enumerate().all(|(i, c)| { i != 0 && (*c >= b'0' && *c <= b'9' || *c == b'-') || (*c >= b'A' && *c <= b'Z') || (*c >= b'a' && *c <= b'z') }) } #[doc(alias = "g_uri_escape_string")] pub fn uri_escape_string( unescaped: impl IntoGStr, reserved_chars_allowed: Option, allow_utf8: bool, ) -> crate::GString { unescaped.run_with_gstr(|unescaped| { reserved_chars_allowed.run_with_gstr(|reserved_chars_allowed| unsafe { from_glib_full(ffi::g_uri_escape_string( unescaped.to_glib_none().0, reserved_chars_allowed.to_glib_none().0, allow_utf8.into_glib(), )) }) }) } #[doc(alias = "g_uri_unescape_string")] pub fn uri_unescape_string( escaped_string: impl IntoGStr, illegal_characters: Option, ) -> Option { escaped_string.run_with_gstr(|escaped_string| { illegal_characters.run_with_gstr(|illegal_characters| unsafe { from_glib_full(ffi::g_uri_unescape_string( escaped_string.to_glib_none().0, illegal_characters.to_glib_none().0, )) }) }) } #[doc(alias = "g_uri_parse_scheme")] pub fn uri_parse_scheme(uri: impl IntoGStr) -> Option { uri.run_with_gstr(|uri| unsafe { from_glib_full(ffi::g_uri_parse_scheme(uri.to_glib_none().0)) }) } #[doc(alias = "g_uri_unescape_segment")] pub fn uri_unescape_segment( escaped_string: Option, escaped_string_end: Option, illegal_characters: Option, ) -> Option { escaped_string.run_with_gstr(|escaped_string| { escaped_string_end.run_with_gstr(|escaped_string_end| { illegal_characters.run_with_gstr(|illegal_characters| unsafe { from_glib_full(ffi::g_uri_unescape_segment( escaped_string.to_glib_none().0, escaped_string_end.to_glib_none().0, illegal_characters.to_glib_none().0, )) }) }) }) } #[cfg(test)] mod tests { use std::{env, sync::Mutex, sync::OnceLock}; //Mutex to prevent run environment tests parallel fn lock() -> &'static Mutex<()> { static LOCK: OnceLock> = OnceLock::new(); LOCK.get_or_init(|| Mutex::new(())) } const VAR_NAME: &str = "function_environment_test"; fn check_getenv(val: &str) { let _data = lock().lock().unwrap(); env::set_var(VAR_NAME, val); assert_eq!(env::var_os(VAR_NAME), Some(val.into())); assert_eq!(crate::getenv(VAR_NAME), Some(val.into())); let environ = crate::environ(); assert_eq!(crate::environ_getenv(&environ, VAR_NAME), Some(val.into())); } fn check_setenv(val: &str) { let _data = lock().lock().unwrap(); crate::setenv(VAR_NAME, val, true).unwrap(); assert_eq!(env::var_os(VAR_NAME), Some(val.into())); } #[test] fn getenv() { check_getenv("Test"); check_getenv("Тест"); // "Test" in Russian } #[test] fn setenv() { check_setenv("Test"); check_setenv("Тест"); // "Test" in Russian } #[test] fn test_filename_from_uri() { use std::path::PathBuf; use crate::GString; let uri: GString = "file:///foo/bar.txt".into(); if let Ok((filename, hostname)) = crate::filename_from_uri(&uri) { assert_eq!(filename, PathBuf::from(r"/foo/bar.txt")); assert_eq!(hostname, None); } else { unreachable!(); } let uri: GString = "file://host/foo/bar.txt".into(); if let Ok((filename, hostname)) = crate::filename_from_uri(&uri) { assert_eq!(filename, PathBuf::from(r"/foo/bar.txt")); assert_eq!(hostname, Some(GString::from("host"))); } else { unreachable!(); } } #[test] fn test_uri_parsing() { use crate::GString; assert_eq!( crate::uri_parse_scheme("foo://bar"), Some(GString::from("foo")) ); assert_eq!(crate::uri_parse_scheme("foo"), None); let escaped = crate::uri_escape_string("&foo", crate::NONE_STR, true); assert_eq!(escaped, GString::from("%26foo")); let unescaped = crate::uri_unescape_string(escaped.as_str(), crate::GStr::NONE); assert_eq!(unescaped, Some(GString::from("&foo"))); assert_eq!( crate::uri_unescape_segment(Some("/foo"), crate::NONE_STR, crate::NONE_STR), Some(GString::from("/foo")) ); assert_eq!( crate::uri_unescape_segment(Some("/foo%"), crate::NONE_STR, crate::NONE_STR), None ); } } glib-0.20.9/src/value.rs000064400000000000000000001333221046102023000131060ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! `Value` binding and helper traits. //! //! The type of a [`Value`](struct.Value.html) is dynamic in that it generally //! isn't known at compile time but once created a `Value` can't change its //! type. //! //! [`SendValue`](struct.SendValue.html) is a version of [`Value`](struct.Value.html) //! that can only store types that implement `Send` and as such implements `Send` itself. It //! dereferences to `Value` so it can be used everywhere `Value` references are accepted. //! //! Supported types are `bool`, `i8`, `u8`, `i32`, `u32`, `i64`, `u64`, `f32`, //! `f64`, `String` and objects (`T: IsA`). //! //! # Examples //! //! ``` //! use glib::prelude::*; // or `use gtk::prelude::*;` //! use glib::Value; //! //! // Value implement From<&i32>, From<&str> and From>. //! // Another option is the `ToValue` trait. //! let mut num = 10.to_value(); //! let mut hello = Value::from("Hello!"); //! let none: Option<&str> = None; //! let str_none = none.to_value(); //! //! // `is` tests the type of the value. //! assert!(num.is::()); //! assert!(hello.is::()); //! //! // `get` tries to get an optional value of the specified type //! // and returns an `Err` if the type doesn't match. //! assert_eq!(num.get(), Ok(10)); //! assert!(num.get::().is_err()); //! assert_eq!(hello.get(), Ok(String::from("Hello!"))); //! assert_eq!(hello.get::(), Ok(String::from("Hello!"))); //! assert_eq!(str_none.get::>(), Ok(None)); //! ``` use std::{ convert::Infallible, error, ffi::CStr, fmt, mem, num::{NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU32, NonZeroU64, NonZeroU8}, ops::Deref, path::{Path, PathBuf}, ptr, }; use libc::{c_char, c_void}; use crate::{ ffi, gobject_ffi, gstring::GString, prelude::*, translate::*, types::{Pointee, Pointer, Type}, GStr, }; // rustdoc-stripper-ignore-next /// A type that can be stored in `Value`s. pub trait ValueType: ToValue + for<'a> FromValue<'a> + 'static { // rustdoc-stripper-ignore-next /// Type to get the `Type` from. /// /// This exists only for handling optional types. // FIXME: Should default to Self once associated type defaults are stabilized // https://github.com/rust-lang/rust/issues/29661 type Type: StaticType; } // rustdoc-stripper-ignore-next /// A type that can be stored in `Value`s and is optional. /// /// These are types were storing an `Option` is valid. Examples are `String` and all object types. pub trait ValueTypeOptional: ValueType + ToValueOptional + FromValueOptional<'static> + StaticType { } impl ValueType for Option where T: for<'a> FromValue<'a, Checker = C> + ValueTypeOptional + StaticType + 'static, C: ValueTypeChecker>, E: error::Error + Send + Sized + 'static, { type Type = T::Type; } // rustdoc-stripper-ignore-next /// Trait for `Value` type checkers. pub unsafe trait ValueTypeChecker { type Error: error::Error + Send + Sized + 'static; fn check(value: &Value) -> Result<(), Self::Error>; } // rustdoc-stripper-ignore-next /// An error returned from the [`get`](struct.Value.html#method.get) function /// on a [`Value`](struct.Value.html) for non-optional types an `Option`. #[derive(Clone, PartialEq, Eq, Debug)] pub struct ValueTypeMismatchError { actual: Type, requested: Type, } impl ValueTypeMismatchError { pub fn new(actual: Type, requested: Type) -> Self { Self { actual, requested } } } impl ValueTypeMismatchError { pub fn actual_type(&self) -> Type { self.actual } pub fn requested_type(&self) -> Type { self.requested } } impl fmt::Display for ValueTypeMismatchError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "Value type mismatch. Actual {:?}, requested {:?}", self.actual_type(), self.requested_type(), ) } } impl error::Error for ValueTypeMismatchError {} impl From for ValueTypeMismatchError { fn from(e: Infallible) -> Self { match e {} } } // rustdoc-stripper-ignore-next /// Generic `Value` type checker for types. pub struct GenericValueTypeChecker(std::marker::PhantomData); unsafe impl ValueTypeChecker for GenericValueTypeChecker { type Error = ValueTypeMismatchError; #[doc(alias = "g_type_check_value_holds")] #[inline] fn check(value: &Value) -> Result<(), Self::Error> { unsafe { if gobject_ffi::g_type_check_value_holds(&value.inner, T::static_type().into_glib()) == ffi::GFALSE { Err(ValueTypeMismatchError::new( Type::from_glib(value.inner.g_type), T::static_type(), )) } else { Ok(()) } } } } pub struct CharTypeChecker(); unsafe impl ValueTypeChecker for CharTypeChecker { type Error = InvalidCharError; #[inline] fn check(value: &Value) -> Result<(), Self::Error> { let v = value.get::()?; match char::from_u32(v) { Some(_) => Ok(()), None => Err(InvalidCharError::CharConversionError), } } } // rustdoc-stripper-ignore-next /// An error returned from the [`get`](struct.Value.html#method.get) function /// on a [`Value`](struct.Value.html) for char (which are internally u32) types. #[derive(Clone, PartialEq, Eq, Debug)] pub enum InvalidCharError { WrongValueType(ValueTypeMismatchError), CharConversionError, } impl fmt::Display for InvalidCharError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::WrongValueType(err) => err.fmt(f), Self::CharConversionError => { write!(f, "couldn't convert to char, invalid u32 contents") } } } } impl error::Error for InvalidCharError {} impl From for InvalidCharError { fn from(err: ValueTypeMismatchError) -> Self { Self::WrongValueType(err) } } impl From for InvalidCharError { fn from(e: Infallible) -> Self { match e {} } } // rustdoc-stripper-ignore-next /// An error returned from the [`get`](struct.Value.html#method.get) /// function on a [`Value`](struct.Value.html) for optional types. #[derive(Clone, PartialEq, Eq, Debug)] pub enum ValueTypeMismatchOrNoneError { WrongValueType(E), UnexpectedNone, } impl fmt::Display for ValueTypeMismatchOrNoneError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::WrongValueType(err) => ::fmt(err, f), Self::UnexpectedNone => write!(f, "Unexpected None",), } } } impl error::Error for ValueTypeMismatchOrNoneError {} impl From for ValueTypeMismatchOrNoneError { fn from(err: E) -> Self { Self::WrongValueType(err) } } // rustdoc-stripper-ignore-next /// Generic `Value` type checker for optional types. pub struct GenericValueTypeOrNoneChecker(std::marker::PhantomData); unsafe impl ValueTypeChecker for GenericValueTypeOrNoneChecker { type Error = ValueTypeMismatchOrNoneError; #[inline] fn check(value: &Value) -> Result<(), Self::Error> { GenericValueTypeChecker::::check(value)?; unsafe { // Values are always zero-initialized so even if pointers are only 32 bits then the // whole 64 bit value will be 0 for NULL pointers. if value.inner.data[0].v_uint64 == 0 { return Err(Self::Error::UnexpectedNone); } } Ok(()) } } // rustdoc-stripper-ignore-next /// Trait to retrieve the contained value from a `Value`. /// /// Usually this would not be used directly but from the [`get`](struct.Value.html#method.get) /// function on a [`Value`](struct.Value.html) pub unsafe trait FromValue<'a>: Sized { // rustdoc-stripper-ignore-next /// Value type checker. type Checker: ValueTypeChecker; // rustdoc-stripper-ignore-next /// Get the contained value from a `Value`. /// /// # Safety /// `Self::Checker::check()` must be called first and must not fail. unsafe fn from_value(value: &'a Value) -> Self; } // rustdoc-stripper-ignore-next /// Trait for types that implement `FromValue` and are Optional. /// /// This trait is auto-implemented for the appropriate types and is sealed. pub trait FromValueOptional<'a>: private::FromValueOptionalSealed<'a> {} impl<'a, T, C, E> FromValueOptional<'a> for T where T: FromValue<'a, Checker = C>, C: ValueTypeChecker>, E: error::Error + Send + Sized + 'static, { } mod private { pub trait FromValueOptionalSealed<'a> {} impl<'a, T, C, E> FromValueOptionalSealed<'a> for T where T: super::FromValue<'a, Checker = C>, C: super::ValueTypeChecker>, E: super::error::Error + Send + Sized + 'static, { } } // rustdoc-stripper-ignore-next /// Wrapped `Value` type checker for optional types. pub struct ValueTypeOrNoneChecker(std::marker::PhantomData<(T, C, E)>); unsafe impl<'a, T, C, E> ValueTypeChecker for ValueTypeOrNoneChecker where T: FromValue<'a, Checker = C> + StaticType, C: ValueTypeChecker>, E: error::Error + Send + Sized + 'static, { type Error = E; #[inline] fn check(value: &Value) -> Result<(), Self::Error> { match T::Checker::check(value) { Err(ValueTypeMismatchOrNoneError::UnexpectedNone) => Ok(()), Err(ValueTypeMismatchOrNoneError::WrongValueType(err)) => Err(err), Ok(_) => Ok(()), } } } // rustdoc-stripper-ignore-next /// Blanket implementation for all optional types. unsafe impl<'a, T, C, E> FromValue<'a> for Option where T: FromValue<'a, Checker = C> + StaticType, C: ValueTypeChecker>, E: error::Error + Send + Sized + 'static, { type Checker = ValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a Value) -> Self { match T::Checker::check(value) { Err(ValueTypeMismatchOrNoneError::UnexpectedNone) => None, Err(ValueTypeMismatchOrNoneError::WrongValueType(_err)) => { // This should've been caught by the caller already. unreachable!(); } Ok(_) => Some(T::from_value(value)), } } } // rustdoc-stripper-ignore-next /// Trait to convert a value to a `Value`. /// /// Similar to other common conversion traits, the following invariants are guaranteed: /// /// - **Invertibility**: `x.to_value().get().unwrap() == x`. In words, [`FromValue`] is the inverse of `ToValue`. /// - **Idempotence**: `x.to_value() == x.to_value().to_value()`. /// In words, applying `ToValue` multiple times yields the same result as applying it once. /// Idempotence also applies the other way around: `value.get::()` is a no-op. /// /// There is also the possibility to wrap values within values, see [`BoxedValue`]. All (un-)boxing needs to be done /// manually, and will be preserved under the conversion methods. /// /// The conversion methods may cause values to be cloned, which may result in reference counter changes or heap allocations depending /// on the source and target type. pub trait ToValue { // rustdoc-stripper-ignore-next /// Convert a value to a `Value`. fn to_value(&self) -> Value; // rustdoc-stripper-ignore-next /// Returns the type identifier of `self`. /// /// This is the type of the value to be returned by `to_value`. fn value_type(&self) -> Type; } // rustdoc-stripper-ignore-next /// Blanket implementation for all references. impl ToValue for &T { #[inline] fn to_value(&self) -> Value { T::to_value(*self) } #[inline] fn value_type(&self) -> Type { T::static_type() } } // rustdoc-stripper-ignore-next /// Trait to convert an `Option` to a `Value` for optional types. pub trait ToValueOptional { // rustdoc-stripper-ignore-next /// Convert an `Option` to a `Value`. #[allow(clippy::wrong_self_convention)] fn to_value_optional(s: Option<&Self>) -> Value; } // rustdoc-stripper-ignore-next /// Blanket implementation for all optional types. impl ToValue for Option { #[inline] fn to_value(&self) -> Value { T::to_value_optional(self.as_ref()) } #[inline] fn value_type(&self) -> Type { T::static_type() } } impl + ToValueOptional> From> for Value { #[inline] fn from(t: Option) -> Self { match t { None => T::to_value_optional(None), Some(t) => t.into(), } } } impl StaticType for Option { #[inline] fn static_type() -> Type { T::static_type() } } impl ToValueOptional for &T { #[inline] fn to_value_optional(s: Option<&Self>) -> Value { ::to_value_optional(s.as_ref().map(|s| **s)) } } #[inline] unsafe fn copy_value(value: *const gobject_ffi::GValue) -> *mut gobject_ffi::GValue { let copy = ffi::g_malloc0(mem::size_of::()) as *mut gobject_ffi::GValue; copy_into_value(copy, value); copy } #[inline] unsafe fn free_value(value: *mut gobject_ffi::GValue) { clear_value(value); ffi::g_free(value as *mut _); } #[inline] unsafe fn init_value(value: *mut gobject_ffi::GValue) { ptr::write(value, mem::zeroed()); } #[inline] unsafe fn copy_into_value(dest: *mut gobject_ffi::GValue, src: *const gobject_ffi::GValue) { gobject_ffi::g_value_init(dest, (*src).g_type); gobject_ffi::g_value_copy(src, dest); } #[inline] unsafe fn clear_value(value: *mut gobject_ffi::GValue) { // Before GLib 2.48, unsetting a zeroed GValue would give critical warnings // https://bugzilla.gnome.org/show_bug.cgi?id=755766 if (*value).g_type != gobject_ffi::G_TYPE_INVALID { gobject_ffi::g_value_unset(value); } } // TODO: Should use impl !Send for Value {} once stable crate::wrapper! { // rustdoc-stripper-ignore-next /// 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. #[doc(alias = "GValue")] pub struct Value(BoxedInline); match fn { copy => |ptr| copy_value(ptr), free => |ptr| free_value(ptr), init => |ptr| init_value(ptr), copy_into => |dest, src| copy_into_value(dest, src), clear => |ptr| clear_value(ptr), } } impl Value { // rustdoc-stripper-ignore-next /// Creates a new `Value` that is initialized with `type_`. /// /// # Panics /// /// If `type_` can't be stored in a `Value` this function panics. pub fn from_type(type_: Type) -> Self { unsafe { assert_eq!( gobject_ffi::g_type_check_is_value_type(type_.into_glib()), ffi::GTRUE ); Self::from_type_unchecked(type_) } } // rustdoc-stripper-ignore-next /// Creates a new `Value` that is initialized with `type_`. /// /// # SAFETY /// /// This must be called with a valid `type_` that can be stored in `Value`s. #[inline] pub unsafe fn from_type_unchecked(type_: Type) -> Self { unsafe { let mut value = Value::uninitialized(); gobject_ffi::g_value_init(value.to_glib_none_mut().0, type_.into_glib()); value } } // rustdoc-stripper-ignore-next /// Creates a new `Value` that is initialized for a given `ValueType`. #[inline] pub fn for_value_type() -> Self { unsafe { Value::from_type_unchecked(T::Type::static_type()) } } // rustdoc-stripper-ignore-next /// Creates a new `String`-typed `Value` from a `'static` string. #[inline] #[doc(alias = "g_value_set_static_string")] pub fn from_static_str(s: &'static GStr) -> Self { unsafe { let mut v = Self::from_type_unchecked(Type::STRING); gobject_ffi::g_value_set_static_string(v.to_glib_none_mut().0, s.as_ptr()); v } } #[cfg(feature = "v2_66")] #[cfg_attr(docsrs, doc(cfg(feature = "v2_66")))] // rustdoc-stripper-ignore-next /// Creates a new `String`-typed `Value` from a `'static` string that is also assumed to be /// interned. #[inline] #[doc(alias = "g_value_set_interned_string")] pub fn from_interned_str(s: &'static GStr) -> Self { unsafe { let mut v = Self::from_type_unchecked(Type::STRING); gobject_ffi::g_value_set_interned_string(v.to_glib_none_mut().0, s.as_ptr()); v } } // rustdoc-stripper-ignore-next /// Tries to get a value of type `T`. /// /// Returns `Ok` if the type is correct. #[inline] pub fn get<'a, T>( &'a self, ) -> Result>::Checker as ValueTypeChecker>::Error> where T: FromValue<'a>, { unsafe { T::Checker::check(self)?; Ok(T::from_value(self)) } } // rustdoc-stripper-ignore-next /// Tries to get a value of an owned type `T`. #[inline] pub fn get_owned(&self) -> Result::Checker as ValueTypeChecker>::Error> where T: for<'b> FromValue<'b> + 'static, { unsafe { T::Checker::check(self)?; Ok(FromValue::from_value(self)) } } // rustdoc-stripper-ignore-next /// Returns `true` if the type of the value corresponds to `T` /// or is a sub-type of `T`. #[inline] pub fn is(&self) -> bool { self.is_type(T::static_type()) } // rustdoc-stripper-ignore-next /// Returns `true` if the type of the value corresponds to `type_` /// or is a sub-type of `type_`. #[inline] pub fn is_type(&self, type_: Type) -> bool { self.type_().is_a(type_) } // rustdoc-stripper-ignore-next /// Returns the type of the value. #[inline] pub fn type_(&self) -> Type { unsafe { from_glib(self.inner.g_type) } } // rustdoc-stripper-ignore-next /// Returns whether `Value`s of type `src` can be transformed to type `dst`. #[doc(alias = "g_value_type_transformable")] pub fn type_transformable(src: Type, dst: Type) -> bool { unsafe { from_glib(gobject_ffi::g_value_type_transformable( src.into_glib(), dst.into_glib(), )) } } // rustdoc-stripper-ignore-next /// Tries to transform the value into a value of the target type #[doc(alias = "g_value_transform")] pub fn transform(&self) -> Result { self.transform_with_type(T::Type::static_type()) } // rustdoc-stripper-ignore-next /// Tries to transform the value into a value of the target type #[doc(alias = "g_value_transform")] pub fn transform_with_type(&self, type_: Type) -> Result { unsafe { let mut dest = Value::from_type(type_); if from_glib(gobject_ffi::g_value_transform( self.to_glib_none().0, dest.to_glib_none_mut().0, )) { Ok(dest) } else { Err(crate::bool_error!( "Can't transform value of type '{}' into '{}'", self.type_(), type_ )) } } } // rustdoc-stripper-ignore-next /// Consumes `Value` and returns the corresponding `GValue`. #[inline] pub fn into_raw(self) -> gobject_ffi::GValue { unsafe { let s = mem::ManuallyDrop::new(self); ptr::read(&s.inner) } } // rustdoc-stripper-ignore-next /// Converts a `Value` into a `SendValue`. This fails if `self` does not store a value of type /// `T`. It is required for `T` to be `Send` to call this function. #[inline] pub fn try_into_send_value(self) -> Result { if self.type_().is_a(T::static_type()) { unsafe { Ok(SendValue::unsafe_from(self.into_raw())) } } else { Err(self) } } // rustdoc-stripper-ignore-next /// Converts a `Value` into a `SendValue`. /// /// # Safety /// /// The type of the value contained in `self` must be `Send`. #[inline] pub unsafe fn into_send_value(self) -> SendValue { SendValue::unsafe_from(self.into_raw()) } fn content_debug_string(&self) -> GString { unsafe { from_glib_full(gobject_ffi::g_strdup_value_contents(self.to_glib_none().0)) } } } impl fmt::Debug for Value { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "({}) {}", self.type_(), self.content_debug_string()) } } impl<'a, T: ?Sized + ToValue> From<&'a T> for Value { #[inline] fn from(value: &'a T) -> Self { value.to_value() } } impl From for Value { #[inline] fn from(value: SendValue) -> Self { unsafe { Value::unsafe_from(value.into_raw()) } } } impl ToValue for Value { #[inline] fn to_value(&self) -> Value { self.clone() } #[inline] fn value_type(&self) -> Type { self.type_() } } impl ToValue for &Value { #[inline] fn to_value(&self) -> Value { (*self).clone() } #[inline] fn value_type(&self) -> Type { self.type_() } } pub struct NopChecker; unsafe impl ValueTypeChecker for NopChecker { type Error = Infallible; #[inline] fn check(_value: &Value) -> Result<(), Self::Error> { Ok(()) } } unsafe impl<'a> FromValue<'a> for Value { type Checker = NopChecker; #[inline] unsafe fn from_value(value: &'a Value) -> Self { value.clone() } } unsafe impl<'a> FromValue<'a> for &'a Value { type Checker = NopChecker; #[inline] unsafe fn from_value(value: &'a Value) -> Self { value } } impl ToValue for SendValue { #[inline] fn to_value(&self) -> Value { unsafe { from_glib_none(self.to_glib_none().0) } } #[inline] fn value_type(&self) -> Type { self.type_() } } impl ToValue for &SendValue { #[inline] fn to_value(&self) -> Value { unsafe { from_glib_none(self.to_glib_none().0) } } #[inline] fn value_type(&self) -> Type { self.type_() } } impl StaticType for BoxedValue { #[inline] fn static_type() -> Type { unsafe { from_glib(gobject_ffi::g_value_get_type()) } } } crate::wrapper! { // rustdoc-stripper-ignore-next /// A version of [`Value`](struct.Value.html) for storing `Send` types, that implements Send /// itself. /// /// See the [module documentation](index.html) for more details. #[doc(alias = "GValue")] pub struct SendValue(BoxedInline); match fn { copy => |ptr| copy_value(ptr), free => |ptr| free_value(ptr), init => |ptr| init_value(ptr), copy_into => |dest, src| copy_into_value(dest, src), clear => |ptr| clear_value(ptr), } } unsafe impl Send for SendValue {} impl SendValue { // rustdoc-stripper-ignore-next /// Consumes `SendValue` and returns the corresponding `GValue`. #[inline] pub fn into_raw(self) -> gobject_ffi::GValue { unsafe { let s = mem::ManuallyDrop::new(self); ptr::read(&s.inner) } } #[inline] pub fn from_owned>(t: T) -> Self { unsafe { Self::unsafe_from(t.into().into_raw()) } } } impl fmt::Debug for SendValue { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "({}) {}", self.type_(), self.content_debug_string()) } } impl Deref for SendValue { type Target = Value; #[inline] fn deref(&self) -> &Value { unsafe { &*(self as *const SendValue as *const Value) } } } impl<'a, T: ?Sized + ToSendValue> From<&'a T> for SendValue { #[inline] fn from(value: &'a T) -> Self { value.to_send_value() } } // rustdoc-stripper-ignore-next /// Converts to `SendValue`. pub trait ToSendValue: Send + ToValue { // rustdoc-stripper-ignore-next /// Returns a `SendValue` clone of `self`. fn to_send_value(&self) -> SendValue; } impl ToSendValue for T { #[inline] fn to_send_value(&self) -> SendValue { unsafe { SendValue::unsafe_from(self.to_value().into_raw()) } } } unsafe impl<'a> FromValue<'a> for &'a str { type Checker = GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a Value) -> Self { let ptr = gobject_ffi::g_value_get_string(value.to_glib_none().0); CStr::from_ptr(ptr).to_str().expect("Invalid UTF-8") } } impl ToValue for str { fn to_value(&self) -> Value { unsafe { let mut value = Value::for_value_type::(); gobject_ffi::g_value_take_string(value.to_glib_none_mut().0, self.to_glib_full()); value } } fn value_type(&self) -> Type { String::static_type() } } impl ToValue for &str { fn to_value(&self) -> Value { (*self).to_value() } fn value_type(&self) -> Type { String::static_type() } } impl ToValueOptional for str { fn to_value_optional(s: Option<&Self>) -> Value { let mut value = Value::for_value_type::(); unsafe { gobject_ffi::g_value_take_string(value.to_glib_none_mut().0, s.to_glib_full()); } value } } impl ValueType for String { type Type = String; } impl ValueTypeOptional for String {} unsafe impl<'a> FromValue<'a> for String { type Checker = GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a Value) -> Self { String::from(<&str>::from_value(value)) } } impl ToValue for String { fn to_value(&self) -> Value { <&str>::to_value(&self.as_str()) } fn value_type(&self) -> Type { String::static_type() } } impl From for Value { #[inline] fn from(s: String) -> Self { s.to_value() } } impl ToValueOptional for String { fn to_value_optional(s: Option<&Self>) -> Value { ::to_value_optional(s.as_ref().map(|s| s.as_str())) } } impl ValueType for Box { type Type = String; } impl ValueTypeOptional for Box {} unsafe impl<'a> FromValue<'a> for Box { type Checker = GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a Value) -> Self { Box::::from(<&str>::from_value(value)) } } impl StaticType for Box { fn static_type() -> Type { String::static_type() } } impl ToValue for Box { fn to_value(&self) -> Value { <&str>::to_value(&self.as_ref()) } fn value_type(&self) -> Type { String::static_type() } } impl From> for Value { #[inline] fn from(s: Box) -> Self { s.to_value() } } impl ToValueOptional for Box { fn to_value_optional(s: Option<&Self>) -> Value { ::to_value_optional(s.as_ref().map(|s| s.as_ref())) } } impl ValueType for Vec { type Type = Vec; } unsafe impl<'a> FromValue<'a> for Vec { type Checker = GenericValueTypeChecker; unsafe fn from_value(value: &'a Value) -> Self { let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const *const c_char; FromGlibPtrContainer::from_glib_none(ptr) } } impl ToValue for Vec { fn to_value(&self) -> Value { unsafe { let mut value = Value::for_value_type::(); let ptr: *mut *mut c_char = self.to_glib_full(); gobject_ffi::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void); value } } fn value_type(&self) -> Type { >::static_type() } } impl From> for Value { #[inline] fn from(s: Vec) -> Self { s.to_value() } } impl ToValue for [&'_ str] { fn to_value(&self) -> Value { unsafe { let mut value = Value::for_value_type::>(); let ptr: *mut *mut c_char = self.to_glib_full(); gobject_ffi::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void); value } } fn value_type(&self) -> Type { >::static_type() } } impl ToValue for &'_ [&'_ str] { fn to_value(&self) -> Value { unsafe { let mut value = Value::for_value_type::>(); let ptr: *mut *mut c_char = self.to_glib_full(); gobject_ffi::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void); value } } fn value_type(&self) -> Type { >::static_type() } } impl ToValue for Path { fn to_value(&self) -> Value { unsafe { let mut value = Value::for_value_type::(); gobject_ffi::g_value_take_string(value.to_glib_none_mut().0, self.to_glib_full()); value } } fn value_type(&self) -> Type { PathBuf::static_type() } } impl ToValue for &Path { fn to_value(&self) -> Value { (*self).to_value() } fn value_type(&self) -> Type { PathBuf::static_type() } } impl ToValueOptional for Path { fn to_value_optional(s: Option<&Self>) -> Value { let mut value = Value::for_value_type::(); unsafe { gobject_ffi::g_value_take_string(value.to_glib_none_mut().0, s.to_glib_full()); } value } } impl ValueType for PathBuf { type Type = PathBuf; } impl ValueTypeOptional for PathBuf {} unsafe impl<'a> FromValue<'a> for PathBuf { type Checker = GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a Value) -> Self { from_glib_none(gobject_ffi::g_value_get_string(value.to_glib_none().0)) } } impl ToValue for PathBuf { fn to_value(&self) -> Value { <&Path>::to_value(&self.as_path()) } fn value_type(&self) -> Type { PathBuf::static_type() } } impl From for Value { #[inline] fn from(s: PathBuf) -> Self { s.to_value() } } impl ToValueOptional for PathBuf { fn to_value_optional(s: Option<&Self>) -> Value { ::to_value_optional(s.as_ref().map(|s| s.as_path())) } } impl ValueType for bool { type Type = Self; } unsafe impl<'a> FromValue<'a> for bool { type Checker = GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a Value) -> Self { from_glib(gobject_ffi::g_value_get_boolean(value.to_glib_none().0)) } } impl ToValue for bool { #[inline] fn to_value(&self) -> Value { let mut value = Value::for_value_type::(); unsafe { gobject_ffi::g_value_set_boolean(&mut value.inner, self.into_glib()); } value } #[inline] fn value_type(&self) -> Type { Self::static_type() } } impl From for Value { #[inline] fn from(v: bool) -> Self { v.to_value() } } impl ValueType for Pointer { type Type = Self; } unsafe impl<'a> FromValue<'a> for Pointer { type Checker = GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a Value) -> Self { gobject_ffi::g_value_get_pointer(value.to_glib_none().0) } } impl ToValue for Pointer { #[inline] fn to_value(&self) -> Value { let mut value = Value::for_value_type::(); unsafe { gobject_ffi::g_value_set_pointer(&mut value.inner, *self); } value } #[inline] fn value_type(&self) -> Type { <::Type as StaticType>::static_type() } } impl From for Value { #[inline] fn from(v: Pointer) -> Self { v.to_value() } } impl ValueType for ptr::NonNull { type Type = Pointer; } unsafe impl<'a> FromValue<'a> for ptr::NonNull { type Checker = GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a Value) -> Self { ptr::NonNull::new_unchecked(Pointer::from_value(value)) } } impl ToValue for ptr::NonNull { #[inline] fn to_value(&self) -> Value { self.as_ptr().to_value() } #[inline] fn value_type(&self) -> Type { <::Type as StaticType>::static_type() } } impl From> for Value { #[inline] fn from(v: ptr::NonNull) -> Self { v.to_value() } } impl ToValueOptional for ptr::NonNull { #[inline] fn to_value_optional(p: Option<&Self>) -> Value { p.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut()).to_value() } } macro_rules! numeric { ($name:ty, $get:expr, $set:expr) => { impl ValueType for $name { type Type = Self; } unsafe impl<'a> FromValue<'a> for $name { type Checker = GenericValueTypeChecker; #[inline] #[allow(clippy::redundant_closure_call)] unsafe fn from_value(value: &'a Value) -> Self { $get(value.to_glib_none().0) } } impl ToValue for $name { #[inline] #[allow(clippy::redundant_closure_call)] fn to_value(&self) -> Value { let mut value = Value::for_value_type::(); unsafe { $set(&mut value.inner, *self); } value } #[inline] fn value_type(&self) -> Type { Self::static_type() } } impl From<$name> for Value { #[inline] fn from(v: $name) -> Self { v.to_value() } } }; } macro_rules! not_zero { ($name:ty, $num:ty) => { impl ValueType for $name { type Type = $name; } unsafe impl<'a> FromValue<'a> for $name { // Works because it returns `UnexpectedNone` if the value is NULL // by checking it against `0`. type Checker = GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a Value) -> Self { let res = <$num>::from_value(value); Self::try_from(res).unwrap() } } impl ToValue for $name { #[inline] fn to_value(&self) -> Value { <$num>::to_value(&<$num>::from(*self)) } #[inline] fn value_type(&self) -> Type { Self::static_type() } } impl From<$name> for Value { #[inline] fn from(v: $name) -> Self { v.to_value() } } impl ToValueOptional for $name { fn to_value_optional(s: Option<&Self>) -> Value { match s { Some(x) => x.to_value(), None => <$num>::to_value(&0), } } } }; } numeric!( i8, gobject_ffi::g_value_get_schar, gobject_ffi::g_value_set_schar ); not_zero!(NonZeroI8, i8); numeric!( u8, gobject_ffi::g_value_get_uchar, gobject_ffi::g_value_set_uchar ); not_zero!(NonZeroU8, u8); numeric!( i32, gobject_ffi::g_value_get_int, gobject_ffi::g_value_set_int ); not_zero!(NonZeroI32, i32); numeric!( u32, gobject_ffi::g_value_get_uint, gobject_ffi::g_value_set_uint ); not_zero!(NonZeroU32, u32); numeric!( i64, gobject_ffi::g_value_get_int64, gobject_ffi::g_value_set_int64 ); not_zero!(NonZeroI64, i64); numeric!( u64, gobject_ffi::g_value_get_uint64, gobject_ffi::g_value_set_uint64 ); not_zero!(NonZeroU64, u64); numeric!( crate::ILong, |v| gobject_ffi::g_value_get_long(v).into(), |v, i: crate::ILong| gobject_ffi::g_value_set_long(v, i.0) ); numeric!( crate::ULong, |v| gobject_ffi::g_value_get_ulong(v).into(), |v, i: crate::ULong| gobject_ffi::g_value_set_ulong(v, i.0) ); numeric!( f32, gobject_ffi::g_value_get_float, gobject_ffi::g_value_set_float ); numeric!( f64, gobject_ffi::g_value_get_double, gobject_ffi::g_value_set_double ); impl ValueType for char { type Type = u32; } unsafe impl<'a> FromValue<'a> for char { type Checker = CharTypeChecker; #[inline] unsafe fn from_value(value: &'a Value) -> Self { let res: u32 = gobject_ffi::g_value_get_uint(value.to_glib_none().0); // safe because the check is done by `Self::Checker` char::from_u32_unchecked(res) } } impl ToValue for char { #[inline] fn to_value(&self) -> Value { let mut value = Value::for_value_type::(); unsafe { gobject_ffi::g_value_set_uint(&mut value.inner, *self as u32); } value } #[inline] fn value_type(&self) -> Type { crate::Type::U32 } } impl From for Value { #[inline] fn from(v: char) -> Self { v.to_value() } } // rustdoc-stripper-ignore-next /// A [`Value`] containing another [`Value`]. pub struct BoxedValue(pub Value); impl Deref for BoxedValue { type Target = Value; #[inline] fn deref(&self) -> &Value { &self.0 } } impl ValueType for BoxedValue { type Type = BoxedValue; } impl ValueTypeOptional for BoxedValue {} unsafe impl<'a> FromValue<'a> for BoxedValue { type Checker = GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a Value) -> Self { let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0); BoxedValue(from_glib_none(ptr as *const gobject_ffi::GValue)) } } impl ToValue for BoxedValue { #[inline] fn to_value(&self) -> Value { unsafe { let mut value = Value::for_value_type::(); gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, self.0.to_glib_none().0 as ffi::gconstpointer, ); value } } #[inline] fn value_type(&self) -> Type { BoxedValue::static_type() } } impl From for Value { #[inline] fn from(v: BoxedValue) -> Self { unsafe { let mut value = Value::for_value_type::(); gobject_ffi::g_value_take_boxed( value.to_glib_none_mut().0, v.0.to_glib_full() as ffi::gconstpointer, ); value } } } impl ToValueOptional for BoxedValue { #[inline] fn to_value_optional(s: Option<&Self>) -> Value { let mut value = Value::for_value_type::(); unsafe { gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, s.map(|s| &s.0).to_glib_none().0 as ffi::gconstpointer, ); } value } } #[cfg(test)] mod tests { use std::num::NonZeroI32; 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 = ["123", "456"].to_value(); assert_eq!( v.get::>(), Ok(vec![GString::from("123"), GString::from("456")]) ); let v = vec![String::from("123"), String::from("456")].to_value(); assert_eq!( v.get::>(), Ok(vec![GString::from("123"), GString::from("456")]) ); } #[test] fn test_from_to_value() { let v = 123.to_value(); assert_eq!(v.get(), Ok(123)); assert_eq!( v.get::<&str>(), Err(ValueTypeMismatchError::new(Type::I32, Type::STRING).into()) ); assert_eq!( v.get::(), Err(ValueTypeMismatchError::new(Type::I32, Type::BOOL)) ); // Check if &str / str / Option<&str> etc can be converted and retrieved let v_str = "test".to_value(); assert_eq!(v_str.get::<&str>(), Ok("test")); assert_eq!(v_str.get::>(), Ok(Some("test"))); assert_eq!( v_str.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); let some_v = Some("test").to_value(); assert_eq!(some_v.get::<&str>(), Ok("test")); assert_eq!(some_v.get_owned::(), Ok("test".to_string())); assert_eq!( some_v.get_owned::>(), Ok(Some("test".to_string())) ); assert_eq!(some_v.get::>(), Ok(Some("test"))); assert_eq!( some_v.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); let none_str: Option<&str> = None; let none_v = none_str.to_value(); assert_eq!(none_v.get::>(), Ok(None)); assert_eq!( none_v.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); // Check if owned T and Option can be converted and retrieved let v_str = String::from("test").to_value(); assert_eq!(v_str.get::(), Ok(String::from("test"))); assert_eq!( v_str.get::>(), Ok(Some(String::from("test"))) ); assert_eq!( v_str.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); let some_v = Some(String::from("test")).to_value(); assert_eq!(some_v.get::(), Ok(String::from("test"))); assert_eq!( some_v.get::>(), Ok(Some(String::from("test"))) ); assert_eq!( some_v.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); let none_str: Option = None; let none_v = none_str.to_value(); assert_eq!(none_v.get::>(), Ok(None)); assert_eq!( none_v.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); let c_v = 'c'.to_value(); assert_eq!(c_v.get::(), Ok('c')); let c_v = 0xFFFFFFFFu32.to_value(); assert_eq!( c_v.get::(), Err(InvalidCharError::CharConversionError) ); // Check if &T and Option<&T> can be converted and retrieved let v_str = String::from("test").to_value(); assert_eq!(v_str.get::(), Ok(String::from("test"))); assert_eq!( v_str.get::>(), Ok(Some(String::from("test"))) ); assert_eq!( v_str.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); let some_v = Some(&String::from("test")).to_value(); assert_eq!(some_v.get::(), Ok(String::from("test"))); assert_eq!( some_v.get::>(), Ok(Some(String::from("test"))) ); assert_eq!( some_v.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); let none_str: Option<&String> = None; let none_v = none_str.to_value(); assert_eq!(none_v.get::>(), Ok(None)); assert_eq!( none_v.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); // Check handling of NonZeroT let v = NonZeroI32::new(123).unwrap().to_value(); assert_eq!(v.get::(), Ok(NonZeroI32::new(123).unwrap())); let v = 123i32.to_value(); assert_eq!(v.get::(), Ok(NonZeroI32::new(123).unwrap())); let v = 0i32.to_value(); assert_eq!( v.get::(), Err(ValueTypeMismatchOrNoneError::UnexpectedNone) ); assert_eq!(v.get::>(), Ok(None)); } #[test] fn test_transform() { let v = 123.to_value(); let v2 = v .transform::() .expect("Failed to transform to string"); assert_eq!(v2.get::<&str>(), Ok("123")); } #[test] fn test_into_raw() { unsafe { let mut v = 123.to_value().into_raw(); assert_eq!(gobject_ffi::g_type_check_value(&v), ffi::GTRUE); assert_eq!(gobject_ffi::g_value_get_int(&v), 123); gobject_ffi::g_value_unset(&mut v); } } #[test] fn test_debug() { fn value_debug_string(val: T) -> String { format!("{:?}", val.to_value()) } assert_eq!(value_debug_string(1u32), "(guint) 1"); assert_eq!(value_debug_string(2i32), "(gint) 2"); assert_eq!(value_debug_string(false), "(gboolean) FALSE"); assert_eq!(value_debug_string("FooBar"), r#"(gchararray) "FooBar""#); } } glib-0.20.9/src/value_array.rs000064400000000000000000000222521046102023000143030ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{cmp::Ordering, ops, slice}; use crate::{ ffi, gobject_ffi, prelude::*, translate::*, ParamSpecValueArray, ParamSpecValueArrayBuilder, Type, Value, }; wrapper! { #[derive(Debug)] #[doc(alias = "GValueArray")] pub struct ValueArray(Boxed); match fn { copy => |ptr| gobject_ffi::g_value_array_copy(mut_override(ptr)), free => |ptr| gobject_ffi::g_value_array_free(ptr), } } impl ValueArray { #[inline] pub fn new(values: impl IntoIterator) -> Self { let iter = values.into_iter(); let mut array = Self::with_capacity(iter.size_hint().0); for v in iter { array.append(v.to_value()); } array } #[inline] pub fn from_values(values: impl IntoIterator) -> Self { Self::new(values) } #[doc(alias = "g_value_array_new")] #[inline] pub fn with_capacity(capacity: usize) -> ValueArray { assert!(capacity <= u32::MAX as usize); unsafe { from_glib_full(gobject_ffi::g_value_array_new(capacity as u32)) } } #[inline] pub fn is_empty(&self) -> bool { self.len() == 0 } #[inline] pub fn len(&self) -> usize { self.inner.n_values as usize } #[doc(alias = "g_value_array_append")] #[inline] pub fn append(&mut self, value: impl ToValue) { self.append_value(&value.to_value()); } #[doc(alias = "g_value_array_append")] #[inline] pub fn append_value(&mut self, value: &Value) { unsafe { gobject_ffi::g_value_array_append(self.to_glib_none_mut().0, value.to_glib_none().0); } } #[doc(alias = "g_value_array_insert")] #[inline] pub fn insert(&mut self, index_: usize, value: impl ToValue) { self.insert_value(index_, &value.to_value()); } #[doc(alias = "g_value_array_insert")] #[inline] pub fn insert_value(&mut self, index_: usize, value: &Value) { assert!(index_ <= self.len()); unsafe { gobject_ffi::g_value_array_insert( self.to_glib_none_mut().0, index_ as u32, value.to_glib_none().0, ); } } #[doc(alias = "g_value_array_prepend")] #[inline] pub fn prepend(&mut self, value: impl ToValue) { self.prepend_value(&value.to_value()); } #[doc(alias = "g_value_array_prepend")] #[inline] pub fn prepend_value(&mut self, value: &Value) { unsafe { gobject_ffi::g_value_array_prepend(self.to_glib_none_mut().0, value.to_glib_none().0); } } #[doc(alias = "g_value_array_remove")] #[inline] pub fn remove(&mut self, index_: usize) { assert!(index_ < self.len()); unsafe { gobject_ffi::g_value_array_remove(self.to_glib_none_mut().0, index_ as u32); } } #[doc(alias = "g_value_array_sort_with_data")] pub fn sort_with_data Ordering>(&mut self, compare_func: F) { unsafe extern "C" fn compare_func_trampoline( a: ffi::gconstpointer, b: ffi::gconstpointer, func: ffi::gpointer, ) -> i32 { let func = func as *mut &mut (dyn FnMut(&Value, &Value) -> Ordering); let a = &*(a as *const Value); let b = &*(b as *const Value); (*func)(a, b).into_glib() } unsafe { let mut func = compare_func; let func_obj: &mut (dyn FnMut(&Value, &Value) -> Ordering) = &mut func; let func_ptr = &func_obj as *const &mut (dyn FnMut(&Value, &Value) -> Ordering) as ffi::gpointer; gobject_ffi::g_value_array_sort_with_data( self.to_glib_none_mut().0, Some(compare_func_trampoline), func_ptr, ); } } #[inline] pub fn as_slice(&self) -> &[Value] { if self.is_empty() { return &[]; } unsafe { slice::from_raw_parts( (*self.as_ptr()).values as *const Value, (*self.as_ptr()).n_values as usize, ) } } #[inline] pub fn as_mut_slice(&mut self) -> &mut [Value] { if self.is_empty() { return &mut []; } unsafe { slice::from_raw_parts_mut( (*self.as_ptr()).values as *mut Value, (*self.as_ptr()).n_values as usize, ) } } } impl ops::Deref for ValueArray { type Target = [Value]; #[inline] fn deref(&self) -> &[Value] { self.as_slice() } } impl ops::DerefMut for ValueArray { #[inline] fn deref_mut(&mut self) -> &mut [Value] { self.as_mut_slice() } } impl Default for ValueArray { fn default() -> Self { Self::with_capacity(8) } } impl std::iter::FromIterator for ValueArray { fn from_iter>(iter: T) -> Self { Self::from_values(iter) } } impl std::iter::Extend for ValueArray { fn extend>(&mut self, iter: T) { for v in iter.into_iter() { self.append_value(&v); } } } // Implementing `Value` traits manually because of a custom ParamSpec impl StaticType for ValueArray { #[inline] fn static_type() -> Type { unsafe { from_glib(gobject_ffi::g_value_array_get_type()) } } } #[doc(hidden)] impl ValueType for ValueArray { type Type = Self; } #[doc(hidden)] impl crate::value::ValueTypeOptional for ValueArray {} #[doc(hidden)] unsafe impl<'a> crate::value::FromValue<'a> for ValueArray { type Checker = crate::value::GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a Value) -> Self { let ptr = gobject_ffi::g_value_dup_boxed(value.to_glib_none().0); debug_assert!(!ptr.is_null()); from_glib_full(ptr as *mut gobject_ffi::GValueArray) } } #[doc(hidden)] unsafe impl<'a> crate::value::FromValue<'a> for &'a ValueArray { type Checker = crate::value::GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a Value) -> Self { debug_assert_eq!( std::mem::size_of::(), std::mem::size_of::() ); let value = &*(value as *const Value as *const gobject_ffi::GValue); debug_assert!(!value.data[0].v_pointer.is_null()); ::from_glib_ptr_borrow( &*(&value.data[0].v_pointer as *const ffi::gpointer as *const *mut gobject_ffi::GValueArray), ) } } #[doc(hidden)] impl ToValue for ValueArray { #[inline] fn to_value(&self) -> Value { unsafe { let mut value = Value::from_type_unchecked(::static_type()); gobject_ffi::g_value_take_boxed( value.to_glib_none_mut().0, ToGlibPtr::<*mut gobject_ffi::GValueArray>::to_glib_full(self) as *mut _, ); value } } #[inline] fn value_type(&self) -> Type { ::static_type() } } impl std::convert::From for Value { #[inline] fn from(o: ValueArray) -> Self { unsafe { let mut value = Value::from_type_unchecked(::static_type()); gobject_ffi::g_value_take_boxed( value.to_glib_none_mut().0, IntoGlibPtr::<*mut gobject_ffi::GValueArray>::into_glib_ptr(o) as *mut _, ); value } } } #[doc(hidden)] impl crate::value::ToValueOptional for ValueArray { #[inline] fn to_value_optional(s: Option<&Self>) -> Value { let mut value = Value::for_value_type::(); unsafe { gobject_ffi::g_value_take_boxed( value.to_glib_none_mut().0, ToGlibPtr::<*mut gobject_ffi::GValueArray>::to_glib_full(&s) as *mut _, ); } value } } impl HasParamSpec for ValueArray { type ParamSpec = ParamSpecValueArray; type SetValue = Self; type BuilderFn = fn(&str) -> ParamSpecValueArrayBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } #[cfg(test)] mod tests { use super::*; #[test] fn test_new() { let arr = ValueArray::new(["123", "456"]); assert_eq!( arr.first().and_then(|v| v.get::().ok()), Some(String::from("123")) ); assert_eq!( arr.get(1).and_then(|v| v.get::().ok()), Some(String::from("456")) ); } #[test] fn test_append() { let mut arr = ValueArray::default(); arr.append("123"); arr.append(123u32); arr.append_value(&Value::from(456u64)); assert_eq!( arr.first().and_then(|v| v.get::().ok()), Some(String::from("123")) ); assert_eq!(arr.get(1).and_then(|v| v.get::().ok()), Some(123)); assert_eq!(arr.get(2).and_then(|v| v.get::().ok()), Some(456)); } } glib-0.20.9/src/variant.rs000064400000000000000000002257741046102023000134530ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! `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". //! //! `GVariant` supports arbitrarily complex types built from primitives like integers, floating point //! numbers, strings, arrays, tuples and dictionaries. See [`ToVariant#foreign-impls`] for //! a full list of supported types. You may also implement [`ToVariant`] and [`FromVariant`] //! manually, or derive them using the [`Variant`](derive@crate::Variant) derive macro. //! //! # Examples //! //! ``` //! use glib::prelude::*; // or `use gtk::prelude::*;` //! use glib::variant::{Variant, FromVariant}; //! use std::collections::HashMap; //! //! // Using the `ToVariant` trait. //! let num = 10.to_variant(); //! //! // `is` tests the type of the value. //! assert!(num.is::()); //! //! // `get` tries to extract the value. //! assert_eq!(num.get::(), Some(10)); //! assert_eq!(num.get::(), None); //! //! // `get_str` tries to borrow a string slice. //! let hello = "Hello!".to_variant(); //! assert_eq!(hello.str(), Some("Hello!")); //! assert_eq!(num.str(), None); //! //! // `fixed_array` tries to borrow a fixed size array (u8, bool, i16, etc.), //! // rather than creating a deep copy which would be expensive for //! // nontrivially sized arrays of fixed size elements. //! // The test data here is the zstd compression header, which //! // stands in for arbitrary binary data (e.g. not UTF-8). //! let bufdata = b"\xFD\x2F\xB5\x28"; //! let bufv = glib::Variant::array_from_fixed_array(&bufdata[..]); //! assert_eq!(bufv.fixed_array::().unwrap(), bufdata); //! assert!(num.fixed_array::().is_err()); //! //! // Variant carrying a Variant //! let variant = Variant::from_variant(&hello); //! let variant = variant.as_variant().unwrap(); //! assert_eq!(variant.str(), Some("Hello!")); //! //! // Variant carrying an array //! let array = ["Hello", "there!"]; //! let variant = array.into_iter().collect::(); //! assert_eq!(variant.n_children(), 2); //! assert_eq!(variant.child_value(0).str(), Some("Hello")); //! assert_eq!(variant.child_value(1).str(), Some("there!")); //! //! // You can also convert from and to a Vec //! let variant = vec!["Hello", "there!"].to_variant(); //! assert_eq!(variant.n_children(), 2); //! let vec = >::from_variant(&variant).unwrap(); //! assert_eq!(vec[0], "Hello"); //! //! // Conversion to and from HashMap and BTreeMap is also possible //! let mut map: HashMap = HashMap::new(); //! map.insert(1, "hi"); //! map.insert(2, "there"); //! let variant = map.to_variant(); //! assert_eq!(variant.n_children(), 2); //! let map: HashMap = HashMap::from_variant(&variant).unwrap(); //! assert_eq!(map[&1], "hi"); //! assert_eq!(map[&2], "there"); //! //! // And conversion to and from tuples. //! let variant = ("hello", 42u16, vec![ "there", "you" ],).to_variant(); //! assert_eq!(variant.n_children(), 3); //! assert_eq!(variant.type_().as_str(), "(sqas)"); //! let tuple = <(String, u16, Vec)>::from_variant(&variant).unwrap(); //! assert_eq!(tuple.0, "hello"); //! assert_eq!(tuple.1, 42); //! assert_eq!(tuple.2, &[ "there", "you"]); //! //! // `Option` is supported as well, through maybe types //! let variant = Some("hello").to_variant(); //! assert_eq!(variant.n_children(), 1); //! let mut s = >::from_variant(&variant).unwrap(); //! assert_eq!(s.unwrap(), "hello"); //! s = None; //! let variant = s.to_variant(); //! assert_eq!(variant.n_children(), 0); //! let s = >::from_variant(&variant).unwrap(); //! assert!(s.is_none()); //! //! // Paths may be converted, too. Please note the portability warning above! //! use std::path::{Path, PathBuf}; //! let path = Path::new("foo/bar"); //! let path_variant = path.to_variant(); //! assert_eq!(PathBuf::from_variant(&path_variant).as_deref(), Some(path)); //! ``` use std::{ borrow::Cow, cmp::Ordering, collections::{BTreeMap, HashMap}, fmt, hash::{BuildHasher, Hash, Hasher}, mem, ptr, slice, str, }; use crate::{ ffi, gobject_ffi, prelude::*, translate::*, Bytes, Type, VariantIter, VariantStrIter, VariantTy, VariantType, }; wrapper! { // rustdoc-stripper-ignore-next /// A generic immutable value capable of carrying various types. /// /// See the [module documentation](index.html) for more details. #[doc(alias = "GVariant")] pub struct Variant(Shared); match fn { ref => |ptr| ffi::g_variant_ref_sink(ptr), unref => |ptr| ffi::g_variant_unref(ptr), } } impl StaticType for Variant { #[inline] fn static_type() -> Type { Type::VARIANT } } #[doc(hidden)] impl crate::value::ValueType for Variant { type Type = Variant; } #[doc(hidden)] impl crate::value::ValueTypeOptional for Variant {} #[doc(hidden)] unsafe impl<'a> crate::value::FromValue<'a> for Variant { type Checker = crate::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a crate::Value) -> Self { let ptr = gobject_ffi::g_value_dup_variant(value.to_glib_none().0); debug_assert!(!ptr.is_null()); from_glib_full(ptr) } } #[doc(hidden)] impl crate::value::ToValue for Variant { fn to_value(&self) -> crate::Value { unsafe { let mut value = crate::Value::from_type_unchecked(Variant::static_type()); gobject_ffi::g_value_take_variant(value.to_glib_none_mut().0, self.to_glib_full()); value } } fn value_type(&self) -> crate::Type { Variant::static_type() } } #[doc(hidden)] impl From for crate::Value { #[inline] fn from(v: Variant) -> Self { unsafe { let mut value = crate::Value::from_type_unchecked(Variant::static_type()); gobject_ffi::g_value_take_variant(value.to_glib_none_mut().0, v.into_glib_ptr()); value } } } #[doc(hidden)] impl crate::value::ToValueOptional for Variant { fn to_value_optional(s: Option<&Self>) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { gobject_ffi::g_value_take_variant(value.to_glib_none_mut().0, s.to_glib_full()); } value } } // rustdoc-stripper-ignore-next /// An error returned from the [`try_get`](struct.Variant.html#method.try_get) function /// on a [`Variant`](struct.Variant.html) when the expected type does not match the actual type. #[derive(Clone, PartialEq, Eq, Debug)] pub struct VariantTypeMismatchError { pub actual: VariantType, pub expected: VariantType, } impl VariantTypeMismatchError { pub fn new(actual: VariantType, expected: VariantType) -> Self { Self { actual, expected } } } impl fmt::Display for VariantTypeMismatchError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "Type mismatch: Expected '{}' got '{}'", self.expected, self.actual ) } } impl std::error::Error for VariantTypeMismatchError {} impl Variant { // rustdoc-stripper-ignore-next /// Returns the type of the value. #[doc(alias = "g_variant_get_type")] pub fn type_(&self) -> &VariantTy { unsafe { VariantTy::from_ptr(ffi::g_variant_get_type(self.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Returns `true` if the type of the value corresponds to `T`. #[inline] #[doc(alias = "g_variant_is_of_type")] pub fn is(&self) -> bool { self.is_type(&T::static_variant_type()) } // rustdoc-stripper-ignore-next /// Returns `true` if the type of the value corresponds to `type_`. /// /// This is equivalent to [`self.type_().is_subtype_of(type_)`](VariantTy::is_subtype_of). #[inline] #[doc(alias = "g_variant_is_of_type")] pub fn is_type(&self, type_: &VariantTy) -> bool { unsafe { from_glib(ffi::g_variant_is_of_type( self.to_glib_none().0, type_.to_glib_none().0, )) } } // rustdoc-stripper-ignore-next /// Returns the classification of the variant. #[doc(alias = "g_variant_classify")] pub fn classify(&self) -> crate::VariantClass { unsafe { from_glib(ffi::g_variant_classify(self.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// 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) } // rustdoc-stripper-ignore-next /// Tries to extract a value of type `T`. pub fn try_get(&self) -> Result { self.get().ok_or_else(|| { VariantTypeMismatchError::new( self.type_().to_owned(), T::static_variant_type().into_owned(), ) }) } // rustdoc-stripper-ignore-next /// Boxes value. #[inline] pub fn from_variant(value: &Variant) -> Self { unsafe { from_glib_none(ffi::g_variant_new_variant(value.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Unboxes self. /// /// Returns `Some` if self contains a `Variant`. #[inline] #[doc(alias = "get_variant")] pub fn as_variant(&self) -> Option { unsafe { from_glib_full(ffi::g_variant_get_variant(self.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Reads a child item out of a container `Variant` instance. /// /// # Panics /// /// * if `self` is not a container type. /// * if given `index` is larger than number of children. #[doc(alias = "get_child_value")] #[doc(alias = "g_variant_get_child_value")] #[must_use] pub fn child_value(&self, index: usize) -> Variant { assert!(self.is_container()); assert!(index < self.n_children()); unsafe { from_glib_full(ffi::g_variant_get_child_value(self.to_glib_none().0, index)) } } // rustdoc-stripper-ignore-next /// Try to read a child item out of a container `Variant` instance. /// /// It returns `None` if `self` is not a container type or if the given /// `index` is larger than number of children. pub fn try_child_value(&self, index: usize) -> Option { if !(self.is_container() && index < self.n_children()) { return None; } let v = unsafe { from_glib_full(ffi::g_variant_get_child_value(self.to_glib_none().0, index)) }; Some(v) } // rustdoc-stripper-ignore-next /// Try to read a child item out of a container `Variant` instance. /// /// It returns `Ok(None)` if `self` is not a container type or if the given /// `index` is larger than number of children. An error is thrown if the /// type does not match. pub fn try_child_get( &self, index: usize, ) -> Result, VariantTypeMismatchError> { // TODO: In the future optimize this by using g_variant_get_child() // directly to avoid allocating a GVariant. self.try_child_value(index).map(|v| v.try_get()).transpose() } // rustdoc-stripper-ignore-next /// Read a child item out of a container `Variant` instance. /// /// # Panics /// /// * if `self` is not a container type. /// * if given `index` is larger than number of children. /// * if the expected variant type does not match pub fn child_get(&self, index: usize) -> T { // TODO: In the future optimize this by using g_variant_get_child() // directly to avoid allocating a GVariant. self.child_value(index).get().unwrap() } // rustdoc-stripper-ignore-next /// Tries to extract a `&str`. /// /// Returns `Some` if the variant has a string type (`s`, `o` or `g` type /// strings). #[doc(alias = "get_str")] #[doc(alias = "g_variant_get_string")] pub fn str(&self) -> Option<&str> { unsafe { match self.type_().as_str() { "s" | "o" | "g" => { let mut len = 0; let ptr = ffi::g_variant_get_string(self.to_glib_none().0, &mut len); if len == 0 { Some("") } else { let ret = str::from_utf8_unchecked(slice::from_raw_parts( ptr as *const u8, len as _, )); Some(ret) } } _ => None, } } } // rustdoc-stripper-ignore-next /// Tries to extract a `&[T]` from a variant of array type with a suitable element type. /// /// Returns an error if the type is wrong. #[doc(alias = "g_variant_get_fixed_array")] pub fn fixed_array(&self) -> Result<&[T], VariantTypeMismatchError> { unsafe { let expected_ty = T::static_variant_type().as_array(); if self.type_() != expected_ty { return Err(VariantTypeMismatchError { actual: self.type_().to_owned(), expected: expected_ty.into_owned(), }); } let mut n_elements = mem::MaybeUninit::uninit(); let ptr = ffi::g_variant_get_fixed_array( self.to_glib_none().0, n_elements.as_mut_ptr(), mem::size_of::(), ); let n_elements = n_elements.assume_init(); if n_elements == 0 { Ok(&[]) } else { debug_assert!(!ptr.is_null()); Ok(slice::from_raw_parts(ptr as *const T, n_elements)) } } } // rustdoc-stripper-ignore-next /// Creates a new Variant array from children. /// /// # Panics /// /// This function panics if not all variants are of type `T`. #[doc(alias = "g_variant_new_array")] pub fn array_from_iter( children: impl IntoIterator, ) -> Self { Self::array_from_iter_with_type(&T::static_variant_type(), children) } // rustdoc-stripper-ignore-next /// Creates a new Variant array from children with the specified type. /// /// # Panics /// /// This function panics if not all variants are of type `type_`. #[doc(alias = "g_variant_new_array")] pub fn array_from_iter_with_type( type_: &VariantTy, children: impl IntoIterator>, ) -> Self { unsafe { let mut builder = mem::MaybeUninit::uninit(); ffi::g_variant_builder_init(builder.as_mut_ptr(), type_.as_array().to_glib_none().0); let mut builder = builder.assume_init(); for value in children.into_iter() { let value = value.as_ref(); if ffi::g_variant_is_of_type(value.to_glib_none().0, type_.to_glib_none().0) == ffi::GFALSE { ffi::g_variant_builder_clear(&mut builder); assert!(value.is_type(type_)); } ffi::g_variant_builder_add_value(&mut builder, value.to_glib_none().0); } from_glib_none(ffi::g_variant_builder_end(&mut builder)) } } // rustdoc-stripper-ignore-next /// Creates a new Variant array from a fixed array. #[doc(alias = "g_variant_new_fixed_array")] pub fn array_from_fixed_array(array: &[T]) -> Self { let type_ = T::static_variant_type(); unsafe { from_glib_none(ffi::g_variant_new_fixed_array( type_.as_ptr(), array.as_ptr() as ffi::gconstpointer, array.len(), mem::size_of::(), )) } } // rustdoc-stripper-ignore-next /// Creates a new Variant tuple from children. #[doc(alias = "g_variant_new_tuple")] pub fn tuple_from_iter(children: impl IntoIterator>) -> Self { unsafe { let mut builder = mem::MaybeUninit::uninit(); ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::TUPLE.to_glib_none().0); let mut builder = builder.assume_init(); for value in children.into_iter() { ffi::g_variant_builder_add_value(&mut builder, value.as_ref().to_glib_none().0); } from_glib_none(ffi::g_variant_builder_end(&mut builder)) } } // rustdoc-stripper-ignore-next /// Creates a new dictionary entry Variant. /// /// [DictEntry] should be preferred over this when the types are known statically. #[doc(alias = "g_variant_new_dict_entry")] pub fn from_dict_entry(key: &Variant, value: &Variant) -> Self { unsafe { from_glib_none(ffi::g_variant_new_dict_entry( key.to_glib_none().0, value.to_glib_none().0, )) } } // rustdoc-stripper-ignore-next /// Creates a new maybe Variant. #[doc(alias = "g_variant_new_maybe")] pub fn from_maybe(child: Option<&Variant>) -> Self { let type_ = T::static_variant_type(); match child { Some(child) => { assert_eq!(type_, child.type_()); Self::from_some(child) } None => Self::from_none(&type_), } } // rustdoc-stripper-ignore-next /// Creates a new maybe Variant from a child. #[doc(alias = "g_variant_new_maybe")] pub fn from_some(child: &Variant) -> Self { unsafe { from_glib_none(ffi::g_variant_new_maybe( ptr::null(), child.to_glib_none().0, )) } } // rustdoc-stripper-ignore-next /// Creates a new maybe Variant with Nothing. #[doc(alias = "g_variant_new_maybe")] pub fn from_none(type_: &VariantTy) -> Self { unsafe { from_glib_none(ffi::g_variant_new_maybe( type_.to_glib_none().0, ptr::null_mut(), )) } } // rustdoc-stripper-ignore-next /// Extract the value of a maybe Variant. /// /// Returns the child value, or `None` if the value is Nothing. /// /// # Panics /// /// Panics if the variant is not maybe-typed. #[inline] pub fn as_maybe(&self) -> Option { assert!(self.type_().is_maybe()); unsafe { from_glib_full(ffi::g_variant_get_maybe(self.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Pretty-print the contents of this variant in a human-readable form. /// /// A variant can be recreated from this output via [`Variant::parse`]. #[doc(alias = "g_variant_print")] pub fn print(&self, type_annotate: bool) -> crate::GString { unsafe { from_glib_full(ffi::g_variant_print( self.to_glib_none().0, type_annotate.into_glib(), )) } } // rustdoc-stripper-ignore-next /// Parses a GVariant from the text representation produced by [`print()`](Self::print). #[doc(alias = "g_variant_parse")] pub fn parse(type_: Option<&VariantTy>, text: &str) -> Result { unsafe { let mut error = ptr::null_mut(); let text = text.as_bytes().as_ptr_range(); let variant = ffi::g_variant_parse( type_.to_glib_none().0, text.start as *const _, text.end as *const _, ptr::null_mut(), &mut error, ); if variant.is_null() { debug_assert!(!error.is_null()); Err(from_glib_full(error)) } else { debug_assert!(error.is_null()); Ok(from_glib_full(variant)) } } } // rustdoc-stripper-ignore-next /// Constructs a new serialized-mode GVariant instance. #[doc(alias = "g_variant_new_from_bytes")] pub fn from_bytes(bytes: &Bytes) -> Self { Variant::from_bytes_with_type(bytes, &T::static_variant_type()) } // rustdoc-stripper-ignore-next /// Constructs a new serialized-mode GVariant instance. /// /// This is the same as `from_bytes`, except that checks on the passed /// data are skipped. /// /// You should not use this function on data from external sources. /// /// # Safety /// /// Since the data is not validated, this is potentially dangerous if called /// on bytes which are not guaranteed to have come from serialising another /// Variant. The caller is responsible for ensuring bad data is not passed in. pub unsafe fn from_bytes_trusted(bytes: &Bytes) -> Self { Variant::from_bytes_with_type_trusted(bytes, &T::static_variant_type()) } // rustdoc-stripper-ignore-next /// Constructs a new serialized-mode GVariant instance. #[doc(alias = "g_variant_new_from_data")] pub fn from_data>(data: A) -> Self { Variant::from_data_with_type(data, &T::static_variant_type()) } // rustdoc-stripper-ignore-next /// Constructs a new serialized-mode GVariant instance. /// /// This is the same as `from_data`, except that checks on the passed /// data are skipped. /// /// You should not use this function on data from external sources. /// /// # Safety /// /// Since the data is not validated, this is potentially dangerous if called /// on bytes which are not guaranteed to have come from serialising another /// Variant. The caller is responsible for ensuring bad data is not passed in. pub unsafe fn from_data_trusted>(data: A) -> Self { Variant::from_data_with_type_trusted(data, &T::static_variant_type()) } // rustdoc-stripper-ignore-next /// Constructs a new serialized-mode GVariant instance with a given type. #[doc(alias = "g_variant_new_from_bytes")] pub fn from_bytes_with_type(bytes: &Bytes, type_: &VariantTy) -> Self { unsafe { from_glib_none(ffi::g_variant_new_from_bytes( type_.as_ptr() as *const _, bytes.to_glib_none().0, false.into_glib(), )) } } // rustdoc-stripper-ignore-next /// Constructs a new serialized-mode GVariant instance with a given type. /// /// This is the same as `from_bytes`, except that checks on the passed /// data are skipped. /// /// You should not use this function on data from external sources. /// /// # Safety /// /// Since the data is not validated, this is potentially dangerous if called /// on bytes which are not guaranteed to have come from serialising another /// Variant. The caller is responsible for ensuring bad data is not passed in. pub unsafe fn from_bytes_with_type_trusted(bytes: &Bytes, type_: &VariantTy) -> Self { from_glib_none(ffi::g_variant_new_from_bytes( type_.as_ptr() as *const _, bytes.to_glib_none().0, true.into_glib(), )) } // rustdoc-stripper-ignore-next /// Constructs a new serialized-mode GVariant instance with a given type. #[doc(alias = "g_variant_new_from_data")] pub fn from_data_with_type>(data: A, type_: &VariantTy) -> Self { unsafe { let data = Box::new(data); let (data_ptr, len) = { let data = (*data).as_ref(); (data.as_ptr(), data.len()) }; unsafe extern "C" fn free_data>(ptr: ffi::gpointer) { let _ = Box::from_raw(ptr as *mut A); } from_glib_none(ffi::g_variant_new_from_data( type_.as_ptr() as *const _, data_ptr as ffi::gconstpointer, len, false.into_glib(), Some(free_data::), Box::into_raw(data) as ffi::gpointer, )) } } // rustdoc-stripper-ignore-next /// Constructs a new serialized-mode GVariant instance with a given type. /// /// This is the same as `from_data`, except that checks on the passed /// data are skipped. /// /// You should not use this function on data from external sources. /// /// # Safety /// /// Since the data is not validated, this is potentially dangerous if called /// on bytes which are not guaranteed to have come from serialising another /// Variant. The caller is responsible for ensuring bad data is not passed in. pub unsafe fn from_data_with_type_trusted>(data: A, type_: &VariantTy) -> Self { let data = Box::new(data); let (data_ptr, len) = { let data = (*data).as_ref(); (data.as_ptr(), data.len()) }; unsafe extern "C" fn free_data>(ptr: ffi::gpointer) { let _ = Box::from_raw(ptr as *mut A); } from_glib_none(ffi::g_variant_new_from_data( type_.as_ptr() as *const _, data_ptr as ffi::gconstpointer, len, true.into_glib(), Some(free_data::), Box::into_raw(data) as ffi::gpointer, )) } // rustdoc-stripper-ignore-next /// Returns the serialized form of a GVariant instance. #[doc(alias = "get_data_as_bytes")] #[doc(alias = "g_variant_get_data_as_bytes")] pub fn data_as_bytes(&self) -> Bytes { unsafe { from_glib_full(ffi::g_variant_get_data_as_bytes(self.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Returns the serialized form of a GVariant instance. #[doc(alias = "g_variant_get_data")] pub fn data(&self) -> &[u8] { unsafe { let selfv = self.to_glib_none(); let len = ffi::g_variant_get_size(selfv.0); if len == 0 { return &[]; } let ptr = ffi::g_variant_get_data(selfv.0); slice::from_raw_parts(ptr as *const _, len as _) } } // rustdoc-stripper-ignore-next /// Returns the size of serialized form of a GVariant instance. #[doc(alias = "g_variant_get_size")] pub fn size(&self) -> usize { unsafe { ffi::g_variant_get_size(self.to_glib_none().0) } } // rustdoc-stripper-ignore-next /// Stores the serialized form of a GVariant instance into the given slice. /// /// The slice needs to be big enough. #[doc(alias = "g_variant_store")] pub fn store(&self, data: &mut [u8]) -> Result { unsafe { let size = ffi::g_variant_get_size(self.to_glib_none().0); if data.len() < size { return Err(bool_error!("Provided slice is too small")); } ffi::g_variant_store(self.to_glib_none().0, data.as_mut_ptr() as ffi::gpointer); Ok(size) } } // rustdoc-stripper-ignore-next /// Returns a copy of the variant in normal form. #[doc(alias = "g_variant_get_normal_form")] #[must_use] pub fn normal_form(&self) -> Self { unsafe { from_glib_full(ffi::g_variant_get_normal_form(self.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Returns a copy of the variant in the opposite endianness. #[doc(alias = "g_variant_byteswap")] #[must_use] pub fn byteswap(&self) -> Self { unsafe { from_glib_full(ffi::g_variant_byteswap(self.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Determines the number of children in a container GVariant instance. #[doc(alias = "g_variant_n_children")] pub fn n_children(&self) -> usize { assert!(self.is_container()); unsafe { ffi::g_variant_n_children(self.to_glib_none().0) } } // rustdoc-stripper-ignore-next /// Create an iterator over items in the variant. /// /// Note that this heap allocates a variant for each element, /// which can be particularly expensive for large arrays. pub fn iter(&self) -> VariantIter { assert!(self.is_container()); VariantIter::new(self.clone()) } // rustdoc-stripper-ignore-next /// Create an iterator over borrowed strings from a GVariant of type `as` (array of string). /// /// This will fail if the variant is not an array of with /// the expected child type. /// /// A benefit of this API over [`Self::iter()`] is that it /// minimizes allocation, and provides strongly typed access. /// /// ``` /// # use glib::prelude::*; /// let strs = &["foo", "bar"]; /// let strs_variant: glib::Variant = strs.to_variant(); /// for s in strs_variant.array_iter_str()? { /// println!("{}", s); /// } /// # Ok::<(), Box>(()) /// ``` pub fn array_iter_str(&self) -> Result { let child_ty = String::static_variant_type(); let actual_ty = self.type_(); let expected_ty = child_ty.as_array(); if actual_ty != expected_ty { return Err(VariantTypeMismatchError { actual: actual_ty.to_owned(), expected: expected_ty.into_owned(), }); } Ok(VariantStrIter::new(self)) } // rustdoc-stripper-ignore-next /// Return whether this Variant is a container type. #[doc(alias = "g_variant_is_container")] pub fn is_container(&self) -> bool { unsafe { from_glib(ffi::g_variant_is_container(self.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Return whether this Variant is in normal form. #[doc(alias = "g_variant_is_normal_form")] pub fn is_normal_form(&self) -> bool { unsafe { from_glib(ffi::g_variant_is_normal_form(self.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Return whether input string is a valid `VariantClass::ObjectPath`. #[doc(alias = "g_variant_is_object_path")] pub fn is_object_path(string: &str) -> bool { unsafe { from_glib(ffi::g_variant_is_object_path(string.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Return whether input string is a valid `VariantClass::Signature`. #[doc(alias = "g_variant_is_signature")] pub fn is_signature(string: &str) -> bool { unsafe { from_glib(ffi::g_variant_is_signature(string.to_glib_none().0)) } } } 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", &ToGlibPtr::<*const _>::to_glib_none(self).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 { f.write_str(&self.print(true)) } } impl str::FromStr for Variant { type Err = crate::Error; fn from_str(s: &str) -> Result { Self::parse(None, s) } } impl PartialEq for Variant { #[doc(alias = "g_variant_equal")] fn eq(&self, other: &Self) -> bool { unsafe { from_glib(ffi::g_variant_equal( ToGlibPtr::<*const _>::to_glib_none(self).0 as *const _, ToGlibPtr::<*const _>::to_glib_none(other).0 as *const _, )) } } } impl Eq for Variant {} impl PartialOrd for Variant { fn partial_cmp(&self, other: &Self) -> Option { unsafe { if ffi::g_variant_classify(self.to_glib_none().0) != ffi::g_variant_classify(other.to_glib_none().0) { return None; } if self.is_container() { return None; } let res = ffi::g_variant_compare( ToGlibPtr::<*const _>::to_glib_none(self).0 as *const _, ToGlibPtr::<*const _>::to_glib_none(other).0 as *const _, ); Some(res.cmp(&0)) } } } impl Hash for Variant { #[doc(alias = "g_variant_hash")] fn hash(&self, state: &mut H) { unsafe { state.write_u32(ffi::g_variant_hash( ToGlibPtr::<*const _>::to_glib_none(self).0 as *const _, )) } } } impl AsRef for Variant { #[inline] fn as_ref(&self) -> &Self { self } } // rustdoc-stripper-ignore-next /// Converts to `Variant`. pub trait ToVariant { // rustdoc-stripper-ignore-next /// Returns a `Variant` clone of `self`. fn to_variant(&self) -> Variant; } // rustdoc-stripper-ignore-next /// Extracts a value. pub trait FromVariant: Sized + StaticVariantType { // rustdoc-stripper-ignore-next /// Tries to extract a value. /// /// Returns `Some` if the variant's type matches `Self`. fn from_variant(variant: &Variant) -> Option; } // rustdoc-stripper-ignore-next /// Returns `VariantType` of `Self`. pub trait StaticVariantType { // rustdoc-stripper-ignore-next /// Returns the `VariantType` corresponding to `Self`. fn static_variant_type() -> Cow<'static, VariantTy>; } impl StaticVariantType for Variant { fn static_variant_type() -> Cow<'static, VariantTy> { Cow::Borrowed(VariantTy::VARIANT) } } impl ToVariant for &T { fn to_variant(&self) -> Variant { ::to_variant(self) } } impl<'a, T: Into + Clone> From<&'a T> for Variant { #[inline] fn from(v: &'a T) -> Self { v.clone().into() } } impl StaticVariantType for &T { fn static_variant_type() -> Cow<'static, VariantTy> { ::static_variant_type() } } macro_rules! impl_numeric { ($name:ty, $typ:expr, $new_fn:ident, $get_fn:ident) => { impl StaticVariantType for $name { fn static_variant_type() -> Cow<'static, VariantTy> { Cow::Borrowed($typ) } } impl ToVariant for $name { fn to_variant(&self) -> Variant { unsafe { from_glib_none(ffi::$new_fn(*self)) } } } impl From<$name> for Variant { #[inline] fn from(v: $name) -> Self { v.to_variant() } } impl FromVariant for $name { fn from_variant(variant: &Variant) -> Option { unsafe { if variant.is::() { Some(ffi::$get_fn(variant.to_glib_none().0)) } else { None } } } } }; } impl_numeric!(u8, VariantTy::BYTE, g_variant_new_byte, g_variant_get_byte); impl_numeric!( i16, VariantTy::INT16, g_variant_new_int16, g_variant_get_int16 ); impl_numeric!( u16, VariantTy::UINT16, g_variant_new_uint16, g_variant_get_uint16 ); impl_numeric!( i32, VariantTy::INT32, g_variant_new_int32, g_variant_get_int32 ); impl_numeric!( u32, VariantTy::UINT32, g_variant_new_uint32, g_variant_get_uint32 ); impl_numeric!( i64, VariantTy::INT64, g_variant_new_int64, g_variant_get_int64 ); impl_numeric!( u64, VariantTy::UINT64, g_variant_new_uint64, g_variant_get_uint64 ); impl_numeric!( f64, VariantTy::DOUBLE, g_variant_new_double, g_variant_get_double ); impl StaticVariantType for () { fn static_variant_type() -> Cow<'static, VariantTy> { Cow::Borrowed(VariantTy::UNIT) } } impl ToVariant for () { fn to_variant(&self) -> Variant { unsafe { from_glib_none(ffi::g_variant_new_tuple(ptr::null(), 0)) } } } impl From<()> for Variant { #[inline] fn from(_: ()) -> Self { ().to_variant() } } impl FromVariant for () { fn from_variant(variant: &Variant) -> Option { if variant.is::() { Some(()) } else { None } } } impl StaticVariantType for bool { fn static_variant_type() -> Cow<'static, VariantTy> { Cow::Borrowed(VariantTy::BOOLEAN) } } impl ToVariant for bool { fn to_variant(&self) -> Variant { unsafe { from_glib_none(ffi::g_variant_new_boolean(self.into_glib())) } } } impl From for Variant { #[inline] fn from(v: bool) -> Self { v.to_variant() } } impl FromVariant for bool { fn from_variant(variant: &Variant) -> Option { unsafe { if variant.is::() { Some(from_glib(ffi::g_variant_get_boolean( variant.to_glib_none().0, ))) } else { None } } } } impl StaticVariantType for String { fn static_variant_type() -> Cow<'static, VariantTy> { Cow::Borrowed(VariantTy::STRING) } } impl ToVariant for String { fn to_variant(&self) -> Variant { self[..].to_variant() } } impl From for Variant { #[inline] fn from(s: String) -> Self { s.to_variant() } } impl FromVariant for String { fn from_variant(variant: &Variant) -> Option { variant.str().map(String::from) } } impl StaticVariantType for str { fn static_variant_type() -> Cow<'static, VariantTy> { String::static_variant_type() } } impl ToVariant for str { fn to_variant(&self) -> Variant { unsafe { from_glib_none(ffi::g_variant_new_take_string(self.to_glib_full())) } } } impl From<&str> for Variant { #[inline] fn from(s: &str) -> Self { s.to_variant() } } impl StaticVariantType for std::path::PathBuf { fn static_variant_type() -> Cow<'static, VariantTy> { std::path::Path::static_variant_type() } } impl ToVariant for std::path::PathBuf { fn to_variant(&self) -> Variant { self.as_path().to_variant() } } impl From for Variant { #[inline] fn from(p: std::path::PathBuf) -> Self { p.to_variant() } } impl FromVariant for std::path::PathBuf { fn from_variant(variant: &Variant) -> Option { unsafe { let ptr = ffi::g_variant_get_bytestring(variant.to_glib_none().0); Some(crate::translate::c_to_path_buf(ptr as *const _)) } } } impl StaticVariantType for std::path::Path { fn static_variant_type() -> Cow<'static, VariantTy> { <&[u8]>::static_variant_type() } } impl ToVariant for std::path::Path { fn to_variant(&self) -> Variant { let tmp = crate::translate::path_to_c(self); unsafe { from_glib_none(ffi::g_variant_new_bytestring(tmp.as_ptr() as *const u8)) } } } impl From<&std::path::Path> for Variant { #[inline] fn from(p: &std::path::Path) -> Self { p.to_variant() } } impl StaticVariantType for std::ffi::OsString { fn static_variant_type() -> Cow<'static, VariantTy> { std::ffi::OsStr::static_variant_type() } } impl ToVariant for std::ffi::OsString { fn to_variant(&self) -> Variant { self.as_os_str().to_variant() } } impl From for Variant { #[inline] fn from(s: std::ffi::OsString) -> Self { s.to_variant() } } impl FromVariant for std::ffi::OsString { fn from_variant(variant: &Variant) -> Option { unsafe { let ptr = ffi::g_variant_get_bytestring(variant.to_glib_none().0); Some(crate::translate::c_to_os_string(ptr as *const _)) } } } impl StaticVariantType for std::ffi::OsStr { fn static_variant_type() -> Cow<'static, VariantTy> { <&[u8]>::static_variant_type() } } impl ToVariant for std::ffi::OsStr { fn to_variant(&self) -> Variant { let tmp = crate::translate::os_str_to_c(self); unsafe { from_glib_none(ffi::g_variant_new_bytestring(tmp.as_ptr() as *const u8)) } } } impl From<&std::ffi::OsStr> for Variant { #[inline] fn from(s: &std::ffi::OsStr) -> Self { s.to_variant() } } impl StaticVariantType for Option { fn static_variant_type() -> Cow<'static, VariantTy> { Cow::Owned(VariantType::new_maybe(&T::static_variant_type())) } } impl ToVariant for Option { fn to_variant(&self) -> Variant { Variant::from_maybe::(self.as_ref().map(|m| m.to_variant()).as_ref()) } } impl> From> for Variant { #[inline] fn from(v: Option) -> Self { Variant::from_maybe::(v.map(|v| v.into()).as_ref()) } } impl FromVariant for Option { fn from_variant(variant: &Variant) -> Option { unsafe { if variant.is::() { let c_child = ffi::g_variant_get_maybe(variant.to_glib_none().0); if !c_child.is_null() { let child: Variant = from_glib_full(c_child); Some(T::from_variant(&child)) } else { Some(None) } } else { None } } } } impl StaticVariantType for [T] { fn static_variant_type() -> Cow<'static, VariantTy> { T::static_variant_type().as_array() } } impl ToVariant for [T] { fn to_variant(&self) -> Variant { unsafe { if self.is_empty() { return from_glib_none(ffi::g_variant_new_array( T::static_variant_type().to_glib_none().0, ptr::null(), 0, )); } let mut builder = mem::MaybeUninit::uninit(); ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::ARRAY.to_glib_none().0); let mut builder = builder.assume_init(); for value in self { let value = value.to_variant(); ffi::g_variant_builder_add_value(&mut builder, value.to_glib_none().0); } from_glib_none(ffi::g_variant_builder_end(&mut builder)) } } } impl From<&[T]> for Variant { #[inline] fn from(s: &[T]) -> Self { s.to_variant() } } impl FromVariant for Vec { fn from_variant(variant: &Variant) -> Option { if !variant.is_container() { return None; } let mut vec = Vec::with_capacity(variant.n_children()); for i in 0..variant.n_children() { match variant.child_value(i).get() { Some(child) => vec.push(child), None => return None, } } Some(vec) } } impl ToVariant for Vec { fn to_variant(&self) -> Variant { self.as_slice().to_variant() } } impl> From> for Variant { fn from(v: Vec) -> Self { unsafe { if v.is_empty() { return from_glib_none(ffi::g_variant_new_array( T::static_variant_type().to_glib_none().0, ptr::null(), 0, )); } let mut builder = mem::MaybeUninit::uninit(); ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::ARRAY.to_glib_none().0); let mut builder = builder.assume_init(); for value in v { let value = value.into(); ffi::g_variant_builder_add_value(&mut builder, value.to_glib_none().0); } from_glib_none(ffi::g_variant_builder_end(&mut builder)) } } } impl StaticVariantType for Vec { fn static_variant_type() -> Cow<'static, VariantTy> { <[T]>::static_variant_type() } } impl FromVariant for HashMap where K: FromVariant + Eq + Hash, V: FromVariant, H: BuildHasher + Default, { fn from_variant(variant: &Variant) -> Option { if !variant.is_container() { return None; } let mut map = HashMap::default(); for i in 0..variant.n_children() { let entry = variant.child_value(i); let key = entry.child_value(0).get()?; let val = entry.child_value(1).get()?; map.insert(key, val); } Some(map) } } impl FromVariant for BTreeMap where K: FromVariant + Eq + Ord, V: FromVariant, { fn from_variant(variant: &Variant) -> Option { if !variant.is_container() { return None; } let mut map = BTreeMap::default(); for i in 0..variant.n_children() { let entry = variant.child_value(i); let key = entry.child_value(0).get()?; let val = entry.child_value(1).get()?; map.insert(key, val); } Some(map) } } impl ToVariant for HashMap where K: StaticVariantType + ToVariant + Eq + Hash, V: StaticVariantType + ToVariant, { fn to_variant(&self) -> Variant { unsafe { if self.is_empty() { return from_glib_none(ffi::g_variant_new_array( DictEntry::::static_variant_type().to_glib_none().0, ptr::null(), 0, )); } let mut builder = mem::MaybeUninit::uninit(); ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::ARRAY.to_glib_none().0); let mut builder = builder.assume_init(); for (key, value) in self { let entry = DictEntry::new(key, value).to_variant(); ffi::g_variant_builder_add_value(&mut builder, entry.to_glib_none().0); } from_glib_none(ffi::g_variant_builder_end(&mut builder)) } } } impl From> for Variant where K: StaticVariantType + Into + Eq + Hash, V: StaticVariantType + Into, { fn from(m: HashMap) -> Self { unsafe { if m.is_empty() { return from_glib_none(ffi::g_variant_new_array( DictEntry::::static_variant_type().to_glib_none().0, ptr::null(), 0, )); } let mut builder = mem::MaybeUninit::uninit(); ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::ARRAY.to_glib_none().0); let mut builder = builder.assume_init(); for (key, value) in m { let entry = Variant::from(DictEntry::new(key, value)); ffi::g_variant_builder_add_value(&mut builder, entry.to_glib_none().0); } from_glib_none(ffi::g_variant_builder_end(&mut builder)) } } } impl ToVariant for BTreeMap where K: StaticVariantType + ToVariant + Eq + Hash, V: StaticVariantType + ToVariant, { fn to_variant(&self) -> Variant { unsafe { if self.is_empty() { return from_glib_none(ffi::g_variant_new_array( DictEntry::::static_variant_type().to_glib_none().0, ptr::null(), 0, )); } let mut builder = mem::MaybeUninit::uninit(); ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::ARRAY.to_glib_none().0); let mut builder = builder.assume_init(); for (key, value) in self { let entry = DictEntry::new(key, value).to_variant(); ffi::g_variant_builder_add_value(&mut builder, entry.to_glib_none().0); } from_glib_none(ffi::g_variant_builder_end(&mut builder)) } } } impl From> for Variant where K: StaticVariantType + Into + Eq + Hash, V: StaticVariantType + Into, { fn from(m: BTreeMap) -> Self { unsafe { if m.is_empty() { return from_glib_none(ffi::g_variant_new_array( DictEntry::::static_variant_type().to_glib_none().0, ptr::null(), 0, )); } let mut builder = mem::MaybeUninit::uninit(); ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::ARRAY.to_glib_none().0); let mut builder = builder.assume_init(); for (key, value) in m { let entry = Variant::from(DictEntry::new(key, value)); ffi::g_variant_builder_add_value(&mut builder, entry.to_glib_none().0); } from_glib_none(ffi::g_variant_builder_end(&mut builder)) } } } /// A Dictionary entry. /// /// While GVariant format allows a dictionary entry to be an independent type, typically you'll need /// to use this in a dictionary, which is simply an array of dictionary entries. The following code /// creates a dictionary: /// /// ``` ///# use glib::prelude::*; // or `use gtk::prelude::*;` /// use glib::variant::{Variant, FromVariant, DictEntry}; /// /// let entries = [ /// DictEntry::new("uuid", 1000u32), /// DictEntry::new("guid", 1001u32), /// ]; /// let dict = entries.into_iter().collect::(); /// assert_eq!(dict.n_children(), 2); /// assert_eq!(dict.type_().as_str(), "a{su}"); /// ``` pub struct DictEntry { key: K, value: V, } impl DictEntry where K: StaticVariantType, V: StaticVariantType, { pub fn new(key: K, value: V) -> Self { Self { key, value } } pub fn key(&self) -> &K { &self.key } pub fn value(&self) -> &V { &self.value } } impl FromVariant for DictEntry where K: FromVariant, V: FromVariant, { fn from_variant(variant: &Variant) -> Option { if !variant.type_().is_subtype_of(VariantTy::DICT_ENTRY) { return None; } let key = variant.child_value(0).get()?; let value = variant.child_value(1).get()?; Some(Self { key, value }) } } impl ToVariant for DictEntry where K: StaticVariantType + ToVariant, V: StaticVariantType + ToVariant, { fn to_variant(&self) -> Variant { Variant::from_dict_entry(&self.key.to_variant(), &self.value.to_variant()) } } impl From> for Variant where K: StaticVariantType + Into, V: StaticVariantType + Into, { fn from(e: DictEntry) -> Self { Variant::from_dict_entry(&e.key.into(), &e.value.into()) } } impl ToVariant for Variant { fn to_variant(&self) -> Variant { Variant::from_variant(self) } } impl FromVariant for Variant { fn from_variant(variant: &Variant) -> Option { variant.as_variant() } } impl StaticVariantType for DictEntry { fn static_variant_type() -> Cow<'static, VariantTy> { Cow::Owned(VariantType::new_dict_entry( &K::static_variant_type(), &V::static_variant_type(), )) } } fn static_variant_mapping() -> Cow<'static, VariantTy> where K: StaticVariantType, V: StaticVariantType, { use std::fmt::Write; let key_type = K::static_variant_type(); let value_type = V::static_variant_type(); if key_type == VariantTy::STRING && value_type == VariantTy::VARIANT { return Cow::Borrowed(VariantTy::VARDICT); } let mut builder = crate::GStringBuilder::default(); write!(builder, "a{{{}{}}}", key_type.as_str(), value_type.as_str()).unwrap(); Cow::Owned(VariantType::from_string(builder.into_string()).unwrap()) } impl StaticVariantType for HashMap where K: StaticVariantType, V: StaticVariantType, H: BuildHasher + Default, { fn static_variant_type() -> Cow<'static, VariantTy> { static_variant_mapping::() } } impl StaticVariantType for BTreeMap where K: StaticVariantType, V: StaticVariantType, { fn static_variant_type() -> Cow<'static, VariantTy> { static_variant_mapping::() } } macro_rules! tuple_impls { ($($len:expr => ($($n:tt $name:ident)+))+) => { $( impl<$($name),+> StaticVariantType for ($($name,)+) where $($name: StaticVariantType,)+ { fn static_variant_type() -> Cow<'static, VariantTy> { Cow::Owned(VariantType::new_tuple(&[ $( $name::static_variant_type(), )+ ])) } } impl<$($name),+> FromVariant for ($($name,)+) where $($name: FromVariant,)+ { fn from_variant(variant: &Variant) -> Option { if !variant.type_().is_subtype_of(VariantTy::TUPLE) { return None; } Some(( $( match variant.try_child_get::<$name>($n) { Ok(Some(field)) => field, _ => return None, }, )+ )) } } impl<$($name),+> ToVariant for ($($name,)+) where $($name: ToVariant,)+ { fn to_variant(&self) -> Variant { unsafe { let mut builder = mem::MaybeUninit::uninit(); ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::TUPLE.to_glib_none().0); let mut builder = builder.assume_init(); $( let field = self.$n.to_variant(); ffi::g_variant_builder_add_value(&mut builder, field.to_glib_none().0); )+ from_glib_none(ffi::g_variant_builder_end(&mut builder)) } } } impl<$($name),+> From<($($name,)+)> for Variant where $($name: Into,)+ { fn from(t: ($($name,)+)) -> Self { unsafe { let mut builder = mem::MaybeUninit::uninit(); ffi::g_variant_builder_init(builder.as_mut_ptr(), VariantTy::TUPLE.to_glib_none().0); let mut builder = builder.assume_init(); $( let field = t.$n.into(); ffi::g_variant_builder_add_value(&mut builder, field.to_glib_none().0); )+ from_glib_none(ffi::g_variant_builder_end(&mut builder)) } } } )+ } } tuple_impls! { 1 => (0 T0) 2 => (0 T0 1 T1) 3 => (0 T0 1 T1 2 T2) 4 => (0 T0 1 T1 2 T2 3 T3) 5 => (0 T0 1 T1 2 T2 3 T3 4 T4) 6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5) 7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6) 8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7) 9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8) 10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9) 11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10) 12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11) 13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12) 14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13) 15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14) 16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15) } impl + StaticVariantType> FromIterator for Variant { fn from_iter>(iter: I) -> Self { Variant::array_from_iter::(iter.into_iter().map(|v| v.into())) } } /// Trait for fixed size variant types. pub unsafe trait FixedSizeVariantType: StaticVariantType + Sized + Copy {} unsafe impl FixedSizeVariantType for u8 {} unsafe impl FixedSizeVariantType for i16 {} unsafe impl FixedSizeVariantType for u16 {} unsafe impl FixedSizeVariantType for i32 {} unsafe impl FixedSizeVariantType for u32 {} unsafe impl FixedSizeVariantType for i64 {} unsafe impl FixedSizeVariantType for u64 {} unsafe impl FixedSizeVariantType for f64 {} unsafe impl FixedSizeVariantType for bool {} /// Wrapper type for fixed size type arrays. /// /// Converting this from/to a `Variant` is generally more efficient than working on the type /// directly. This is especially important when deriving `Variant` trait implementations on custom /// types. /// /// This wrapper type can hold for example `Vec`, `Box<[u8]>` and similar types. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct FixedSizeVariantArray(A, std::marker::PhantomData) where A: AsRef<[T]>, T: FixedSizeVariantType; impl, T: FixedSizeVariantType> From for FixedSizeVariantArray { fn from(array: A) -> Self { FixedSizeVariantArray(array, std::marker::PhantomData) } } impl, T: FixedSizeVariantType> FixedSizeVariantArray { pub fn into_inner(self) -> A { self.0 } } impl, T: FixedSizeVariantType> std::ops::Deref for FixedSizeVariantArray { type Target = A; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } impl, T: FixedSizeVariantType> std::ops::DerefMut for FixedSizeVariantArray { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl, T: FixedSizeVariantType> AsRef for FixedSizeVariantArray { #[inline] fn as_ref(&self) -> &A { &self.0 } } impl, T: FixedSizeVariantType> AsMut for FixedSizeVariantArray { #[inline] fn as_mut(&mut self) -> &mut A { &mut self.0 } } impl, T: FixedSizeVariantType> AsRef<[T]> for FixedSizeVariantArray { #[inline] fn as_ref(&self) -> &[T] { self.0.as_ref() } } impl + AsMut<[T]>, T: FixedSizeVariantType> AsMut<[T]> for FixedSizeVariantArray { #[inline] fn as_mut(&mut self) -> &mut [T] { self.0.as_mut() } } impl, T: FixedSizeVariantType> StaticVariantType for FixedSizeVariantArray { fn static_variant_type() -> Cow<'static, VariantTy> { <[T]>::static_variant_type() } } impl + for<'a> From<&'a [T]>, T: FixedSizeVariantType> FromVariant for FixedSizeVariantArray { fn from_variant(variant: &Variant) -> Option { Some(FixedSizeVariantArray( A::from(variant.fixed_array::().ok()?), std::marker::PhantomData, )) } } impl, T: FixedSizeVariantType> ToVariant for FixedSizeVariantArray { fn to_variant(&self) -> Variant { Variant::array_from_fixed_array(self.0.as_ref()) } } impl, T: FixedSizeVariantType> From> for Variant { #[doc(alias = "g_variant_new_from_data")] fn from(a: FixedSizeVariantArray) -> Self { unsafe { let data = Box::new(a.0); let (data_ptr, len) = { let data = (*data).as_ref(); (data.as_ptr(), mem::size_of_val(data)) }; unsafe extern "C" fn free_data, T: FixedSizeVariantType>( ptr: ffi::gpointer, ) { let _ = Box::from_raw(ptr as *mut A); } from_glib_none(ffi::g_variant_new_from_data( T::static_variant_type().to_glib_none().0, data_ptr as ffi::gconstpointer, len, false.into_glib(), Some(free_data::), Box::into_raw(data) as ffi::gpointer, )) } } } /// A wrapper type around `Variant` handles. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Handle(pub i32); impl From for Handle { fn from(v: i32) -> Self { Handle(v) } } impl From for i32 { fn from(v: Handle) -> Self { v.0 } } impl StaticVariantType for Handle { fn static_variant_type() -> Cow<'static, VariantTy> { Cow::Borrowed(VariantTy::HANDLE) } } impl ToVariant for Handle { fn to_variant(&self) -> Variant { unsafe { from_glib_none(ffi::g_variant_new_handle(self.0)) } } } impl From for Variant { #[inline] fn from(h: Handle) -> Self { h.to_variant() } } impl FromVariant for Handle { fn from_variant(variant: &Variant) -> Option { unsafe { if variant.is::() { Some(Handle(ffi::g_variant_get_handle(variant.to_glib_none().0))) } else { None } } } } /// A wrapper type around `Variant` object paths. /// /// Values of these type are guaranteed to be valid object paths. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ObjectPath(String); impl ObjectPath { pub fn as_str(&self) -> &str { &self.0 } } impl std::ops::Deref for ObjectPath { type Target = str; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } impl TryFrom for ObjectPath { type Error = crate::BoolError; fn try_from(v: String) -> Result { if !Variant::is_object_path(&v) { return Err(bool_error!("Invalid object path")); } Ok(ObjectPath(v)) } } impl<'a> TryFrom<&'a str> for ObjectPath { type Error = crate::BoolError; fn try_from(v: &'a str) -> Result { ObjectPath::try_from(String::from(v)) } } impl From for String { fn from(v: ObjectPath) -> Self { v.0 } } impl StaticVariantType for ObjectPath { fn static_variant_type() -> Cow<'static, VariantTy> { Cow::Borrowed(VariantTy::OBJECT_PATH) } } impl ToVariant for ObjectPath { fn to_variant(&self) -> Variant { unsafe { from_glib_none(ffi::g_variant_new_object_path(self.0.to_glib_none().0)) } } } impl From for Variant { #[inline] fn from(p: ObjectPath) -> Self { let mut s = p.0; s.push('\0'); unsafe { Self::from_data_trusted::(s) } } } impl FromVariant for ObjectPath { #[allow(unused_unsafe)] fn from_variant(variant: &Variant) -> Option { unsafe { if variant.is::() { Some(ObjectPath(String::from(variant.str().unwrap()))) } else { None } } } } /// A wrapper type around `Variant` signatures. /// /// Values of these type are guaranteed to be valid signatures. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Signature(String); impl Signature { pub fn as_str(&self) -> &str { &self.0 } } impl std::ops::Deref for Signature { type Target = str; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } impl TryFrom for Signature { type Error = crate::BoolError; fn try_from(v: String) -> Result { if !Variant::is_signature(&v) { return Err(bool_error!("Invalid signature")); } Ok(Signature(v)) } } impl<'a> TryFrom<&'a str> for Signature { type Error = crate::BoolError; fn try_from(v: &'a str) -> Result { Signature::try_from(String::from(v)) } } impl From for String { fn from(v: Signature) -> Self { v.0 } } impl StaticVariantType for Signature { fn static_variant_type() -> Cow<'static, VariantTy> { Cow::Borrowed(VariantTy::SIGNATURE) } } impl ToVariant for Signature { fn to_variant(&self) -> Variant { unsafe { from_glib_none(ffi::g_variant_new_signature(self.0.to_glib_none().0)) } } } impl From for Variant { #[inline] fn from(s: Signature) -> Self { let mut s = s.0; s.push('\0'); unsafe { Self::from_data_trusted::(s) } } } impl FromVariant for Signature { #[allow(unused_unsafe)] fn from_variant(variant: &Variant) -> Option { unsafe { if variant.is::() { Some(Signature(String::from(variant.str().unwrap()))) } else { None } } } } #[cfg(test)] mod tests { use std::collections::{HashMap, HashSet}; use super::*; macro_rules! unsigned { ($name:ident, $ty:ident) => { #[test] fn $name() { let mut n = $ty::MAX; while n > 0 { let v = n.to_variant(); assert_eq!(v.get(), Some(n)); n /= 2; } } }; } macro_rules! signed { ($name:ident, $ty:ident) => { #[test] fn $name() { let mut n = $ty::MAX; while n > 0 { let v = n.to_variant(); assert_eq!(v.get(), Some(n)); let v = (-n).to_variant(); assert_eq!(v.get(), Some(-n)); n /= 2; } } }; } unsigned!(test_u8, u8); unsigned!(test_u16, u16); unsigned!(test_u32, u32); unsigned!(test_u64, u64); signed!(test_i16, i16); signed!(test_i32, i32); signed!(test_i64, i64); #[test] fn test_str() { let s = "this is a test"; let v = s.to_variant(); assert_eq!(v.str(), Some(s)); assert_eq!(42u32.to_variant().str(), None); } #[test] fn test_fixed_array() { let b = b"this is a test"; let v = Variant::array_from_fixed_array(&b[..]); assert_eq!(v.type_().as_str(), "ay"); assert_eq!(v.fixed_array::().unwrap(), b); assert!(42u32.to_variant().fixed_array::().is_err()); let b = [1u32, 10u32, 100u32]; let v = Variant::array_from_fixed_array(&b); assert_eq!(v.type_().as_str(), "au"); assert_eq!(v.fixed_array::().unwrap(), b); assert!(v.fixed_array::().is_err()); let b = [true, false, true]; let v = Variant::array_from_fixed_array(&b); assert_eq!(v.type_().as_str(), "ab"); assert_eq!(v.fixed_array::().unwrap(), b); assert!(v.fixed_array::().is_err()); let b = [1.0f64, 2.0f64, 3.0f64]; let v = Variant::array_from_fixed_array(&b); assert_eq!(v.type_().as_str(), "ad"); #[allow(clippy::float_cmp)] { assert_eq!(v.fixed_array::().unwrap(), b); } assert!(v.fixed_array::().is_err()); } #[test] fn test_fixed_variant_array() { let b = FixedSizeVariantArray::from(&b"this is a test"[..]); let v = b.to_variant(); assert_eq!(v.type_().as_str(), "ay"); assert_eq!( &*v.get::, u8>>().unwrap(), &*b ); let b = FixedSizeVariantArray::from(vec![1i32, 2, 3]); let v = b.to_variant(); assert_eq!(v.type_().as_str(), "ai"); assert_eq!(v.get::, i32>>().unwrap(), b); } #[test] fn test_string() { let s = String::from("this is a test"); let v = s.to_variant(); assert_eq!(v.get(), Some(s)); assert_eq!(v.normal_form(), v); } #[test] fn test_eq() { let v1 = "this is a test".to_variant(); let v2 = "this is a test".to_variant(); let v3 = "test".to_variant(); assert_eq!(v1, v2); assert_ne!(v1, v3); } #[test] fn test_hash() { let v1 = "this is a test".to_variant(); let v2 = "this is a test".to_variant(); let v3 = "test".to_variant(); let mut set = HashSet::new(); set.insert(v1); assert!(set.contains(&v2)); assert!(!set.contains(&v3)); assert_eq!( >::static_variant_type().as_str(), "a{s(syu)}" ); } #[test] fn test_array() { assert_eq!(>::static_variant_type().as_str(), "as"); assert_eq!( >::static_variant_type().as_str(), "a(syu)" ); let a = ["foo", "bar", "baz"].to_variant(); assert_eq!(a.normal_form(), a); assert_eq!(a.array_iter_str().unwrap().len(), 3); let o = 0u32.to_variant(); assert!(o.array_iter_str().is_err()); } #[test] fn test_array_from_iter() { let a = Variant::array_from_iter::( ["foo", "bar", "baz"].into_iter().map(|s| s.to_variant()), ); assert_eq!(a.type_().as_str(), "as"); assert_eq!(a.n_children(), 3); assert_eq!(a.try_child_get::(0), Ok(Some(String::from("foo")))); assert_eq!(a.try_child_get::(1), Ok(Some(String::from("bar")))); assert_eq!(a.try_child_get::(2), Ok(Some(String::from("baz")))); } #[test] fn test_array_collect() { let a = ["foo", "bar", "baz"].into_iter().collect::(); assert_eq!(a.type_().as_str(), "as"); assert_eq!(a.n_children(), 3); assert_eq!(a.try_child_get::(0), Ok(Some(String::from("foo")))); assert_eq!(a.try_child_get::(1), Ok(Some(String::from("bar")))); assert_eq!(a.try_child_get::(2), Ok(Some(String::from("baz")))); } #[test] fn test_tuple() { assert_eq!(<(&str, u32)>::static_variant_type().as_str(), "(su)"); assert_eq!(<(&str, u8, u32)>::static_variant_type().as_str(), "(syu)"); let a = ("test", 1u8, 2u32).to_variant(); assert_eq!(a.normal_form(), a); assert_eq!(a.try_child_get::(0), Ok(Some(String::from("test")))); assert_eq!(a.try_child_get::(1), Ok(Some(1u8))); assert_eq!(a.try_child_get::(2), Ok(Some(2u32))); assert_eq!( a.try_get::<(String, u8, u32)>(), Ok((String::from("test"), 1u8, 2u32)) ); } #[test] fn test_tuple_from_iter() { let a = Variant::tuple_from_iter(["foo".to_variant(), 1u8.to_variant(), 2i32.to_variant()]); assert_eq!(a.type_().as_str(), "(syi)"); assert_eq!(a.n_children(), 3); assert_eq!(a.try_child_get::(0), Ok(Some(String::from("foo")))); assert_eq!(a.try_child_get::(1), Ok(Some(1u8))); assert_eq!(a.try_child_get::(2), Ok(Some(2i32))); } #[test] fn test_empty() { assert_eq!(<()>::static_variant_type().as_str(), "()"); let a = ().to_variant(); assert_eq!(a.type_().as_str(), "()"); assert_eq!(a.get::<()>(), Some(())); } #[test] fn test_maybe() { assert!(>::static_variant_type().is_maybe()); let m1 = Some(()).to_variant(); assert_eq!(m1.type_().as_str(), "m()"); assert_eq!(m1.get::>(), Some(Some(()))); assert!(m1.as_maybe().is_some()); let m2 = None::<()>.to_variant(); assert!(m2.as_maybe().is_none()); } #[test] fn test_btreemap() { assert_eq!( >::static_variant_type().as_str(), "a{su}" ); // Validate that BTreeMap adds entries to dict in sorted order let mut m = BTreeMap::new(); let total = 20; for n in 0..total { let k = format!("v{n:04}"); m.insert(k, n as u32); } let v = m.to_variant(); let n = v.n_children(); assert_eq!(total, n); for n in 0..total { let child = v .try_child_get::>(n) .unwrap() .unwrap(); assert_eq!(*child.value(), n as u32); } assert_eq!(BTreeMap::from_variant(&v).unwrap(), m); } #[test] fn test_get() -> Result<(), Box> { let u = 42u32.to_variant(); assert!(u.get::().is_none()); assert_eq!(u.get::().unwrap(), 42); assert!(u.try_get::().is_err()); // Test ? conversion assert_eq!(u.try_get::()?, 42); Ok(()) } #[test] fn test_byteswap() { let u = 42u32.to_variant(); assert_eq!(u.byteswap().get::().unwrap(), 704643072u32); assert_eq!(u.byteswap().byteswap().get::().unwrap(), 42u32); } #[test] fn test_try_child() { let a = ["foo"].to_variant(); assert!(a.try_child_value(0).is_some()); assert_eq!(a.try_child_get::(0).unwrap().unwrap(), "foo"); assert_eq!(a.child_get::(0), "foo"); assert!(a.try_child_get::(0).is_err()); assert!(a.try_child_value(1).is_none()); assert!(a.try_child_get::(1).unwrap().is_none()); let u = 42u32.to_variant(); assert!(u.try_child_value(0).is_none()); assert!(u.try_child_get::(0).unwrap().is_none()); } #[test] fn test_serialize() { let a = ("test", 1u8, 2u32).to_variant(); let bytes = a.data_as_bytes(); let data = a.data(); let len = a.size(); assert_eq!(bytes.len(), len); assert_eq!(data.len(), len); let mut store_data = vec![0u8; len]; assert_eq!(a.store(&mut store_data).unwrap(), len); assert_eq!(&bytes, data); assert_eq!(&store_data, data); let b = Variant::from_data::<(String, u8, u32), _>(store_data); assert_eq!(a, b); let c = Variant::from_bytes::<(String, u8, u32)>(&bytes); assert_eq!(a, c); } #[test] fn test_print_parse() { let a = ("test", 1u8, 2u32).to_variant(); let a2 = Variant::parse(Some(a.type_()), &a.print(false)).unwrap(); assert_eq!(a, a2); let a3: Variant = a.to_string().parse().unwrap(); assert_eq!(a, a3); } #[cfg(any(unix, windows))] #[test] fn test_paths() { use std::path::PathBuf; let path = PathBuf::from("foo"); let v = path.to_variant(); assert_eq!(PathBuf::from_variant(&v), Some(path)); } #[test] fn test_regression_from_variant_panics() { let variant = "text".to_variant(); let hashmap: Option> = FromVariant::from_variant(&variant); assert!(hashmap.is_none()); let variant = HashMap::::new().to_variant(); let hashmap: Option> = FromVariant::from_variant(&variant); assert!(hashmap.is_some()); } } glib-0.20.9/src/variant_dict.rs000064400000000000000000000257721046102023000144520ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::borrow::Cow; use crate::{ffi, translate::*, variant::*, variant_type::*}; wrapper! { // rustdoc-stripper-ignore-next /// `VariantDict` is a mutable key/value store where the keys are always /// strings and the values are [`Variant`s](variant/struct.Variant.html). /// /// Variant dictionaries can easily be converted to/from `Variant`s of the /// appropriate type. In `glib` terms, this is a variant of the form `"a{sv}"`. /// /// # Panics /// /// Note, pretty much all methods on this struct will panic if the /// [`end_unsafe()`](#method.end_unsafe) method was called on the instance. #[doc(alias = "GVariantDict")] pub struct VariantDict(Shared); match fn { ref => |ptr| ffi::g_variant_dict_ref(ptr), unref => |ptr| ffi::g_variant_dict_unref(ptr), type_ => || ffi::g_variant_dict_get_type(), } } impl VariantDict { // rustdoc-stripper-ignore-next /// Create a new `VariantDict` optionally populating it with the given `Variant` /// /// Since `Variant`s are immutable, this does not couple the `VariantDict` with /// the input `Variant`, instead the contents are copied into the `VariantDict`. /// /// # Panics /// /// This function will panic if the given `Variant` is not of the correct type. #[doc(alias = "g_variant_dict_new")] pub fn new(from_asv: Option<&Variant>) -> Self { if let Some(var) = from_asv { assert_eq!(var.type_(), VariantDict::static_variant_type()); } unsafe { from_glib_full(ffi::g_variant_dict_new(from_asv.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Check if this `VariantDict` contains the given key. /// /// Look up whether or not the given key is present, returning `true` if it /// is present in `self`. #[doc(alias = "g_variant_dict_contains")] pub fn contains(&self, key: &str) -> bool { unsafe { from_glib(ffi::g_variant_dict_contains( self.to_glib_none().0, key.to_glib_none().0, )) } } // rustdoc-stripper-ignore-next /// Look up a typed value from this `VariantDict`. /// /// The given `key` is looked up in `self`. /// /// This will return `None` if the `key` is not present in the dictionary, /// and an error if the key is present but with the wrong type. #[doc(alias = "g_variant_dict_lookup")] pub fn lookup(&self, key: &str) -> Result, VariantTypeMismatchError> { self.lookup_value(key, None) .map(|v| Variant::try_get(&v)) .transpose() } // rustdoc-stripper-ignore-next /// Look up and return a value from this `VariantDict`. /// /// The given `key` is looked up in `self`. If `expected_type` is not /// `None` then it will be matched against the type of any found value. /// /// This will return `None` if the `key` is not present in the dictionary /// or if it is present but the type of the value does not match a given /// `expected_type`. Otherwise, `Some(value)` will be returned where /// the `value` is an instance of [`Variant`](variant/struct.Variant.html). #[doc(alias = "g_variant_dict_lookup_value")] pub fn lookup_value(&self, key: &str, expected_type: Option<&VariantTy>) -> Option { unsafe { from_glib_full(ffi::g_variant_dict_lookup_value( self.to_glib_none().0, key.to_glib_none().0, expected_type.to_glib_none().0, )) } } // rustdoc-stripper-ignore-next /// Insert a variant into the dictionary. /// /// The given `key`/`value` pair is inserted into `self`. If a value /// was previously associated with `key` then it is overwritten. /// /// For convenience, you may use the [`insert()`](#method.insert) if /// you have a value which implements [`ToVariant`](variant/trait.ToVariant.html). #[doc(alias = "g_variant_dict_insert_value")] pub fn insert_value(&self, key: &str, value: &Variant) { unsafe { ffi::g_variant_dict_insert_value( self.to_glib_none().0, key.to_glib_none().0, value.to_glib_none().0, ) } } // rustdoc-stripper-ignore-next /// Insert a value into the dictionary /// /// The given `key`/`value` pair is inserted into `self`. If a value /// was previously associated with `key` then it is overwritten. /// /// This is a convenience method which automatically calls /// [`to_variant()`](variant/trait.ToVariant.html#method.to_variant) for you /// on the given value. /// /// If, on the other hand, you have a [`Variant`](variant/struct.Variant.html) /// instance already, you should use the [`insert_value()`](#method.insert_value) /// method instead. #[doc(alias = "g_variant_dict_insert_value")] pub fn insert(&self, key: &str, value: impl Into) { unsafe { ffi::g_variant_dict_insert_value( self.to_glib_none().0, key.to_glib_none().0, value.into().to_glib_none().0, ) } } // rustdoc-stripper-ignore-next /// Remove the given `key` from the dictionary. /// /// This removes the given `key` from the dictionary, releasing the reference /// on the associated value if one is present. /// /// If a `key`/`value` pair was removed from the dictionary, `true` is /// returned. If `key` was not present then `false` is returned instead. #[doc(alias = "g_variant_dict_remove")] pub fn remove(&self, key: &str) -> bool { unsafe { from_glib(ffi::g_variant_dict_remove( self.to_glib_none().0, key.to_glib_none().0, )) } } // rustdoc-stripper-ignore-next /// Convert this dictionary to a [`Variant`](variant/struct.Variant.html) /// /// This method converts `self` into an instance of [`Variant`](variant/struct.Variant.html) /// but in doing so renders it very unsafe to use. /// /// # Safety /// /// After calling this, the underlying `GVariantDict` is in a state where /// the only valid operations to perform as reference ones. As such /// any attempt to read/update the dictionary *will* fail and emit warnings /// of such. /// /// You should only use this function if the extra cost of the safe function /// is too much for your performance critical codepaths pub unsafe fn end_unsafe(&self) -> Variant { from_glib_none(ffi::g_variant_dict_end(self.to_glib_none().0)) } // rustdoc-stripper-ignore-next /// Convert this dictionary to a [`Variant`](variant/struct.Variant.html) /// /// This method converts `self` into an instance of [`Variant`](variant/struct.Variant.html) /// and then reinitialises itself in order to be safe for further use. /// /// If you are certain that nothing other than disposing of references will /// be done after ending the instance, you can call the /// [`end_unsafe()`](#method.end_unsafe) method instead to avoid the unnecessary /// reinitialisation of the dictionary. pub fn end(&self) -> Variant { unsafe { let ret = self.end_unsafe(); // Reinitialise the dict so that we can continue safely ffi::g_variant_dict_init(self.to_glib_none().0, None::.to_glib_none().0); ret } } } impl Default for VariantDict { fn default() -> Self { Self::new(None) } } impl StaticVariantType for VariantDict { fn static_variant_type() -> Cow<'static, VariantTy> { Cow::Borrowed(VariantTy::VARDICT) } } impl ToVariant for VariantDict { fn to_variant(&self) -> Variant { self.end() } } impl From for Variant { // rustdoc-stripper-ignore-next /// Consume a given `VariantDict` and call [`VariantDict::end`] on it. /// /// Note: While this method consumes the `VariantDict`, the underlying /// object could still be accessed through other clones because of the /// reference counted clone semantics. #[inline] fn from(d: VariantDict) -> Self { d.end() } } impl FromVariant for VariantDict { fn from_variant(variant: &Variant) -> Option { if variant.type_() == VariantDict::static_variant_type() { Some(Self::new(Some(variant))) } else { None } } } impl From for VariantDict { fn from(other: Variant) -> Self { Self::new(Some(&other)) } } #[cfg(test)] mod test { use super::*; #[test] fn create_destroy() { let _dict = VariantDict::new(None); } #[test] fn create_roundtrip() { let dict = VariantDict::default(); let var: Variant = dict.to_variant(); let _dict2: VariantDict = var.into(); } #[test] fn into_variant_roundtrip() { let dict1 = VariantDict::default(); let dict2 = dict1.clone(); dict1.insert_value("one", &(1u8.to_variant())); assert_eq!(dict1.lookup::("one").unwrap(), Some(1u8)); assert_eq!(dict2.lookup::("one").unwrap(), Some(1u8)); // Convert it into `Variant` let dict: Variant = dict1.into(); // While we can still access the `VariantDict` via `dict2`, // it should be empty now assert_eq!(dict2.lookup::("one").unwrap(), None); // Convert it back let dict3: VariantDict = dict.into(); assert_eq!(dict3.lookup::("one").unwrap(), Some(1u8)); } #[test] fn create_populate_destroy() { let dict = VariantDict::default(); dict.insert_value("one", &(1u8.to_variant())); assert_eq!(dict.lookup_value("one", None), Some(1u8.to_variant())); } #[test] fn create_populate_roundtrip() { let dict = VariantDict::default(); dict.insert_value("one", &(1u8.to_variant())); let var: Variant = dict.to_variant(); let dict = VariantDict::from_variant(&var).expect("Not a dict?"); assert_eq!(dict.lookup_value("one", None), Some(1u8.to_variant())); } #[test] fn lookup() -> Result<(), Box> { let dict = VariantDict::default(); dict.insert_value("one", &(1u8.to_variant())); assert_eq!(dict.lookup::("one")?.unwrap(), 1u8); assert_eq!( dict.lookup::("one").err().unwrap().actual, u8::static_variant_type() ); assert!(dict.lookup::("two")?.is_none()); Ok(()) } #[test] fn create_populate_remove() { let dict = VariantDict::default(); let empty_var = dict.to_variant(); dict.insert("one", 1u64); assert!(dict.remove("one")); assert!(!dict.remove("one")); let var2 = dict.to_variant(); assert_eq!(empty_var, var2); } } glib-0.20.9/src/variant_iter.rs000064400000000000000000000231551046102023000144630ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // This is similar to the GVariantIter provided by glib, but that would // introduce a heap allocation and doesn't provide a way to determine how // many items are left in the iterator. use std::iter::FusedIterator; use crate::{ffi, translate::*, Variant}; // rustdoc-stripper-ignore-next /// Iterator over items in a variant. #[derive(Debug)] pub struct VariantIter { variant: Variant, head: usize, tail: usize, } impl VariantIter { pub(crate) fn new(variant: Variant) -> Self { let tail = variant.n_children(); Self { variant, head: 0, tail, } } } impl Iterator for VariantIter { type Item = Variant; fn next(&mut self) -> Option { if self.head == self.tail { None } else { let value = self.variant.child_value(self.head); self.head += 1; Some(value) } } fn size_hint(&self) -> (usize, Option) { let size = self.tail - self.head; (size, Some(size)) } fn count(self) -> usize { self.tail - self.head } fn nth(&mut self, n: usize) -> Option { let (end, overflow) = self.head.overflowing_add(n); if end >= self.tail || overflow { self.head = self.tail; None } else { self.head = end + 1; Some(self.variant.child_value(end)) } } fn last(self) -> Option { if self.head == self.tail { None } else { Some(self.variant.child_value(self.tail - 1)) } } } impl DoubleEndedIterator for VariantIter { fn next_back(&mut self) -> Option { if self.head == self.tail { None } else { self.tail -= 1; Some(self.variant.child_value(self.tail)) } } fn nth_back(&mut self, n: usize) -> Option { let (end, overflow) = self.tail.overflowing_sub(n); if end <= self.head || overflow { self.head = self.tail; None } else { self.tail = end - 1; Some(self.variant.child_value(end - 1)) } } } impl ExactSizeIterator for VariantIter {} impl FusedIterator for VariantIter {} // rustdoc-stripper-ignore-next /// Iterator over items in a variant of type `as`. #[derive(Debug)] pub struct VariantStrIter<'a> { variant: &'a Variant, head: usize, tail: usize, } impl<'a> VariantStrIter<'a> { pub(crate) fn new(variant: &'a Variant) -> Self { let tail = variant.n_children(); Self { variant, head: 0, tail, } } fn impl_get(&self, i: usize) -> &'a str { unsafe { let mut p: *mut libc::c_char = std::ptr::null_mut(); let s = b"&s\0"; ffi::g_variant_get_child( self.variant.to_glib_none().0, i, s as *const u8 as *const _, &mut p, std::ptr::null::(), ); let p = std::ffi::CStr::from_ptr(p); p.to_str().unwrap() } } } impl<'a> Iterator for VariantStrIter<'a> { type Item = &'a str; fn next(&mut self) -> Option<&'a str> { if self.head == self.tail { None } else { let v = self.impl_get(self.head); self.head += 1; Some(v) } } fn size_hint(&self) -> (usize, Option) { let size = self.tail - self.head; (size, Some(size)) } fn count(self) -> usize { self.tail - self.head } fn nth(&mut self, n: usize) -> Option<&'a str> { let (end, overflow) = self.head.overflowing_add(n); if end >= self.tail || overflow { self.head = self.tail; None } else { self.head = end + 1; Some(self.impl_get(end)) } } fn last(self) -> Option<&'a str> { if self.head == self.tail { None } else { Some(self.impl_get(self.tail - 1)) } } } impl<'a> DoubleEndedIterator for VariantStrIter<'a> { fn next_back(&mut self) -> Option<&'a str> { if self.head == self.tail { None } else { self.tail -= 1; Some(self.impl_get(self.tail)) } } fn nth_back(&mut self, n: usize) -> Option<&'a str> { let (end, overflow) = self.tail.overflowing_sub(n); if end <= self.head || overflow { self.head = self.tail; None } else { self.tail = end - 1; Some(self.impl_get(end - 1)) } } } impl ExactSizeIterator for VariantStrIter<'_> {} impl FusedIterator for VariantStrIter<'_> {} #[cfg(test)] mod tests { use std::collections::HashMap; use crate::{ prelude::*, variant::{DictEntry, Variant}, }; #[test] fn test_variant_iter_variant() { let v = Variant::from_variant(&"foo".to_string().to_variant()); let vec: Vec = v.iter().map(|i| i.get().unwrap()).collect(); assert_eq!(vec, vec!["foo".to_string()]); } #[test] fn test_variant_iter_array() { let v = Variant::array_from_iter::([ "foo".to_string().to_variant(), "bar".to_string().to_variant(), ]); let vec: Vec = v.iter().map(|i| i.get().unwrap()).collect(); let a = vec!["foo".to_string(), "bar".to_string()]; assert_eq!(&vec, &a); let vec: Vec<_> = v.array_iter_str().unwrap().collect(); assert_eq!(&vec, &a); } #[test] fn test_variant_iter_tuple() { let v = Variant::tuple_from_iter([ "foo".to_string().to_variant(), "bar".to_string().to_variant(), ]); let vec: Vec = v.iter().map(|i| i.get().unwrap()).collect(); assert_eq!(vec, vec!["foo".to_string(), "bar".to_string()]); } #[test] fn test_variant_iter_dictentry() { let v = DictEntry::new("foo", 1337).to_variant(); println!("{:?}", v.iter().collect::>()); assert_eq!(v.iter().count(), 2); } #[test] fn test_variant_iter_map() { let mut map = HashMap::new(); map.insert("foo", 1); map.insert("bar", 1); let v = map.to_variant(); assert_eq!(v.iter().count(), 2); } #[test] fn test_variant_iter_nth() { let v = Variant::array_from_iter::([ "0".to_string().to_variant(), "1".to_string().to_variant(), "2".to_string().to_variant(), "3".to_string().to_variant(), "4".to_string().to_variant(), "5".to_string().to_variant(), ]); let mut iter = v.iter(); assert_eq!(iter.len(), 6); assert_eq!( iter.nth(1).map(|v| v.get::().unwrap()), Some("1".into()) ); assert_eq!(iter.len(), 4); assert_eq!( iter.next().map(|v| v.get::().unwrap()), Some("2".into()) ); assert_eq!( iter.nth_back(2).map(|v| v.get::().unwrap()), Some("3".into()) ); assert_eq!(iter.len(), 0); assert_eq!(iter.next(), None); assert_eq!(iter.next_back(), None); } #[test] fn test_variant_iter_count() { let v = Variant::array_from_iter::([ "0".to_string().to_variant(), "1".to_string().to_variant(), "2".to_string().to_variant(), ]); let iter = v.iter(); assert_eq!(iter.len(), 3); assert_eq!(iter.count(), 3); } #[test] fn test_variant_iter_last() { let v = Variant::array_from_iter::([ "0".to_string().to_variant(), "1".to_string().to_variant(), "2".to_string().to_variant(), ]); let iter = v.iter(); assert_eq!(iter.len(), 3); assert_eq!( iter.last().map(|v| v.get::().unwrap()), Some("2".into()) ); } #[test] fn test_variant_str_iter_nth() { let v = Variant::array_from_iter::([ "0".to_string().to_variant(), "1".to_string().to_variant(), "2".to_string().to_variant(), "3".to_string().to_variant(), "4".to_string().to_variant(), "5".to_string().to_variant(), ]); let mut iter = v.array_iter_str().unwrap(); assert_eq!(iter.len(), 6); assert_eq!(iter.nth(1), Some("1")); assert_eq!(iter.len(), 4); assert_eq!(iter.next(), Some("2")); assert_eq!(iter.nth_back(2), Some("3")); assert_eq!(iter.len(), 0); assert_eq!(iter.next(), None); assert_eq!(iter.next_back(), None); } #[test] fn test_variant_str_iter_count() { let v = Variant::array_from_iter::([ "0".to_string().to_variant(), "1".to_string().to_variant(), "2".to_string().to_variant(), ]); let iter = v.array_iter_str().unwrap(); assert_eq!(iter.len(), 3); assert_eq!(iter.count(), 3); } #[test] fn test_variant_str_iter_last() { let v = Variant::array_from_iter::([ "0".to_string().to_variant(), "1".to_string().to_variant(), "2".to_string().to_variant(), ]); let iter = v.array_iter_str().unwrap(); assert_eq!(iter.len(), 3); assert_eq!(iter.last(), Some("2")); } } glib-0.20.9/src/variant_type.rs000064400000000000000000001006231046102023000144750ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ borrow::{Borrow, Cow}, fmt, hash::{Hash, Hasher}, iter, marker::PhantomData, ops::Deref, ptr, slice, str::FromStr, }; use crate::{ffi, gobject_ffi, prelude::*, translate::*, BoolError, Type}; // rustdoc-stripper-ignore-next /// Describes `Variant` types. /// /// The `Variant` type system (based on the D-Bus one) describes types with /// "type strings". `VariantType` is an owned immutable type string (you can /// think of it as a `Box` statically guaranteed to be a valid type /// string), `&VariantTy` is a borrowed one (like `&str`). #[doc(alias = "GVariantType")] pub struct VariantType { // GVariantType* essentially is a char*, that always is valid UTF-8 but // isn't NUL-terminated. ptr: ptr::NonNull, // We query the length on creation assuming it's cheap (because type strings // are short) and likely to happen anyway. len: usize, } impl VariantType { // rustdoc-stripper-ignore-next /// 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) } // rustdoc-stripper-ignore-next /// Creates a `VariantType` from a key and value type. #[doc(alias = "g_variant_type_new_dict_entry")] pub fn new_dict_entry(key_type: &VariantTy, value_type: &VariantTy) -> VariantType { unsafe { from_glib_full(ffi::g_variant_type_new_dict_entry( key_type.to_glib_none().0, value_type.to_glib_none().0, )) } } // rustdoc-stripper-ignore-next /// Creates a `VariantType` from an array element type. #[doc(alias = "g_variant_type_new_array")] pub fn new_array(elem_type: &VariantTy) -> VariantType { unsafe { from_glib_full(ffi::g_variant_type_new_array(elem_type.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Creates a `VariantType` from a maybe element type. #[doc(alias = "g_variant_type_new_maybe")] pub fn new_maybe(child_type: &VariantTy) -> VariantType { unsafe { from_glib_full(ffi::g_variant_type_new_maybe(child_type.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Creates a `VariantType` from a maybe element type. #[doc(alias = "g_variant_type_new_tuple")] pub fn new_tuple(items: impl IntoIterator>) -> VariantType { let mut builder = crate::GStringBuilder::new("("); for ty in items { builder.append(ty.as_ref().as_str()); } builder.append_c(')'); VariantType::from_string(builder.into_string()).unwrap() } // rustdoc-stripper-ignore-next /// Tries to create a `VariantType` from an owned string. /// /// Returns `Ok` if the string is a valid type string, `Err` otherwise. pub fn from_string(type_string: impl Into) -> Result { let type_string = type_string.into(); VariantTy::new(&type_string)?; let len = type_string.len(); unsafe { let ptr = type_string.into_glib_ptr(); Ok(VariantType { ptr: ptr::NonNull::new_unchecked(ptr as *mut ffi::GVariantType), len, }) } } } unsafe impl Send for VariantType {} unsafe impl Sync for VariantType {} impl Drop for VariantType { #[inline] fn drop(&mut self) { unsafe { ffi::g_variant_type_free(self.ptr.as_ptr()) } } } impl AsRef for VariantType { #[inline] fn as_ref(&self) -> &VariantTy { self } } impl Borrow for VariantType { #[inline] fn borrow(&self) -> &VariantTy { self } } impl Clone for VariantType { #[inline] fn clone(&self) -> VariantType { unsafe { VariantType { ptr: ptr::NonNull::new_unchecked(ffi::g_variant_type_copy(self.ptr.as_ptr())), len: self.len, } } } } impl Deref for VariantType { type Target = VariantTy; #[allow(clippy::cast_slice_from_raw_parts)] #[inline] fn deref(&self) -> &VariantTy { unsafe { &*(slice::from_raw_parts(self.ptr.as_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.as_str()) } } impl FromStr for VariantType { type Err = BoolError; fn from_str(s: &str) -> Result { Self::new(s) } } impl Hash for VariantType { #[inline] fn hash(&self, state: &mut H) { ::hash(self, state) } } impl<'a> From for Cow<'a, VariantTy> { #[inline] fn from(ty: VariantType) -> Cow<'a, VariantTy> { Cow::Owned(ty) } } #[doc(hidden)] impl IntoGlibPtr<*mut ffi::GVariantType> for VariantType { #[inline] unsafe fn into_glib_ptr(self) -> *mut ffi::GVariantType { std::mem::ManuallyDrop::new(self).to_glib_none().0 } } #[doc(hidden)] impl<'a> ToGlibPtr<'a, *const ffi::GVariantType> for VariantType { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GVariantType, Self> { Stash(self.ptr.as_ptr(), PhantomData) } #[inline] fn to_glib_full(&self) -> *const ffi::GVariantType { unsafe { ffi::g_variant_type_copy(self.ptr.as_ptr()) } } } #[doc(hidden)] impl<'a> ToGlibPtr<'a, *mut ffi::GVariantType> for VariantType { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GVariantType, Self> { Stash(self.ptr.as_ptr(), PhantomData) } #[inline] fn to_glib_full(&self) -> *mut ffi::GVariantType { unsafe { ffi::g_variant_type_copy(self.ptr.as_ptr()) } } } #[doc(hidden)] impl<'a> ToGlibPtrMut<'a, *mut ffi::GVariantType> for VariantType { type Storage = PhantomData<&'a mut Self>; #[inline] fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GVariantType, Self> { StashMut(self.ptr.as_ptr(), PhantomData) } } #[doc(hidden)] impl FromGlibPtrNone<*const ffi::GVariantType> for VariantType { #[inline] unsafe fn from_glib_none(ptr: *const ffi::GVariantType) -> VariantType { VariantTy::from_ptr(ptr).to_owned() } } #[doc(hidden)] impl FromGlibPtrFull<*const ffi::GVariantType> for VariantType { #[inline] unsafe fn from_glib_full(ptr: *const ffi::GVariantType) -> VariantType { // Don't assume ownership of a const pointer. // A transfer: full annotation on a `const GVariantType*` is likely a bug. VariantTy::from_ptr(ptr).to_owned() } } #[doc(hidden)] impl FromGlibPtrFull<*mut ffi::GVariantType> for VariantType { #[inline] unsafe fn from_glib_full(ptr: *mut ffi::GVariantType) -> VariantType { debug_assert!(!ptr.is_null()); let len: usize = ffi::g_variant_type_get_string_length(ptr) as _; VariantType { ptr: ptr::NonNull::new_unchecked(ptr), len, } } } // rustdoc-stripper-ignore-next /// 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. #[repr(transparent)] #[derive(Debug, PartialEq, Eq, Hash)] pub struct VariantTy { inner: str, } impl VariantTy { // rustdoc-stripper-ignore-next /// `bool`. #[doc(alias = "G_VARIANT_TYPE_BOOLEAN")] pub const BOOLEAN: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BOOLEAN) }; // rustdoc-stripper-ignore-next /// `u8`. #[doc(alias = "G_VARIANT_TYPE_BYTE")] pub const BYTE: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BYTE) }; // rustdoc-stripper-ignore-next /// `i16`. #[doc(alias = "G_VARIANT_TYPE_INT16")] pub const INT16: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_INT16) }; // rustdoc-stripper-ignore-next /// `u16`. #[doc(alias = "G_VARIANT_TYPE_UINT16")] pub const UINT16: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UINT16) }; // rustdoc-stripper-ignore-next /// `i32`. #[doc(alias = "G_VARIANT_TYPE_INT32")] pub const INT32: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_INT32) }; // rustdoc-stripper-ignore-next /// `u32`. #[doc(alias = "G_VARIANT_TYPE_UINT32")] pub const UINT32: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UINT32) }; // rustdoc-stripper-ignore-next /// `i64`. #[doc(alias = "G_VARIANT_TYPE_INT64")] pub const INT64: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_INT64) }; // rustdoc-stripper-ignore-next /// `u64`. #[doc(alias = "G_VARIANT_TYPE_UINT64")] pub const UINT64: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UINT64) }; // rustdoc-stripper-ignore-next /// `f64`. #[doc(alias = "G_VARIANT_TYPE_DOUBLE")] pub const DOUBLE: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_DOUBLE) }; // rustdoc-stripper-ignore-next /// `&str`. #[doc(alias = "G_VARIANT_TYPE_STRING")] pub const STRING: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_STRING) }; // rustdoc-stripper-ignore-next /// DBus object path. #[doc(alias = "G_VARIANT_TYPE_OBJECT_PATH")] pub const OBJECT_PATH: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_OBJECT_PATH) }; // rustdoc-stripper-ignore-next /// Type signature. #[doc(alias = "G_VARIANT_TYPE_SIGNATURE")] pub const SIGNATURE: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_SIGNATURE) }; // rustdoc-stripper-ignore-next /// Variant. #[doc(alias = "G_VARIANT_TYPE_VARIANT")] pub const VARIANT: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_VARIANT) }; // rustdoc-stripper-ignore-next /// Handle. #[doc(alias = "G_VARIANT_TYPE_HANDLE")] pub const HANDLE: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_HANDLE) }; // rustdoc-stripper-ignore-next /// Unit, i.e. `()`. #[doc(alias = "G_VARIANT_TYPE_UNIT")] pub const UNIT: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_UNIT) }; // rustdoc-stripper-ignore-next /// An indefinite type that is a supertype of every type (including itself). #[doc(alias = "G_VARIANT_TYPE_ANY")] pub const ANY: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_ANY) }; // rustdoc-stripper-ignore-next /// Any basic type. #[doc(alias = "G_VARIANT_TYPE_BASIC")] pub const BASIC: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BASIC) }; // rustdoc-stripper-ignore-next /// Any maybe type, i.e. `Option`. #[doc(alias = "G_VARIANT_TYPE_MAYBE")] pub const MAYBE: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_MAYBE) }; // rustdoc-stripper-ignore-next /// Any array type, i.e. `[T]`. #[doc(alias = "G_VARIANT_TYPE_ARRAY")] pub const ARRAY: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_ARRAY) }; // rustdoc-stripper-ignore-next /// Any tuple type, i.e. `(T)`, `(T, T)`, etc. #[doc(alias = "G_VARIANT_TYPE_TUPLE")] pub const TUPLE: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_TUPLE) }; // rustdoc-stripper-ignore-next /// Any dict entry type, i.e. `DictEntry`. #[doc(alias = "G_VARIANT_TYPE_DICT_ENTRY")] pub const DICT_ENTRY: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_DICT_ENTRY) }; // rustdoc-stripper-ignore-next /// Any dictionary type, i.e. `HashMap`, `BTreeMap`. #[doc(alias = "G_VARIANT_TYPE_DICTIONARY")] pub const DICTIONARY: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_DICTIONARY) }; // rustdoc-stripper-ignore-next /// String array, i.e. `[&str]`. #[doc(alias = "G_VARIANT_TYPE_STRING_ARRAY")] pub const STRING_ARRAY: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_STRING_ARRAY) }; // rustdoc-stripper-ignore-next /// Object path array, i.e. `[&str]`. #[doc(alias = "G_VARIANT_TYPE_OBJECT_PATH_ARRAY")] pub const OBJECT_PATH_ARRAY: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_OBJECT_PATH_ARRAY) }; // rustdoc-stripper-ignore-next /// Byte string, i.e. `[u8]`. #[doc(alias = "G_VARIANT_TYPE_BYTE_STRING")] pub const BYTE_STRING: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BYTE_STRING) }; // rustdoc-stripper-ignore-next /// Byte string array, i.e. `[[u8]]`. #[doc(alias = "G_VARIANT_TYPE_BYTE_STRING_ARRAY")] pub const BYTE_STRING_ARRAY: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_BYTE_STRING_ARRAY) }; // rustdoc-stripper-ignore-next /// Variant dictionary, i.e. `HashMap`, `BTreeMap`, etc. #[doc(alias = "G_VARIANT_TYPE_VARDICT")] pub const VARDICT: &'static VariantTy = unsafe { VariantTy::from_str_unchecked(ffi::G_VARIANT_TYPE_VARDICT) }; // rustdoc-stripper-ignore-next /// Tries to create a `&VariantTy` from a string slice. /// /// Returns `Ok` if the string is a valid type string, `Err` otherwise. pub fn new(type_string: &str) -> Result<&VariantTy, BoolError> { unsafe { let ptr = type_string.as_ptr(); let limit = ptr.add(type_string.len()); let mut end = ptr::null(); let ok = from_glib(ffi::g_variant_type_string_scan( ptr as *const _, limit as *const _, &mut end, )); if ok && end as *const _ == limit { Ok(&*(type_string.as_bytes() as *const [u8] as *const VariantTy)) } else { Err(bool_error!("Invalid type string: '{}'", type_string)) } } } // rustdoc-stripper-ignore-next /// Converts a type string into `&VariantTy` without any checks. /// /// # Safety /// /// The caller is responsible for passing in only a valid variant type string. #[inline] pub const unsafe fn from_str_unchecked(type_string: &str) -> &VariantTy { std::mem::transmute::<&str, &VariantTy>(type_string) } // rustdoc-stripper-ignore-next /// Creates `&VariantTy` with a wildcard lifetime from a `GVariantType` /// pointer. #[doc(hidden)] #[allow(clippy::cast_slice_from_raw_parts)] #[inline] pub unsafe fn from_ptr<'a>(ptr: *const ffi::GVariantType) -> &'a VariantTy { debug_assert!(!ptr.is_null()); let len: usize = ffi::g_variant_type_get_string_length(ptr) as _; debug_assert!(len > 0); &*(slice::from_raw_parts(ptr as *const u8, len) as *const [u8] as *const VariantTy) } // rustdoc-stripper-ignore-next /// Returns a `GVariantType` pointer. #[doc(hidden)] #[inline] pub fn as_ptr(&self) -> *const ffi::GVariantType { self.inner.as_ptr() as *const _ } // rustdoc-stripper-ignore-next /// Converts to a string slice. #[inline] pub fn as_str(&self) -> &str { &self.inner } // rustdoc-stripper-ignore-next /// Check if this variant type is a definite type. #[doc(alias = "g_variant_type_is_definite")] pub fn is_definite(&self) -> bool { unsafe { from_glib(ffi::g_variant_type_is_definite(self.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Check if this variant type is a container type. #[doc(alias = "g_variant_type_is_container")] pub fn is_container(&self) -> bool { unsafe { from_glib(ffi::g_variant_type_is_container(self.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Check if this variant type is a basic type. #[doc(alias = "g_variant_type_is_basic")] pub fn is_basic(&self) -> bool { unsafe { from_glib(ffi::g_variant_type_is_basic(self.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Check if this variant type is a maybe type. #[doc(alias = "g_variant_type_is_maybe")] pub fn is_maybe(&self) -> bool { unsafe { from_glib(ffi::g_variant_type_is_maybe(self.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Check if this variant type is an array type. #[doc(alias = "g_variant_type_is_array")] pub fn is_array(&self) -> bool { unsafe { from_glib(ffi::g_variant_type_is_array(self.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Check if this variant type is a tuple type. #[doc(alias = "g_variant_type_is_tuple")] pub fn is_tuple(&self) -> bool { unsafe { from_glib(ffi::g_variant_type_is_tuple(self.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Check if this variant type is a dict entry type. #[doc(alias = "g_variant_type_is_dict_entry")] pub fn is_dict_entry(&self) -> bool { unsafe { from_glib(ffi::g_variant_type_is_dict_entry(self.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Check if this variant type is a variant. #[doc(alias = "g_variant_type_is_variant")] pub fn is_variant(&self) -> bool { unsafe { from_glib(ffi::g_variant_type_is_variant(self.to_glib_none().0)) } } // rustdoc-stripper-ignore-next /// Check if this variant type is a subtype of another. #[doc(alias = "g_variant_type_is_subtype_of")] pub fn is_subtype_of(&self, supertype: &Self) -> bool { unsafe { from_glib(ffi::g_variant_type_is_subtype_of( self.to_glib_none().0, supertype.to_glib_none().0, )) } } // rustdoc-stripper-ignore-next /// Return the element type of this variant type. /// /// # Panics /// /// This function panics if not called with an array or maybe type. #[doc(alias = "g_variant_type_element")] pub fn element(&self) -> &VariantTy { assert!(self.is_array() || self.is_maybe()); unsafe { let element = ffi::g_variant_type_element(self.to_glib_none().0); Self::from_ptr(element) } } // rustdoc-stripper-ignore-next /// Iterate over the types of this variant type. /// /// # Panics /// /// This function panics if not called with a tuple or dictionary entry type. pub fn tuple_types(&self) -> VariantTyIterator { VariantTyIterator::new(self).expect("VariantTy does not represent a tuple") } // rustdoc-stripper-ignore-next /// Return the first type of this variant type. /// /// # Panics /// /// This function panics if not called with a tuple or dictionary entry type. #[doc(alias = "g_variant_type_first")] pub fn first(&self) -> Option<&VariantTy> { assert!(self.as_str().starts_with('(') || self.as_str().starts_with('{')); unsafe { let first = ffi::g_variant_type_first(self.to_glib_none().0); if first.is_null() { None } else { Some(Self::from_ptr(first)) } } } // rustdoc-stripper-ignore-next /// Return the next type of this variant type. #[doc(alias = "g_variant_type_next")] pub fn next(&self) -> Option<&VariantTy> { unsafe { let next = ffi::g_variant_type_next(self.to_glib_none().0); if next.is_null() { None } else { Some(Self::from_ptr(next)) } } } // rustdoc-stripper-ignore-next /// Return the number of items in this variant type. #[doc(alias = "g_variant_type_n_items")] pub fn n_items(&self) -> usize { unsafe { ffi::g_variant_type_n_items(self.to_glib_none().0) } } // rustdoc-stripper-ignore-next /// Return the key type of this variant type. /// /// # Panics /// /// This function panics if not called with a dictionary entry type. #[doc(alias = "g_variant_type_key")] pub fn key(&self) -> &VariantTy { assert!(self.as_str().starts_with('{')); unsafe { let key = ffi::g_variant_type_key(self.to_glib_none().0); Self::from_ptr(key) } } // rustdoc-stripper-ignore-next /// Return the value type of this variant type. /// /// # Panics /// /// This function panics if not called with a dictionary entry type. #[doc(alias = "g_variant_type_value")] pub fn value(&self) -> &VariantTy { assert!(self.as_str().starts_with('{')); unsafe { let value = ffi::g_variant_type_value(self.to_glib_none().0); Self::from_ptr(value) } } // rustdoc-stripper-ignore-next /// Return this type as an array. pub(crate) fn as_array<'a>(&self) -> Cow<'a, VariantTy> { if self == VariantTy::STRING { Cow::Borrowed(VariantTy::STRING_ARRAY) } else if self == VariantTy::BYTE { Cow::Borrowed(VariantTy::BYTE_STRING) } else if self == VariantTy::BYTE_STRING { Cow::Borrowed(VariantTy::BYTE_STRING_ARRAY) } else if self == VariantTy::OBJECT_PATH { Cow::Borrowed(VariantTy::OBJECT_PATH_ARRAY) } else if self == VariantTy::DICT_ENTRY { Cow::Borrowed(VariantTy::DICTIONARY) } else { Cow::Owned(VariantType::new_array(self)) } } } unsafe impl Sync for VariantTy {} #[doc(hidden)] impl<'a> ToGlibPtr<'a, *const ffi::GVariantType> for VariantTy { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GVariantType, Self> { Stash(self.as_ptr(), PhantomData) } } impl fmt::Display for VariantTy { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.as_str()) } } impl<'a> From<&'a VariantTy> for Cow<'a, VariantTy> { #[inline] fn from(ty: &'a VariantTy) -> Cow<'a, VariantTy> { Cow::Borrowed(ty) } } impl AsRef for VariantTy { #[inline] fn as_ref(&self) -> &Self { self } } impl ToOwned for VariantTy { type Owned = VariantType; #[inline] fn to_owned(&self) -> VariantType { unsafe { VariantType { ptr: ptr::NonNull::new_unchecked(ffi::g_variant_type_copy(self.as_ptr())), len: self.inner.len(), } } } } impl StaticType for VariantTy { #[inline] fn static_type() -> Type { unsafe { from_glib(ffi::g_variant_type_get_gtype()) } } } #[doc(hidden)] unsafe impl<'a> crate::value::FromValue<'a> for &'a VariantTy { type Checker = crate::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a crate::Value) -> Self { let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0); debug_assert!(!ptr.is_null()); VariantTy::from_ptr(ptr as *const ffi::GVariantType) } } #[doc(hidden)] impl crate::value::ToValue for VariantTy { fn to_value(&self) -> crate::Value { unsafe { let mut value = crate::Value::from_type_unchecked(VariantTy::static_type()); gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, self.to_glib_none().0 as *mut _, ); value } } fn value_type(&self) -> crate::Type { VariantTy::static_type() } } #[doc(hidden)] impl crate::value::ToValue for &VariantTy { fn to_value(&self) -> crate::Value { (*self).to_value() } #[inline] fn value_type(&self) -> crate::Type { VariantTy::static_type() } } #[doc(hidden)] impl crate::value::ToValueOptional for &VariantTy { fn to_value_optional(s: Option<&Self>) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, s.to_glib_none().0 as *mut _, ); } value } } impl StaticType for VariantType { #[inline] fn static_type() -> Type { unsafe { from_glib(ffi::g_variant_type_get_gtype()) } } } #[doc(hidden)] impl crate::value::ValueType for VariantType { type Type = VariantType; } #[doc(hidden)] impl crate::value::ValueTypeOptional for VariantType {} #[doc(hidden)] unsafe impl<'a> crate::value::FromValue<'a> for VariantType { type Checker = crate::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a crate::Value) -> Self { let ptr = gobject_ffi::g_value_get_boxed(value.to_glib_none().0); debug_assert!(!ptr.is_null()); from_glib_none(ptr as *const ffi::GVariantType) } } #[doc(hidden)] impl crate::value::ToValue for VariantType { fn to_value(&self) -> crate::Value { unsafe { let mut value = crate::Value::from_type_unchecked(VariantType::static_type()); gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, ToGlibPtr::<*mut _>::to_glib_none(&self).0 as *mut _, ); value } } fn value_type(&self) -> crate::Type { VariantType::static_type() } } #[doc(hidden)] impl From for crate::Value { fn from(t: VariantType) -> Self { unsafe { let mut value = crate::Value::from_type_unchecked(VariantType::static_type()); gobject_ffi::g_value_take_boxed( value.to_glib_none_mut().0, IntoGlibPtr::<*mut _>::into_glib_ptr(t) as *mut _, ); value } } } #[doc(hidden)] impl crate::value::ToValueOptional for VariantType { fn to_value_optional(s: Option<&Self>) -> crate::Value { let mut value = crate::Value::for_value_type::(); unsafe { gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, ToGlibPtr::<*mut _>::to_glib_none(&s).0 as *mut _, ); } value } } impl PartialEq for VariantType { #[inline] fn eq(&self, other: &Self) -> bool { ::eq(self, other) } } macro_rules! impl_eq { ($lhs:ty, $rhs: ty) => { #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialEq<$rhs> for $lhs { #[inline] fn eq(&self, other: &$rhs) -> bool { ::eq(self, other) } } #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialEq<$lhs> for $rhs { #[inline] fn eq(&self, other: &$lhs) -> bool { ::eq(self, other) } } }; } impl_eq!(VariantType, VariantTy); impl_eq!(VariantType, &'a VariantTy); impl_eq!(VariantType, Cow<'a, VariantTy>); impl_eq!(&'a VariantTy, Cow<'b, VariantTy>); macro_rules! impl_str_eq { ($lhs:ty, $rhs: ty) => { #[allow(clippy::redundant_slicing)] #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialEq<$rhs> for $lhs { #[inline] fn eq(&self, other: &$rhs) -> bool { self.as_str().eq(&other[..]) } } #[allow(clippy::extra_unused_lifetimes)] impl<'a, 'b> PartialEq<$lhs> for $rhs { #[inline] fn eq(&self, other: &$lhs) -> bool { self[..].eq(other.as_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 {} // rustdoc-stripper-ignore-next /// An iterator over the individual components of a tuple [VariantTy]. /// /// This can be conveniently constructed using [VariantTy::tuple_types]. #[derive(Debug, Copy, Clone)] pub struct VariantTyIterator<'a> { elem: Option<&'a VariantTy>, } impl<'a> VariantTyIterator<'a> { // rustdoc-stripper-ignore-next /// Creates a new iterator over the types of the specified [VariantTy]. /// /// Returns `Ok` if the type is a definite tuple or dictionary entry type, /// `Err` otherwise. pub fn new(ty: &'a VariantTy) -> Result { if (ty.is_tuple() && ty != VariantTy::TUPLE) || ty.is_dict_entry() { Ok(Self { elem: ty.first() }) } else { Err(bool_error!( "Expected a definite tuple or dictionary entry type" )) } } } impl<'a> Iterator for VariantTyIterator<'a> { type Item = &'a VariantTy; #[doc(alias = "g_variant_type_next")] fn next(&mut self) -> Option { let elem = self.elem?; self.elem = elem.next(); Some(elem) } } impl iter::FusedIterator for VariantTyIterator<'_> {} #[cfg(test)] mod tests { use super::*; unsafe fn equal(ptr1: *const T, ptr2: *const U) -> bool { from_glib(ffi::g_variant_type_equal( ptr1 as *const _, ptr2 as *const _, )) } #[test] fn new() { let ty = VariantTy::new("((iii)s)").unwrap(); unsafe { assert!(equal(ty.as_ptr(), b"((iii)s)\0" as *const u8)); } } #[test] fn new_empty() { assert!(VariantTy::new("").is_err()); } #[test] fn new_with_nul() { assert!(VariantTy::new("((iii\0)s)").is_err()); } #[test] fn new_too_short() { assert!(VariantTy::new("((iii").is_err()); } #[test] fn new_too_long() { assert!(VariantTy::new("(iii)s").is_err()); } #[test] fn eq() { let ty1 = VariantTy::new("((iii)s)").unwrap(); let ty2 = VariantTy::new("((iii)s)").unwrap(); assert_eq!(ty1, ty2); assert_eq!(ty1, "((iii)s)"); unsafe { assert!(equal(ty1.as_ptr(), ty2.as_ptr())); } } #[test] fn ne() { let ty1 = VariantTy::new("((iii)s)").unwrap(); let ty2 = VariantTy::new("((iii)o)").unwrap(); assert_ne!(ty1, ty2); assert_ne!(ty1, "((iii)o)"); unsafe { assert!(!equal(ty1.as_ptr(), ty2.as_ptr())); } } #[test] fn from_bytes() { unsafe { let ty = VariantTy::from_ptr(b"((iii)s)" as *const u8 as *const _); assert_eq!(ty, "((iii)s)"); assert!(equal(ty.as_ptr(), "((iii)s)".as_ptr())); } } #[test] fn to_owned() { let ty1 = VariantTy::new("((iii)s)").unwrap(); let ty2 = ty1.to_owned(); assert_eq!(ty1, ty2); assert_eq!(ty2, "((iii)s)"); unsafe { assert!(equal(ty1.as_ptr(), ty2.as_ptr())); } } #[test] fn value() { let ty1 = VariantType::new("*").unwrap(); let tyv = ty1.to_value(); let ty2 = tyv.get::().unwrap(); assert_eq!(ty1, ty2); let ty3 = VariantTy::new("*").unwrap(); let tyv2 = ty3.to_value(); let ty4 = tyv2.get::().unwrap(); assert_eq!(ty3, ty4); let ty5 = VariantTy::ANY; let tyv3 = ty5.to_value(); let ty6 = tyv3.get::().unwrap(); assert_eq!(ty5, ty6); } #[test] fn type_() { assert_eq!(VariantTy::static_type(), VariantType::static_type()) } #[test] fn tuple_iter() { let ty = VariantTy::new("((iii)s)").unwrap(); let types: Vec<_> = ty.tuple_types().map(|t| t.as_str()).collect(); assert_eq!(&types, &["(iii)", "s"]); } } glib-0.20.9/src/win32.rs000064400000000000000000000076261046102023000127430ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::path::PathBuf; use crate::{ffi, translate::*, GString, StrV}; #[doc(alias = "GWin32OSType")] #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] pub enum Win32OSType { #[doc(alias = "G_WIN32_OS_ANY")] Any, #[doc(alias = "G_WIN32_OS_WORKSTATION")] Workstation, #[doc(alias = "G_WIN32_OS_SERVER")] Server, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for Win32OSType { type GlibType = ffi::GWin32OSType; #[inline] fn into_glib(self) -> Self::GlibType { match self { Self::Any => ffi::G_WIN32_OS_ANY, Self::Workstation => ffi::G_WIN32_OS_WORKSTATION, Self::Server => ffi::G_WIN32_OS_SERVER, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for Win32OSType { #[inline] unsafe fn from_glib(value: ffi::GWin32OSType) -> Self { match value { ffi::G_WIN32_OS_ANY => Self::Any, ffi::G_WIN32_OS_WORKSTATION => Self::Workstation, ffi::G_WIN32_OS_SERVER => Self::Server, value => Self::__Unknown(value), } } } #[doc(alias = "g_win32_check_windows_version")] pub fn win32_check_windows_version( major: i32, minor: i32, spver: i32, os_type: Win32OSType, ) -> bool { unsafe { from_glib(ffi::g_win32_check_windows_version( major, minor, spver, os_type.into_glib(), )) } } #[doc(alias = "g_win32_get_command_line")] #[doc(alias = "get_command_line")] pub fn win32_command_line() -> StrV { unsafe { FromGlibPtrContainer::from_glib_full(ffi::g_win32_get_command_line()) } } #[doc(alias = "g_win32_error_message")] pub fn win32_error_message(error: i32) -> GString { unsafe { from_glib_full(ffi::g_win32_error_message(error)) } } #[doc(alias = "g_win32_getlocale")] pub fn win32_getlocale() -> GString { unsafe { from_glib_full(ffi::g_win32_getlocale()) } } #[doc(alias = "g_win32_get_package_installation_directory_of_module")] #[doc(alias = "get_package_installation_directory_of_module")] pub fn win32_package_installation_directory_of_module( hmodule: std::os::windows::raw::HANDLE, ) -> Result { // # Safety // The underlying `GetModuleFilenameW` function has three possible // outcomes when a raw pointer get passed to it: // - When the pointer is a valid HINSTANCE of a DLL (e.g. acquired // through the `GetModuleHandleW`), it sets a file path to the // assigned "out" buffer and sets the return value to be the length // of said path string // - When the pointer is null, it sets the full path of the process' // executable binary to the assigned buffer and sets the return value // to be the length of said string // - Whenever the provided buffer size is too small, it will set a // truncated version of the path and return the length of said string // while also setting the thread-local last-error code to // `ERROR_INSUFFICIENT_BUFFER` (evaluates to 0x7A) // - When the pointer is not a valid HINSTANCE that isn't NULL (e.g. // a pointer to some GKeyFile), it will return 0 and set the last-error // code to `ERROR_MOD_NOT_FOUND` (evaluates to 0x7E) // // The `g_win32_get_package_installation_directory_of_module` already // handles all of the outcomes gracefully by: // - Preallocating a MAX_PATH-long array of wchar_t for the out buffer, // so that outcome #3 can be safely assumed to never happen // - Returning NULL when outcome #4 happens match unsafe { from_glib_full::<_, Option>( ffi::g_win32_get_package_installation_directory_of_module(hmodule), ) } { Some(pb) => Ok(pb), None => Err(std::io::Error::last_os_error()), } } glib-0.20.9/src/wrapper.rs000064400000000000000000000350241046102023000134520ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! `IMPL` The `wrapper!` macro and miscellaneous wrapper traits. // rustdoc-stripper-ignore-next /// Defines a wrapper type and implements the appropriate traits. /// /// The basic syntax is /// /// ```ignore /// wrapper! { /// /// Your documentation goes here /// pub struct $name($kind<$foreign>); /// /// match fn { /// $fn_name => /* a closure-like expression */, /// ... /// } /// } /// ``` /// /// This creates a wrapper named `$name` around the foreign type /// `$foreign` of `$kind` — one of [`Boxed`][#boxed], /// [`Shared`][#shared], or [`Object`][#object]. /// /// Inside the `match fn` block there are closure-like expressions to /// provide ways of copying/freeing, or referencing/unreferencing the /// value that you are wrapping. These expressions will be evaluated /// in an `unsafe` context, since they frequently invoke `extern` /// functions from an FFI crate. /// /// What follows is a description of each of the possible `$kind`: /// [`Boxed`][#boxed], [`Shared`][#shared], and [`Object`][#object]; /// note that each supports different sets of `$fn_name` inside the /// `match fn` block. Also, `Object` may require you to specify /// things like the class struct to wrap, plus any interfaces that the /// class implements. /// /// ### Boxed (heap allocated) /// /// Boxed records with single ownership allocated on the heap. /// /// With no registered `glib_ffi::GType`: /// /// ```ignore /// wrapper! { /// /// Text buffer iterator /// pub struct TextIter(Boxed); /// /// match fn { /// copy => |ptr| ffi::gtk_text_iter_copy(ptr), /// free => |ptr| ffi::gtk_text_iter_free(ptr), /// } /// } /// ``` /// /// `copy`: `|*const $foreign| -> *mut $foreign` creates a copy of the value. /// /// `free`: `|*mut $foreign|` frees the value. /// /// With a registered `glib_ffi::GType`: /// /// ```ignore /// wrapper! { /// /// Text buffer iterator /// pub struct TextIter(Boxed); /// /// match fn { /// copy => |ptr| ffi::gtk_text_iter_copy(ptr), /// free => |ptr| ffi::gtk_text_iter_free(ptr), /// type_ => || ffi::gtk_text_iter_get_type(), /// } /// } /// ``` /// /// `type_`: `|| -> glib_ffi::GType` (optional) returns the /// `glib_ffi::GType` that corresponds to the foreign struct. /// /// ### BoxedInline (inline, stack allocated) /// /// Boxed records with single ownership allocated on the stack or otherwise inline. /// With no registered `glib_ffi::GType`: /// /// ```ignore /// wrapper! { /// /// Text buffer iterator /// pub struct TextIter(BoxedInline); /// /// match fn { /// copy => |ptr| ffi::gtk_text_iter_copy(ptr), /// free => |ptr| ffi::gtk_text_iter_free(ptr), /// } /// } /// ``` /// /// `copy`: `|*const $foreign| -> *mut $foreign` (optional) creates a heap allocated copy of the value. /// /// `free`: `|*mut $foreign|` (optional) frees the value. /// /// With a registered `glib_ffi::GType`: /// /// ```ignore /// wrapper! { /// /// Text buffer iterator /// pub struct TextIter(BoxedInline); /// /// match fn { /// copy => |ptr| ffi::gtk_text_iter_copy(ptr), /// free => |ptr| ffi::gtk_text_iter_free(ptr), /// type_ => || ffi::gtk_text_iter_get_type(), /// } /// } /// ``` /// /// `type_`: `|| -> glib_ffi::GType` (optional) returns the /// `glib_ffi::GType` that corresponds to the foreign struct. /// /// ### Shared /// /// Records with reference-counted, shared ownership. /// /// With no registered `glib_ffi::GType`: /// /// ```ignore /// wrapper! { /// /// Object holding timing information for a single frame. /// pub struct FrameTimings(Shared); /// /// match fn { /// ref => |ptr| ffi::gdk_frame_timings_ref(ptr), /// unref => |ptr| ffi::gdk_frame_timings_unref(ptr), /// } /// } /// ``` /// /// `ref`: `|*mut $foreign|` increases the refcount. /// /// `unref`: `|*mut $foreign|` decreases the refcount. /// /// With a registered `glib_ffi::GType`: /// /// ```ignore /// wrapper! { /// /// Object holding timing information for a single frame. /// pub struct FrameTimings(Shared); /// /// match fn { /// ref => |ptr| ffi::gdk_frame_timings_ref(ptr), /// unref => |ptr| ffi::gdk_frame_timings_unref(ptr), /// type_ => || ffi::gdk_frame_timings_get_type(), /// } /// } /// ``` /// /// `type_`: `|| -> glib_ffi::GType` (optional) returns the /// `glib_ffi::GType` that corresponds to the foreign struct. /// /// ### Object /// /// Objects -- classes. Note that the class name, if available, must be specified after the /// $foreign type; see below for [non-derivable classes][#non-derivable-classes]. /// /// The basic syntax is this: /// /// ```ignore /// wrapper! { /// /// Your documentation goes here /// pub struct InstanceName(Object) /// @extends ParentClass, GrandparentClass, ..., /// @implements Interface1, Interface2, ...; /// /// match fn { /// type_ => || ffi::instance_get_type(), /// } /// } /// ``` /// /// `type_`: `|| -> glib_ffi::GType` returns the `glib_ffi::GType` /// that corresponds to the foreign class. /// /// #### All parent classes must be specified /// /// In the example above, "`@extends ParentClass, GrandparentClass, ...,`" is where you must /// specify all the parent classes of the one you are wrapping. The uppermost parent class, /// `glib::Object`, must not be specified. /// /// For example, `ffi::GtkWindowGroup` derives directly from /// `GObject`, so it can be simply wrapped as follows: /// /// ```ignore /// wrapper! { /// pub struct WindowGroup(Object); /// /// match fn { /// type_ => || ffi::gtk_window_group_get_type(), /// } /// } /// ``` /// /// In contrast, `ffi::GtkButton` has a parent, grandparent, etc. classes, which must be specified: /// /// ```ignore /// wrapper! { /// pub struct Button(Object) @extends Bin, Container, Widget; /// // see note on interfaces in the example below /// /// match fn { /// type_ => || ffi::gtk_button_get_type(), /// } /// } /// ``` /// /// #### Objects which implement interfaces /// /// The example above is incomplete, since `ffi::GtkButton` actually implements two interfaces, /// `Buildable` and `Actionable`. In this case, they must be specified after all the parent classes /// behind the `@implements` keyword: /// /// ```ignore /// wrapper! { /// pub struct Button(Object) /// @extends Bin, Container, Widget, // parent classes /// @implements Buildable, Actionable; // interfaces /// /// match fn { /// type_ => || ffi::gtk_button_get_type(), /// } /// } /// ``` /// /// #### Non-derivable classes /// /// By convention, GObject implements "final" classes, i.e. those who /// cannot be subclassed, by *not* exposing a public Class struct. /// This way it is not possible to override any methods, as there are /// no `klass.method_name` fields to overwrite. In this case, don't /// specify a FFI class name at all in the `Object<>` part: /// /// ```ignore /// wrapper! { /// pub struct Clipboard(Object); /// ... /// } /// ``` /// /// #### Interfaces /// /// Interfaces are passed in the same way to the macro but instead of specifying /// `Object`, `Interface` has to be specified: /// /// ```ignore /// wrapper! { /// pub struct TreeModel(Interface); /// ... /// } /// ``` /// /// #### Interfaces with prerequisites /// /// Interfaces can declare prerequisites, i.e. the classes from which types that implement the /// interface have to inherit or interfaces that have to be implemented: /// /// ```ignore /// wrapper! { /// pub struct TreeSortable(Interface) @requires TreeModel; /// ... /// } /// ``` /// /// [#boxed]: #boxed /// [#shared]: #shared /// [#object]: #object /// [#non-derivable-classes]: #non-derivable-classes #[macro_export] macro_rules! wrapper { // Boxed ( $(#[$attr:meta])* $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (Boxed<$ffi_name:ty>); match fn { copy => |$copy_arg:ident| $copy_expr:expr, free => |$free_arg:ident| $free_expr:expr, $( type_ => || $get_type_expr:expr, )? } ) => { $crate::glib_boxed_wrapper!( [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name, @copy $copy_arg $copy_expr, @free $free_arg $free_expr $(, @type_ $get_type_expr)? ); }; // BoxedInline ( $(#[$attr:meta])* $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (BoxedInline<$ffi_name:ty>); match fn { $( copy => |$copy_arg:ident| $copy_expr:expr, free => |$free_arg:ident| $free_expr:expr, )? $( init => |$init_arg:ident| $init_expr:expr, copy_into => |$copy_into_arg_dest:ident, $copy_into_arg_src:ident| $copy_into_expr:expr, clear => |$clear_arg:ident| $clear_expr:expr, )? $( type_ => || $get_type_expr:expr, )? } ) => { $crate::glib_boxed_inline_wrapper!( [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name $(, @copy $copy_arg $copy_expr, @free $free_arg $free_expr)? $(, @init $init_arg $init_expr, @copy_into $copy_into_arg_dest $copy_into_arg_src $copy_into_expr, @clear $clear_arg $clear_expr)? $(, @type_ $get_type_expr)? ); }; // BoxedInline ( $(#[$attr:meta])* $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (BoxedInline<$ffi_name:ty>); ) => { $crate::glib_boxed_inline_wrapper!( [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name ); }; // Shared ( $(#[$attr:meta])* $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (Shared<$ffi_name:ty>); match fn { ref => |$ref_arg:ident| $ref_expr:expr, unref => |$unref_arg:ident| $unref_expr:expr, $( type_ => || $get_type_expr:expr, )? } ) => { $crate::glib_shared_wrapper!( [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $ffi_name, @ref $ref_arg $ref_expr, @unref $unref_arg $unref_expr $(, @type_ $get_type_expr)? ); }; // Object, no parents ( $(#[$attr:meta])* $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (Object<$ffi_name:ty $(, $ffi_class_name:ty)?>) $(@implements $($implements:path),+)?; match fn { type_ => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!( @object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, (), $ffi_name, $( @ffi_class $ffi_class_name ,)? @type_ $get_type_expr, @extends [], @implements [$($($implements),+)?] ); }; // Object, parents ( $(#[$attr:meta])* $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (Object<$ffi_name:ty $(, $ffi_class_name:ty)?>) @extends $($extends:path),+ $(, @implements $($implements:path),+)?; match fn { type_ => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!( @object [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, (), $ffi_name, $( @ffi_class $ffi_class_name ,)? @type_ $get_type_expr, @extends [$($extends),+], @implements [$($($implements),+)?] ); }; // ObjectSubclass, no parents ( $(#[$attr:meta])* $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (ObjectSubclass<$subclass:ty>) $(@implements $($implements:path),+)?; ) => { $crate::glib_object_wrapper!( @object_subclass [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $subclass, @extends [], @implements [$($($implements),+)?] ); }; // ObjectSubclass, parents ( $(#[$attr:meta])* $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (ObjectSubclass<$subclass:ty>) @extends $($extends:path),+ $(, @implements $($implements:path),+)?; ) => { $crate::glib_object_wrapper!( @object_subclass [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $subclass, @extends [$($extends),+], @implements [$($($implements),+)?] ); }; // Interface ( $(#[$attr:meta])* $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (Interface<$ffi_name:ty $(, $ffi_class_name:ty)?>) $(@requires $($requires:path),+)?; match fn { type_ => || $get_type_expr:expr, } ) => { $crate::glib_object_wrapper!( @interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, $ffi_name, $( @ffi_class $ffi_class_name ,)? @type_ $get_type_expr, @requires [$( $($requires),+ )?] ); }; // ObjectInterface ( $(#[$attr:meta])* $visibility:vis struct $name:ident $(<$($generic:ident $(: $bound:tt $(+ $bound2:tt)*)?),+>)? (ObjectInterface<$iface_name:ty>) $(@requires $($requires:path),+)?; ) => { $crate::glib_object_wrapper!( @object_interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, $iface_name, @type_ $crate::translate::IntoGlib::into_glib(<$iface_name as $crate::subclass::interface::ObjectInterfaceType>::type_()), @requires [$( $($requires),+ )?] ); }; } glib-0.20.9/tests/bridged_logging.rs000064400000000000000000000111301046102023000154430ustar 00000000000000#![cfg(feature = "log")] use std::sync::{Arc, Mutex}; use glib::LogLevel; use rs_log::Log; #[derive(Debug, PartialEq, Eq)] struct LoggedEvent { level: LogLevel, fields: Vec<(String, Option)>, } fn setup_log_collector() -> Arc>> { let events = Arc::new(Mutex::new(Vec::new())); let event_writer = events.clone(); glib::log_set_writer_func(move |level, fields| { let fields = fields .iter() .map(|field| { ( field.key().to_string(), field.value_str().map(|s| s.to_owned()), ) }) .collect(); event_writer .lock() .unwrap() .push(LoggedEvent { level, fields }); glib::LogWriterOutput::Handled }); events } /// Test the glib Rust logger with different formats. /// /// We put everything into one test because we can only set the log writer func once. #[test] fn glib_logger_formats() { let events = setup_log_collector(); let record = rs_log::RecordBuilder::new() .target("test_target") .level(rs_log::Level::Info) .args(format_args!("test message")) .file(Some("/path/to/a/test/file.rs")) .line(Some(42)) .module_path(Some("foo::bar")) .build(); glib::GlibLogger::new( glib::GlibLoggerFormat::Plain, glib::GlibLoggerDomain::CrateTarget, ) .log(&record); let event = events.lock().unwrap().pop().unwrap(); assert_eq!( event, LoggedEvent { level: glib::LogLevel::Info, fields: vec![ ("GLIB_OLD_LOG_API".to_string(), Some("1".to_string())), ("MESSAGE".to_string(), Some("test message".to_string())), ("PRIORITY".to_string(), Some("6".to_string())), ("GLIB_DOMAIN".to_string(), Some("test_target".to_string())) ] } ); events.lock().unwrap().clear(); glib::GlibLogger::new( glib::GlibLoggerFormat::LineAndFile, glib::GlibLoggerDomain::CrateTarget, ) .log(&record); let event = events.lock().unwrap().pop().unwrap(); assert_eq!( event, LoggedEvent { level: glib::LogLevel::Info, fields: vec![ ("GLIB_OLD_LOG_API".to_string(), Some("1".to_string())), ( "MESSAGE".to_string(), Some("/path/to/a/test/file.rs:42: test message".to_string()) ), ("PRIORITY".to_string(), Some("6".to_string())), ("GLIB_DOMAIN".to_string(), Some("test_target".to_string())) ] } ); glib::GlibLogger::new( glib::GlibLoggerFormat::Structured, glib::GlibLoggerDomain::CrateTarget, ) .log(&record); let event = events.lock().unwrap().pop().unwrap(); assert_eq!( event, LoggedEvent { level: glib::LogLevel::Info, fields: vec![ ("PRIORITY".to_string(), Some("6".to_string())), ( "CODE_FILE".to_string(), Some("/path/to/a/test/file.rs".to_string()) ), ("CODE_LINE".to_string(), Some("42".to_string())), ("CODE_FUNC".to_string(), Some("foo::bar".to_string())), ("MESSAGE".to_string(), Some("test message".to_string())), ("GLIB_DOMAIN".to_string(), Some("test_target".to_string())) ] } ); // Structured logging without location fields glib::GlibLogger::new( glib::GlibLoggerFormat::Structured, glib::GlibLoggerDomain::CrateTarget, ) .log( &rs_log::RecordBuilder::new() .target("test_target") .level(rs_log::Level::Info) .args(format_args!("test message")) .build(), ); let event = events.lock().unwrap().pop().unwrap(); assert_eq!( event, LoggedEvent { level: glib::LogLevel::Info, fields: vec![ ("PRIORITY".to_string(), Some("6".to_string())), ("CODE_FILE".to_string(), Some("".to_string())), ("CODE_LINE".to_string(), Some("".to_string())), ( "CODE_FUNC".to_string(), Some("".to_string()) ), ("MESSAGE".to_string(), Some("test message".to_string())), ("GLIB_DOMAIN".to_string(), Some("test_target".to_string())) ] } ); } glib-0.20.9/tests/check_gir.rs000064400000000000000000000003461046102023000142620ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #[test] fn check_gir_file() { let res = gir_format_check::check_gir_file("Gir.toml"); println!("{res}"); assert_eq!(res.nb_errors, 0); } glib-0.20.9/tests/clone.rs000064400000000000000000000564721046102023000134570ustar 00000000000000// All the tests have their arguments used so they produce unused variable compiler warnings #![allow(unused_variables)] use std::{ cell::RefCell, panic, rc::Rc, sync::{Arc, Mutex}, thread, }; use futures_executor::block_on; use glib::clone; struct State { count: i32, started: bool, } impl State { fn new() -> Self { Self { count: 0, started: false, } } } #[test] fn clone_and_references() { let state = Rc::new(RefCell::new(State::new())); let ref_state = &state; assert!(!ref_state.borrow().started); let closure = { clone!( #[weak] ref_state, move || { ref_state.borrow_mut().started = true; } ) }; closure(); assert!(ref_state.borrow().started); } #[test] fn subfields_renaming() { struct Foo { v: Rc, } impl Foo { fn foo(&self) { let state = Rc::new(RefCell::new(State::new())); let closure = clone!( #[strong(rename_to = v)] self.v, #[weak(rename_to = hello)] state, move |_| { println!("v: {v}"); hello.borrow_mut().started = true; } ); closure(2); } } Foo { v: Rc::new(0) }.foo(); } #[test] fn renaming() { let state = Rc::new(RefCell::new(State::new())); assert!(!state.borrow().started); let closure = { clone!( #[weak(rename_to = hello)] state, move || { hello.borrow_mut().started = true; } ) }; closure(); assert!(state.borrow().started); } #[test] fn clone_closure() { let state = Rc::new(RefCell::new(State::new())); assert!(!state.borrow().started); let closure = { clone!( #[weak] state, move || { state.borrow_mut().started = true; } ) }; closure(); assert!(state.borrow().started); assert_eq!(state.borrow().count, 0); let closure = { let state2 = Rc::new(RefCell::new(State::new())); assert!(state.borrow().started); clone!( #[weak] state, #[strong] state2, move || { state.borrow_mut().count += 1; state.borrow_mut().started = true; state2.borrow_mut().started = true; } ) }; closure(); assert_eq!(state.borrow().count, 1); assert!(state.borrow().started); } #[test] fn clone_default_value() { let closure = { let state = Rc::new(RefCell::new(State::new())); clone!( #[weak] state, #[upgrade_or] 42, move |_| { state.borrow_mut().started = true; 10 } ) }; assert_eq!(42, closure(50)); } #[test] fn clone_panic() { let state = Arc::new(Mutex::new(State::new())); state.lock().expect("Failed to lock state mutex").count = 20; let closure = { let state2 = Arc::new(Mutex::new(State::new())); clone!( #[weak] state2, #[strong] state, #[upgrade_or_else] || panic!(), move |_| { state.lock().expect("Failed to lock state mutex").count = 21; state2.lock().expect("Failed to lock state2 mutex").started = true; 10 } ) }; let result = panic::catch_unwind(|| { closure(50); }); assert!(result.is_err()); assert_eq!(state.lock().expect("Failed to lock state mutex").count, 20); } #[test] fn clone_import_rename() { import_rename::test(); } mod import_rename { use glib::clone as clone_g; #[allow(unused_macros)] macro_rules! clone { ($($anything:tt)*) => { |_, _| panic!("The clone! macro doesn't support renaming") }; } #[allow(unused_variables)] pub fn test() { let n = 2; let closure: Box = Box::new(clone_g!( #[strong] n, move |_, _| println!("The clone! macro does support renaming") )); closure(0, 0); } } #[test] fn test_clone_macro_self_rename() { #[derive(Debug)] struct Foo { v: u8, } impl Foo { #[allow(dead_code)] fn foo(&self) { let closure = clone!( #[strong(rename_to = this)] self, move |_x| { println!("v: {this:?}"); } ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[strong(rename_to = this)] self, move || { println!("v: {this:?}"); } ); let closure = clone!( #[strong(rename_to = this)] self, move |_x| println!("v: {this:?}") ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[strong(rename_to = this)] self, move || println!("v: {this:?}") ); // Fields now! let closure = clone!( #[strong(rename_to = v)] self.v, move |_x| { println!("v: {v:?}"); } ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[strong(rename_to = v)] self.v, move || println!("v: {v:?}") ); } } } #[test] fn test_clone_macro_rename() { let v = Rc::new(1); let closure = clone!( #[weak(rename_to = y)] v, #[upgrade_or_panic] move |_x| { println!("v: {y}"); } ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[weak(rename_to = y)] v, #[upgrade_or_panic] move || println!("v: {y}") ); let closure = clone!( #[strong(rename_to = y)] v, move |_x| { println!("v: {y}"); } ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[strong(rename_to = y)] v, move || println!("v: {y}") ); let closure = clone!( #[weak(rename_to = y)] v, move |_x| { println!("v: {y}"); } ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[weak(rename_to = y)] v, move || println!("v: {y}") ); let closure = clone!( #[strong(rename_to = y)] v, move |_x| { println!("v: {y}"); } ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[strong(rename_to = y)] v, move || println!("v: {y}") ); let closure = clone!( #[weak(rename_to = y)] v, #[upgrade_or] true, move |_x| false ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[weak(rename_to = y)] v, #[upgrade_or_else] || true, move || false ); let closure = clone!( #[strong(rename_to = y)] v, move |_x| false ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[strong(rename_to = y)] v, move || false ); } #[test] fn test_clone_macro_simple() { let v = Rc::new(1); let closure = clone!( #[weak] v, #[upgrade_or_panic] move |_x| { println!("v: {v}"); } ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[weak] v, #[upgrade_or_panic] move || println!("v: {v}") ); let closure = clone!( #[strong] v, move |_x| { println!("v: {v}"); } ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[strong] v, move || println!("v: {v}") ); let closure = clone!( #[weak] v, move |_x| { println!("v: {v}"); } ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[weak] v, move || println!("v: {v}") ); let closure = clone!( #[strong] v, move |_x| { println!("v: {v}"); } ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[strong] v, move || println!("v: {v}") ); let closure = clone!( #[weak] v, #[upgrade_or] true, move |_x| false ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[weak] v, #[upgrade_or_else] || true, move || false ); let closure = clone!( #[strong] v, move |_x| false ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[strong] v, move || false ); } #[test] fn test_clone_macro_double_simple() { let v = Rc::new(1); let w = Rc::new(2); let closure = clone!( #[weak] v, #[weak] w, #[upgrade_or_panic] move |_x| { println!("v: {v}, w: {w}"); } ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[weak] v, #[weak] w, #[upgrade_or_panic] move || println!("v: {v}, w: {w}") ); let closure = clone!( #[strong] v, #[strong] w, move |_x| { println!("v: {v}, w: {w}"); } ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[strong] v, #[strong] w, move || println!("v: {v}, w: {w}") ); let closure = clone!( #[weak] v, #[weak] w, move |_x| { println!("v: {v}, w: {w}"); } ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[weak] v, #[weak] w, move || println!("v: {v}, w: {w}") ); let closure = clone!( #[strong] v, #[strong] w, move |_x| { println!("v: {v}, w: {w}"); } ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[strong] v, #[strong] w, move || println!("v: {v}, w: {w}") ); let closure = clone!( #[weak] v, #[weak] w, #[upgrade_or] true, move |_x| false ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[weak] v, #[weak] w, #[upgrade_or_else] || true, move || false ); let closure = clone!( #[strong] v, #[strong] w, move |_x| false ); closure(0i8); // to prevent compiler error for unknown `x` type. let _ = clone!( #[strong] v, #[strong] w, move || false ); } #[test] fn test_clone_macro_double_rename() { let v = Rc::new(1); let w = Rc::new(2); let done = Rc::new(RefCell::new(0)); let closure = clone!( #[weak(rename_to = x)] v, #[weak] w, #[upgrade_or_panic] move |z| z + *x + *w ); assert_eq!(closure(1i8), 4i8); let closure = clone!( #[weak(rename_to = x)] v, #[weak] w, #[upgrade_or_panic] move || 1 ); assert_eq!(closure(), 1); let closure = clone!( #[weak] v, #[weak(rename_to = x)] w, #[upgrade_or_panic] move |z| z + *v + *x ); assert_eq!(closure(10i8), 13i8); let closure = clone!( #[weak] v, #[weak(rename_to = x)] w, #[upgrade_or_panic] move || 2 + *x ); assert_eq!(closure(), 4); let closure = clone!( #[strong(rename_to = x)] v, #[strong] w, move |z| z + *x + *w ); assert_eq!(closure(3i8), 6i8); let closure = clone!( #[strong(rename_to = x)] v, #[strong] w, move || 4 + *w ); assert_eq!(closure(), 6); let closure = clone!( #[strong] v, #[strong(rename_to = x)] w, move |z| z + *v + *x ); assert_eq!(closure(0i8), 3i8); let closure = clone!( #[strong] v, #[strong(rename_to = x)] w, move || 5 ); assert_eq!(closure(), 5); let t_done = done.clone(); let closure = clone!( #[weak(rename_to = x)] v, #[weak] w, move |z| { *t_done.borrow_mut() = z + *x + *w; } ); closure(4i8); assert_eq!(*done.borrow(), 7); let t_done = done.clone(); let closure = clone!( #[weak(rename_to = x)] v, #[weak] w, move || *t_done.borrow_mut() = *x + *w ); closure(); assert_eq!(*done.borrow(), 3); let t_done = done.clone(); let closure = clone!( #[weak] v, #[weak(rename_to = x)] w, move |z| { *t_done.borrow_mut() = z + *v + *x; } ); closure(8i8); assert_eq!(*done.borrow(), 11i8); let t_done = done.clone(); let closure = clone!( #[weak] v, #[weak(rename_to = x)] w, move || *t_done.borrow_mut() = *v * *x ); closure(); assert_eq!(*done.borrow(), 2); let t_done = done.clone(); let closure = clone!( #[strong(rename_to = x)] v, #[strong] w, move |z| { *t_done.borrow_mut() = z + *x + *w; } ); closure(9i8); assert_eq!(*done.borrow(), 12i8); let t_done = done.clone(); let closure = clone!( #[strong(rename_to = x)] v, #[strong] w, move || *t_done.borrow_mut() = *x - *w ); closure(); assert_eq!(*done.borrow(), -1); let t_done = done.clone(); let closure = clone!( #[strong] v, #[strong(rename_to = x)] w, move |z| { *t_done.borrow_mut() = *v + *x * z; } ); closure(2i8); assert_eq!(*done.borrow(), 5); let t_done = done.clone(); let closure = clone!( #[strong] v, #[strong(rename_to = x)] w, move || *t_done.borrow_mut() = *x - *v ); closure(); assert_eq!(*done.borrow(), 1); let closure = clone!( #[weak(rename_to = x)] v, #[weak] w, #[upgrade_or] true, move |_| false ); assert!(!closure(0u8)); let closure = clone!( #[weak(rename_to = x)] v, #[weak] w, #[upgrade_or_else] || true, move || false ); assert!(!closure()); let closure = clone!( #[weak] v, #[weak(rename_to = x)] w, #[upgrade_or] true, move |_| false ); assert!(!closure("a")); let closure = clone!( #[weak] v, #[weak(rename_to = x)] w, #[upgrade_or_else] || true, move || false ); assert!(!closure()); let closure = clone!( #[weak] v, #[weak(rename_to = x)] w, #[upgrade_or_default] move || true ); assert!(closure()); let closure = clone!( #[strong(rename_to = x)] v, #[strong] w, move |_| false ); assert!(!closure('a')); let closure = clone!( #[strong(rename_to = x)] v, #[strong] w, move || false ); assert!(!closure()); let closure = clone!( #[strong] v, #[strong(rename_to = x)] w, move |_| false ); assert!(!closure(12.)); let closure = clone!( #[strong] v, #[strong(rename_to = x)] w, move || false ); assert!(!closure()); } #[test] fn test_clone_macro_typed_args() { macro_rules! test_closure { ($kind:tt, panic) => {{ // We need Arc and Mutex to use them below in the thread. let check = Arc::new(Mutex::new(0)); let v = Arc::new(Mutex::new(1)); let w = Arc::new(Mutex::new(1)); let closure = clone!( #[$kind(rename_to = x)] v, #[$kind] w, #[weak] check, #[upgrade_or_panic] move |arg: i8| { *x.lock().unwrap() += arg; *w.lock().unwrap() += arg; *check.lock().unwrap() += 1; } ); closure(1); assert_eq!(2, *v.lock().unwrap()); assert_eq!(2, *w.lock().unwrap()); assert_eq!(1, *check.lock().unwrap()); let closure2 = clone!( #[$kind] v, #[$kind(rename_to = x)] w, #[weak] check, #[upgrade_or_panic] move |arg: i8| { *v.lock().unwrap() += arg; *x.lock().unwrap() += arg; *check.lock().unwrap() += 1; } ); closure2(1); assert_eq!(3, *v.lock().unwrap()); assert_eq!(3, *w.lock().unwrap()); assert_eq!(2, *check.lock().unwrap()); #[allow(unused_macro_rules)] macro_rules! inner { (strong) => {{}}; (weak) => {{ std::mem::drop(v); std::mem::drop(w); // We use the threads to ensure that the closure panics as expected. assert!(thread::spawn(move || { closure(1); }) .join() .is_err()); assert_eq!(2, *check.lock().unwrap()); assert!(thread::spawn(move || { closure2(1); }) .join() .is_err()); assert_eq!(2, *check.lock().unwrap()); }}; } inner!($kind); }}; ($kind:tt) => {{ let check = Rc::new(RefCell::new(0)); let v = Rc::new(RefCell::new(1)); let w = Rc::new(RefCell::new(1)); let closure = clone!( #[$kind(rename_to = x)] v, #[$kind] w, #[weak] check, move |arg: i8| { *x.borrow_mut() += arg; *w.borrow_mut() += arg; *check.borrow_mut() += 1; } ); closure(1); assert_eq!(2, *v.borrow()); assert_eq!(2, *w.borrow()); assert_eq!(1, *check.borrow()); let closure2 = clone!( #[$kind] v, #[$kind(rename_to = x)] w, #[weak] check, move |arg: i8| { *v.borrow_mut() += arg; *x.borrow_mut() += arg; *check.borrow_mut() += 1; } ); closure2(1); assert_eq!(3, *v.borrow()); assert_eq!(3, *w.borrow()); assert_eq!(2, *check.borrow()); #[allow(unused_macro_rules)] macro_rules! inner { (strong) => {{}}; (weak) => {{ std::mem::drop(v); std::mem::drop(w); closure(1); assert_eq!(2, *check.borrow()); closure2(1); assert_eq!(2, *check.borrow()); }}; } inner!($kind); }}; } test_closure!(weak, panic); test_closure!(strong, panic); test_closure!(weak); test_closure!(strong); let check = Rc::new(RefCell::new(0)); let v = Rc::new(RefCell::new(1)); let w = Rc::new(RefCell::new(1)); let closure = clone!( #[weak] v, #[weak(rename_to = x)] w, #[weak] check, move |arg: i8, arg2| { *v.borrow_mut() = arg; *x.borrow_mut() = arg2; *check.borrow_mut() += 1; } ); closure(0, 9); assert_eq!(0, *v.borrow()); assert_eq!(9, *w.borrow()); assert_eq!(1, *check.borrow()); std::mem::drop(v); std::mem::drop(w); assert_eq!(1, *check.borrow()); } #[test] #[allow(clippy::bool_assert_comparison)] #[allow(clippy::nonminimal_bool)] fn test_clone_macro_upgrade_failure() { macro_rules! test_default { ($ret:expr, $($closure_body:tt)*) => {{ let v = Rc::new(1); let tmp = clone!(#[weak] v, #[upgrade_or_else] || $ret, move || $($closure_body)*); assert_eq!(tmp(), $($closure_body)*, "shouldn't use default-return value!"); ::std::mem::drop(v); assert_eq!(tmp(), $ret, "should use default-return value!"); }} } #[derive(PartialEq, Debug)] struct Foo(i32); test_default!(Foo(0), Foo(1)); #[derive(PartialEq, Debug)] struct Bar { x: i32, } test_default!(Bar { x: 0 }, Bar { x: 1 }); #[derive(PartialEq, Debug)] enum Enum { A, B(i32), C { x: i32 }, } test_default!(Enum::A, Enum::B(0)); test_default!(Enum::B(0), Enum::A); test_default!(Enum::C { x: 0 }, Enum::A); test_default!( { let x = 12; x + 2 }, 19 ); // This one is simply to check that we wait for the comma for the default-return value. test_default!(Enum::A == Enum::B(0) || false, true); } #[test] fn test_clone_macro_body() { let v = Arc::new(Mutex::new(0)); let closure = clone!( #[weak] v, move || { std::thread::spawn(move || { let mut lock = v.lock().expect("failed to lock"); for _ in 1..=10 { *lock += 1; } }) .join() .expect("thread::spawn failed"); } ); closure(); assert_eq!(10, *v.lock().expect("failed to lock")); } #[test] fn test_clone_macro_async_kinds() { let v = Rc::new(RefCell::new(1)); block_on(clone!( #[weak] v, async move { *v.borrow_mut() += 1; } )); assert_eq!(*v.borrow(), 2); } glib-0.20.9/tests/derive.rs000064400000000000000000000012471046102023000136230ustar 00000000000000use std::marker::PhantomData; use glib::{Downgrade, Object}; #[test] fn derive_downgrade() { #[derive(Downgrade)] pub struct NewType(Object); #[derive(Downgrade)] pub struct Struct { o1: Object, o2: std::rc::Rc, } #[derive(Downgrade)] pub enum Enum { None, Pair { x: Object, y: Object }, Unit(), SingleUnnamed(Object), MultipleUnnamed(Object, Object, Object), } #[derive(Downgrade)] pub struct TypedWrapper(Object, PhantomData); #[derive(Downgrade)] pub enum TypedEnum { This(Object, PhantomData), That(Object, PhantomData), } } glib-0.20.9/tests/log.rs000064400000000000000000000077651046102023000131410ustar 00000000000000use std::sync::{Arc, Mutex}; use glib::*; #[derive(Default)] struct Counters { criticals: usize, warnings: usize, messages: usize, infos: usize, debugs: usize, } fn assert_counts( count: &Arc>, criticals: usize, warnings: usize, messages: usize, infos: usize, debugs: usize, ) { let count = count.lock().expect("failed to lock 1"); assert_eq!(count.criticals, criticals); assert_eq!(count.warnings, warnings); assert_eq!(count.messages, messages); assert_eq!(count.infos, infos); assert_eq!(count.debugs, debugs); } #[test] fn check_log_handlers() { // We set the fatal level explicitly in case it's set outside of the test. log_set_fatal_mask(Some("domain"), LogLevels::LEVEL_ERROR); // // log_set_default_handler check part // let count = Arc::new(Mutex::new(Counters::default())); log_set_default_handler(clone!( #[weak] count, move |_, level, _| { match level { LogLevel::Critical => { count.lock().expect("failed to lock 3").criticals += 1; } LogLevel::Warning => { count.lock().expect("failed to lock 4").warnings += 1; } LogLevel::Message => { count.lock().expect("failed to lock 5").messages += 1; } LogLevel::Info => { count.lock().expect("failed to lock 6").infos += 1; } LogLevel::Debug => { count.lock().expect("failed to lock 7").debugs += 1; } _ => unreachable!(), } } )); assert_counts(&count, 0, 0, 0, 0, 0); g_warning!(Some("domain"), "hello"); assert_counts(&count, 0, 1, 0, 0, 0); g_warning!(Some("domain"), "hello"); g_critical!(Some("domain"), "hello"); g_warning!(Some("domain"), "hello"); g_message!(Some("domain"), "hello"); g_info!(Some("domain"), "hello"); g_debug!(Some("domain"), "hello"); g_info!(Some("domain"), "hello"); assert_counts(&count, 1, 3, 1, 2, 1); // We now unset our callback and check if it has really been unset. log_unset_default_handler(); g_info!(Some("domain"), "hello"); g_debug!(Some("domain"), "hello"); assert_counts(&count, 1, 3, 1, 2, 1); // // log_set_handler check part // let count = Arc::new(Mutex::new(Counters::default())); // We set the handler for both warning and debug. let handler_id = log_set_handler( Some("domain"), LogLevels::LEVEL_WARNING | LogLevels::LEVEL_DEBUG, false, false, clone!( #[weak] count, move |_, level, _| { match level { LogLevel::Warning => { count.lock().expect("failed to lock 4").warnings += 1; } LogLevel::Debug => { count.lock().expect("failed to lock 7").debugs += 1; } _ => unreachable!(), } } ), ); assert_counts(&count, 0, 0, 0, 0, 0); g_warning!(Some("domain"), "hello"); assert_counts(&count, 0, 1, 0, 0, 0); g_critical!(Some("domain"), "hello"); g_message!(Some("domain"), "hello"); g_info!(Some("domain"), "hello"); assert_counts(&count, 0, 1, 0, 0, 0); g_debug!(Some("domain"), "hello"); assert_counts(&count, 0, 1, 0, 0, 1); // We check that only "domain" messages are calling our callback. g_debug!(Some("not-domain"), "hello"); g_warning!(Some("not-domain"), "hello"); assert_counts(&count, 0, 1, 0, 0, 1); log_remove_handler(Some("domain"), handler_id); g_critical!(Some("domain"), "hello"); g_message!(Some("domain"), "hello"); g_info!(Some("domain"), "hello"); g_debug!(Some("domain"), "hello"); g_warning!(Some("domain"), "hello"); assert_counts(&count, 0, 1, 0, 0, 1); } glib-0.20.9/tests/print.rs000064400000000000000000000034051046102023000134770ustar 00000000000000use std::sync::{Arc, Mutex}; use glib::*; // Funny thing: we can't put those two tests in two different functions, otherwise they might // conflict with the results of the other one (or it would be mandatory to run the tests on only // one thread). #[test] fn check_print_handler() { // // g_print check part // let count = Arc::new(Mutex::new(0)); set_print_handler(clone!( #[weak] count, move |_| { // we don't care about the message in here! *count.lock().expect("failed to lock 1") += 1; } )); g_print!("test"); assert_eq!(*count.lock().expect("failed to lock 2"), 1); g_printerr!("one"); assert_eq!(*count.lock().expect("failed to lock 3"), 1); g_print!("another"); assert_eq!(*count.lock().expect("failed to lock 4"), 2); unset_print_handler(); g_print!("tadam"); assert_eq!(*count.lock().expect("failed to lock 5"), 2); g_printerr!("toudoum"); assert_eq!(*count.lock().expect("failed to lock 6"), 2); // // g_printerr check part // let count = Arc::new(Mutex::new(0)); set_printerr_handler(clone!( #[weak] count, move |_| { // we don't care about the message in here! *count.lock().expect("failed to lock a") += 1; } )); g_printerr!("test"); assert_eq!(*count.lock().expect("failed to lock b"), 1); g_print!("one"); assert_eq!(*count.lock().expect("failed to lock c"), 1); g_printerr!("another"); assert_eq!(*count.lock().expect("failed to lock d"), 2); unset_printerr_handler(); g_printerr!("tadam"); assert_eq!(*count.lock().expect("failed to lock e"), 2); g_print!("toudoum"); assert_eq!(*count.lock().expect("failed to lock f"), 2); } glib-0.20.9/tests/regex_compiletest/01-not-dangling.rs000064400000000000000000000014541046102023000206660ustar 00000000000000fn main() { let r = glib::Regex::new( "hello", glib::RegexCompileFlags::DEFAULT, glib::RegexMatchFlags::DEFAULT, ) .unwrap() .unwrap(); // implicit drop { let s = glib::GString::from("hello"); let match_info = r .match_(s.as_gstr(), glib::RegexMatchFlags::DEFAULT) .expect("should match"); assert_eq!(match_info.fetch_all(), vec!["hello"]); // match_info is dropped // s is dropped } // explicit drop { let s = glib::GString::from("hello"); let match_info = r .match_(s.as_gstr(), glib::RegexMatchFlags::DEFAULT) .expect("should match"); assert_eq!(match_info.fetch_all(), vec!["hello"]); drop(match_info); drop(s); } } glib-0.20.9/tests/regex_compiletest/02-dangling.rs000064400000000000000000000006001046102023000200610ustar 00000000000000fn main() { let r = glib::Regex::new( "hello", glib::RegexCompileFlags::DEFAULT, glib::RegexMatchFlags::DEFAULT, ) .unwrap() .unwrap(); let s = glib::GString::from("hello"); let match_info = r .match_(s.as_gstr(), glib::RegexMatchFlags::DEFAULT) .expect("should match"); dbg!(match_info.fetch_all()); drop(s); } glib-0.20.9/tests/regex_compiletest/03-static-value.rs000064400000000000000000000011021046102023000206760ustar 00000000000000#![allow(unused)] use glib::prelude::*; fn main() { let r = glib::Regex::new( "hello", glib::RegexCompileFlags::DEFAULT, glib::RegexMatchFlags::DEFAULT, ) .unwrap() .unwrap(); let s = glib::GStr::from_str_until_nul("hello\0").unwrap(); let match_info = r .match_(s, glib::RegexMatchFlags::DEFAULT) .expect("should match"); assert_eq!(match_info.fetch_all(), vec!["hello"]); let v: glib::Value = match_info.to_value(); drop(match_info); let match_info = v.get::>().unwrap(); } glib-0.20.9/tests/regex_compiletest/04-nonstatic-value.rs000064400000000000000000000010561046102023000214220ustar 00000000000000#![allow(unused)] use glib::prelude::*; fn main() { let r = glib::Regex::new( "hello", glib::RegexCompileFlags::DEFAULT, glib::RegexMatchFlags::DEFAULT, ) .unwrap() .unwrap(); let s = glib::GString::from("hello"); let match_info = r .match_(s.as_gstr(), glib::RegexMatchFlags::DEFAULT) .expect("should match"); dbg!(match_info.fetch_all()); let v: glib::Value = match_info.to_value(); drop(match_info); drop(s); let match_info = v.get::>().unwrap(); } glib-0.20.9/tests/regex_compiletest/05-variance.rs000064400000000000000000000003551046102023000201000ustar 00000000000000use glib::MatchInfo; // pass fn covariance_check<'short>(input: MatchInfo<'static>) -> MatchInfo<'short> { input } // fail fn contravariance_check<'short>(input: MatchInfo<'short>) -> MatchInfo<'static> { input } fn main() {} glib-0.20.9/tests/regex_compiletest/05-variance.stderr000064400000000000000000000005331046102023000207550ustar 00000000000000error: lifetime may not live long enough --> tests/regex_compiletest/05-variance.rs:10:5 | 9 | fn contravariance_check<'short>(input: MatchInfo<'short>) -> MatchInfo<'static> { | ------ lifetime `'short` defined here 10 | input | ^^^^^ returning this value requires that `'short` must outlive `'static` glib-0.20.9/tests/regex_compiletest/06-property.rs000064400000000000000000000022421046102023000201720ustar 00000000000000use glib::prelude::*; use glib::subclass::prelude::*; use glib_macros::Properties; use std::cell::RefCell; pub mod imp { use super::*; #[derive(Properties, Default)] #[properties(wrapper_type = super::Foo)] pub struct Foo { #[property(get, set)] match_info: RefCell>>, } #[glib::derived_properties] impl ObjectImpl for Foo {} #[glib::object_subclass] impl ObjectSubclass for Foo { const NAME: &'static str = "MyFoo"; type Type = super::Foo; } } glib::wrapper! { pub struct Foo(ObjectSubclass); } fn main() { let myfoo: Foo = glib::object::Object::new(); let r = glib::Regex::new( "hello", glib::RegexCompileFlags::DEFAULT, glib::RegexMatchFlags::DEFAULT, ) .unwrap() .unwrap(); let s = glib::GStr::from_str_until_nul("hello\0").unwrap(); let match_info = r .match_(s, glib::RegexMatchFlags::DEFAULT) .expect("should match"); myfoo.set_match_info(match_info); let match_info: glib::MatchInfo<'_> = myfoo.match_info().unwrap(); assert_eq!(match_info.fetch_all(), vec!["hello"]); } glib-0.20.9/tests/regex_compiletest.rs000064400000000000000000000017121046102023000160640ustar 00000000000000#[test] pub fn test() { let t = trybuild2::TestCases::new(); t.pass("tests/regex_compiletest/01-not-dangling.rs"); // The exact error message format changed sometime between 1.70.0 and 1.73.0, // so the .stderr file would be incorrect for at least one CI run, // so use compile_fail_check_sub instead of compile_fail. t.compile_fail_check_sub( "tests/regex_compiletest/02-dangling.rs", "error[E0505]: cannot move out of `s` because it is borrowed", ); t.pass("tests/regex_compiletest/03-static-value.rs"); // See above about 02 t.compile_fail_check_sub( "tests/regex_compiletest/04-nonstatic-value.rs", "argument requires that `s` is borrowed for `'static`", ); // Don't use check_sub: Check the exact error message to ensure that only the contravariance check fails. t.compile_fail("tests/regex_compiletest/05-variance.rs"); t.pass("tests/regex_compiletest/06-property.rs"); } glib-0.20.9/tests/structured_log.rs000064400000000000000000000107351046102023000154140ustar 00000000000000#![allow(clippy::unnecessary_to_owned)] #![allow(clippy::unnecessary_cast)] #[test] fn structured_log() { use std::sync::{Arc, Mutex}; use glib::{gstr, prelude::*, GString, LogField, LogLevel}; let log = Arc::new(Mutex::new(Vec::new())); { let log = log.clone(); // can only be called once per test file glib::log_set_writer_func(move |level, fields| { let fields = fields .iter() .map(|f| { let value = if let Some(data) = f.user_data() { assert!(f.value_str().is_none()); format!("USERDATA: {data}") } else { f.value_str().unwrap().to_owned() }; (f.key().to_owned(), value) }) .collect::>(); log.lock().unwrap().push((level, fields)); glib::LogWriterOutput::Handled }); } glib::log_structured!( "test", LogLevel::Message, { "MY_META" => "abc"; "MESSAGE" => "normal with meta"; "MY_META2" => "def"; } ); glib::log_structured!( None, LogLevel::Message, { "MY_META" => "abc"; "MESSAGE" => "formatted with meta: {} {}", 123, 456.0; "MY_META2" => "def{}", "ghi"; "EMPTY" => b""; GString::from("MY_META3") => b"bstring".to_owned(); } ); glib::log_structured_array( LogLevel::Warning, &[ LogField::new( gstr!("MESSAGE_ID"), "1e45a69523d3460680e2721d3072408f".as_bytes(), ), LogField::new(gstr!("PRIORITY"), "4".as_bytes()), LogField::new(gstr!("MESSAGE"), "from array".as_bytes()), LogField::new_user_data(gstr!("SOMEDATA"), 12345), ], ); let dict = glib::VariantDict::new(None); dict.insert_value( "MESSAGE_ID", &"9e093d0fac2f4d50838a649796ab154b".to_variant(), ); dict.insert_value("RELEASE", &"true".to_variant()); dict.insert_value("MY_BYTES", &"123".as_bytes().to_variant()); dict.insert_value("MESSAGE", &"from variant".to_variant()); glib::log_variant(Some("test"), LogLevel::Debug, &dict.end()); let log = std::mem::take(&mut *log.lock().unwrap()); let log = log .iter() .map(|(l, v)| { ( *l, v.iter() .map(|(k, v)| (k.as_str(), v.as_str())) .collect::>(), ) }) .collect::>(); let path = if cfg!(windows) { "glib\\tests\\structured_log.rs" } else { "glib/tests/structured_log.rs" }; assert_eq!( log[0], ( LogLevel::Message, vec![ ("PRIORITY", "5" as &str), ("CODE_FILE", path as &str), ("CODE_LINE", "31" as &str), ("CODE_FUNC", "structured_log::structured_log" as &str), ("MY_META", "abc"), ("MESSAGE", "normal with meta"), ("MY_META2", "def"), ("GLIB_DOMAIN", "test"), ] ), ); assert_eq!( log[1], ( LogLevel::Message, vec![ ("PRIORITY", "5" as &str), ("CODE_FILE", path as &str), ("CODE_LINE", "41" as &str), ("CODE_FUNC", "structured_log::structured_log" as &str), ("MY_META", "abc"), ("MESSAGE", "formatted with meta: 123 456"), ("MY_META2", "defghi"), ("EMPTY", ""), ("MY_META3", "bstring"), ] ) ); assert_eq!( log[2], ( LogLevel::Warning, vec![ ("MESSAGE_ID", "1e45a69523d3460680e2721d3072408f" as &str), ("PRIORITY", "4"), ("MESSAGE", "from array"), ("SOMEDATA", "USERDATA: 12345"), ] ) ); assert_eq!( log[3], ( LogLevel::Debug, vec![ ("PRIORITY", "7" as &str), ("GLIB_DOMAIN", "test"), ("MESSAGE_ID", "9e093d0fac2f4d50838a649796ab154b"), ("MY_BYTES", "123"), ("RELEASE", "true"), ("MESSAGE", "from variant"), ] ) ); } glib-0.20.9/tests/subclass_compiletest/01-auto-send-sync.rs000064400000000000000000000011471046102023000216620ustar 00000000000000mod imp { use glib::subclass::prelude::*; #[derive(Default)] pub struct TestObject { s: String, } #[glib::object_subclass] impl ObjectSubclass for TestObject { const NAME: &'static str = "TestObject"; type Type = super::TestObject; } impl ObjectImpl for TestObject {} } glib::wrapper! { pub struct TestObject(ObjectSubclass); } impl Default for TestObject { fn default() -> Self { glib::Object::new() } } fn main() { fn check(_obj: &T) {} let obj = TestObject::default(); check(&obj); } glib-0.20.9/tests/subclass_compiletest/02-no-auto-send-sync.rs000064400000000000000000000012051046102023000222700ustar 00000000000000mod imp { use glib::subclass::prelude::*; use std::cell::RefCell; #[derive(Default)] pub struct TestObject { s: RefCell, } #[glib::object_subclass] impl ObjectSubclass for TestObject { const NAME: &'static str = "TestObject"; type Type = super::TestObject; } impl ObjectImpl for TestObject {} } glib::wrapper! { pub struct TestObject(ObjectSubclass); } impl Default for TestObject { fn default() -> Self { glib::Object::new() } } fn main() { fn check(_obj: &T) {} let obj = TestObject::default(); check(&obj); } glib-0.20.9/tests/subclass_compiletest/02-no-auto-send-sync.stderr000064400000000000000000000023671046102023000231610ustar 00000000000000error[E0277]: `RefCell` cannot be shared between threads safely --> tests/subclass_compiletest/02-no-auto-send-sync.rs:33:11 | 33 | check(&obj); | ----- ^^^^ `RefCell` cannot be shared between threads safely | | | required by a bound introduced by this call | = help: within `imp::TestObject`, the trait `Sync` is not implemented for `RefCell` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: required because it appears within the type `imp::TestObject` --> tests/subclass_compiletest/02-no-auto-send-sync.rs:6:16 | 6 | pub struct TestObject { | ^^^^^^^^^^ = note: required for `TypedObjectRef` to implement `Send` note: required because it appears within the type `TestObject` --> tests/subclass_compiletest/02-no-auto-send-sync.rs:20:16 | 20 | pub struct TestObject(ObjectSubclass); | ^^^^^^^^^^ note: required by a bound in `main::check` --> tests/subclass_compiletest/02-no-auto-send-sync.rs:30:17 | 30 | fn check(_obj: &T) {} | ^^^^ required by this bound in `check` glib-0.20.9/tests/subclass_compiletest/03-object-no-auto-send-sync.rs000064400000000000000000000001751046102023000235420ustar 00000000000000fn main() { fn check(_obj: &T) {} let obj = glib::Object::new::(); check(&obj); } glib-0.20.9/tests/subclass_compiletest/03-object-no-auto-send-sync.stderr000064400000000000000000000034231046102023000244200ustar 00000000000000error[E0277]: `*mut c_void` cannot be sent between threads safely --> tests/subclass_compiletest/03-object-no-auto-send-sync.rs:5:11 | 5 | check(&obj); | ----- ^^^^ `*mut c_void` cannot be sent between threads safely | | | required by a bound introduced by this call | = help: the trait `Send` is not implemented for `*mut c_void` = note: required for `TypedObjectRef<*mut c_void, ()>` to implement `Send` note: required because it appears within the type `Object` --> src/object.rs | | pub Object, *mut std::os::raw::c_void, (), gobject_ffi::GObject, @ffi_class gobject_ffi::GObjectClass, @type_ gobject_ffi::g_object_g... | ^^^^^^ note: required by a bound in `main::check` --> tests/subclass_compiletest/03-object-no-auto-send-sync.rs:2:17 | 2 | fn check(_obj: &T) {} | ^^^^ required by this bound in `check` error[E0277]: `*mut c_void` cannot be shared between threads safely --> tests/subclass_compiletest/03-object-no-auto-send-sync.rs:5:11 | 5 | check(&obj); | ----- ^^^^ `*mut c_void` cannot be shared between threads safely | | | required by a bound introduced by this call | = help: the trait `Sync` is not implemented for `*mut c_void` = note: required for `TypedObjectRef<*mut c_void, ()>` to implement `Send` note: required because it appears within the type `Object` --> src/object.rs | | pub Object, *mut std::os::raw::c_void, (), gobject_ffi::GObject, @ffi_class gobject_ffi::GObjectClass, @type_ gobject_ffi::g_object_g... | ^^^^^^ note: required by a bound in `main::check` --> tests/subclass_compiletest/03-object-no-auto-send-sync.rs:2:17 | 2 | fn check(_obj: &T) {} | ^^^^ required by this bound in `check` glib-0.20.9/tests/subclass_compiletest/04-auto-send-sync-with-send-sync-parent.rs000064400000000000000000000027211046102023000260250ustar 00000000000000mod imp_parent { use glib::subclass::prelude::*; #[derive(Default)] pub struct TestParent { s: String, } #[glib::object_subclass] impl ObjectSubclass for TestParent { const NAME: &'static str = "TestParent"; type Type = super::TestParent; } impl ObjectImpl for TestParent {} } glib::wrapper! { pub struct TestParent(ObjectSubclass); } pub trait TestParentImpl: glib::subclass::prelude::ObjectImpl + Send + Sync {} unsafe impl glib::subclass::prelude::IsSubclassable for TestParent {} impl Default for TestParent { fn default() -> Self { glib::Object::new() } } mod imp_object { use glib::subclass::prelude::*; #[derive(Default)] pub struct TestObject { s: String, } #[glib::object_subclass] impl ObjectSubclass for TestObject { const NAME: &'static str = "TestObject"; type Type = super::TestObject; type ParentType = super::TestParent; } impl ObjectImpl for TestObject {} impl super::TestParentImpl for TestObject {} } glib::wrapper! { pub struct TestObject(ObjectSubclass) @extends TestParent; } impl Default for TestObject { fn default() -> Self { glib::Object::new() } } fn main() { fn check(_obj: &T) {} let obj = TestParent::default(); check(&obj); let obj = TestObject::default(); check(&obj); } glib-0.20.9/tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.rs000064400000000000000000000026611046102023000272330ustar 00000000000000mod imp_parent { use glib::subclass::prelude::*; use std::cell::RefCell; #[derive(Default)] pub struct TestParent { s: RefCell, } #[glib::object_subclass] impl ObjectSubclass for TestParent { const NAME: &'static str = "TestParent"; type Type = super::TestParent; } impl ObjectImpl for TestParent {} } glib::wrapper! { pub struct TestParent(ObjectSubclass); } pub trait TestParentImpl: glib::subclass::prelude::ObjectImpl {} unsafe impl glib::subclass::prelude::IsSubclassable for TestParent {} impl Default for TestParent { fn default() -> Self { glib::Object::new() } } mod imp_object { use glib::subclass::prelude::*; #[derive(Default)] pub struct TestObject { s: String, } #[glib::object_subclass] impl ObjectSubclass for TestObject { const NAME: &'static str = "TestObject"; type Type = super::TestObject; type ParentType = super::TestParent; } impl ObjectImpl for TestObject {} impl super::TestParentImpl for TestObject {} } glib::wrapper! { pub struct TestObject(ObjectSubclass) @extends TestParent; } impl Default for TestObject { fn default() -> Self { glib::Object::new() } } fn main() { fn check(_obj: &T) {} let obj = TestObject::default(); check(&obj); } glib-0.20.9/tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.stderr000064400000000000000000000033731046102023000301130ustar 00000000000000error[E0277]: `RefCell` cannot be shared between threads safely --> tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.rs:66:11 | 66 | check(&obj); | ----- ^^^^ `RefCell` cannot be shared between threads safely | | | required by a bound introduced by this call | = help: within `imp_parent::TestParent`, the trait `Sync` is not implemented for `RefCell` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead note: required because it appears within the type `imp_parent::TestParent` --> tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.rs:6:16 | 6 | pub struct TestParent { | ^^^^^^^^^^ = note: required for `TypedObjectRef` to implement `Send` note: required because it appears within the type `TestParent` --> tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.rs:20:16 | 20 | pub struct TestParent(ObjectSubclass); | ^^^^^^^^^^ = note: required for `TypedObjectRef` to implement `Send` note: required because it appears within the type `TestObject` --> tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.rs:53:16 | 53 | pub struct TestObject(ObjectSubclass) @extends TestParent; | ^^^^^^^^^^ note: required by a bound in `main::check` --> tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.rs:63:17 | 63 | fn check(_obj: &T) {} | ^^^^ required by this bound in `check` glib-0.20.9/tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.rs000064400000000000000000000023021046102023000277660ustar 00000000000000glib::wrapper! { #[doc(alias = "GInitiallyUnowned")] pub struct InitiallyUnowned(Object); match fn { type_ => || glib::gobject_ffi::g_initially_unowned_get_type(), } } pub trait InitiallyUnownedImpl: glib::subclass::prelude::ObjectImpl {} unsafe impl glib::subclass::prelude::IsSubclassable for InitiallyUnowned { } mod imp_object { use glib::subclass::prelude::*; #[derive(Default)] pub struct TestObject { s: String, } #[glib::object_subclass] impl ObjectSubclass for TestObject { const NAME: &'static str = "TestObject"; type Type = super::TestObject; type ParentType = super::InitiallyUnowned; } impl ObjectImpl for TestObject {} impl super::InitiallyUnownedImpl for TestObject {} } glib::wrapper! { pub struct TestObject(ObjectSubclass) @extends InitiallyUnowned; } impl Default for TestObject { fn default() -> Self { glib::Object::new() } } fn main() { fn check(_obj: &T) {} let obj = TestObject::default(); check(&obj); } glib-0.20.9/tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.stderr000064400000000000000000000055071046102023000306570ustar 00000000000000error[E0277]: `*mut c_void` cannot be sent between threads safely --> tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.rs:50:11 | 50 | check(&obj); | ----- ^^^^ `*mut c_void` cannot be sent between threads safely | | | required by a bound introduced by this call | = help: the trait `Send` is not implemented for `*mut c_void` = note: required for `TypedObjectRef<*mut c_void, ()>` to implement `Send` note: required because it appears within the type `InitiallyUnowned` --> tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.rs:3:16 | 3 | pub struct InitiallyUnowned(Object); | ^^^^^^^^^^^^^^^^ = note: required for `TypedObjectRef` to implement `Send` note: required because it appears within the type `TestObject` --> tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.rs:37:16 | 37 | pub struct TestObject(ObjectSubclass) @extends InitiallyUnowned; | ^^^^^^^^^^ note: required by a bound in `main::check` --> tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.rs:47:17 | 47 | fn check(_obj: &T) {} | ^^^^ required by this bound in `check` error[E0277]: `*mut c_void` cannot be shared between threads safely --> tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.rs:50:11 | 50 | check(&obj); | ----- ^^^^ `*mut c_void` cannot be shared between threads safely | | | required by a bound introduced by this call | = help: the trait `Sync` is not implemented for `*mut c_void` = note: required for `TypedObjectRef<*mut c_void, ()>` to implement `Send` note: required because it appears within the type `InitiallyUnowned` --> tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.rs:3:16 | 3 | pub struct InitiallyUnowned(Object); | ^^^^^^^^^^^^^^^^ = note: required for `TypedObjectRef` to implement `Send` note: required because it appears within the type `TestObject` --> tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.rs:37:16 | 37 | pub struct TestObject(ObjectSubclass) @extends InitiallyUnowned; | ^^^^^^^^^^ note: required by a bound in `main::check` --> tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.rs:47:17 | 47 | fn check(_obj: &T) {} | ^^^^ required by this bound in `check` glib-0.20.9/tests/subclass_compiletest.rs000064400000000000000000000011161046102023000165670ustar 00000000000000#[test] pub fn test() { let t = trybuild2::TestCases::new(); t.pass("tests/subclass_compiletest/01-auto-send-sync.rs"); t.compile_fail("tests/subclass_compiletest/02-no-auto-send-sync.rs"); t.compile_fail("tests/subclass_compiletest/03-object-no-auto-send-sync.rs"); t.pass("tests/subclass_compiletest/04-auto-send-sync-with-send-sync-parent.rs"); t.compile_fail("tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.rs"); t.compile_fail( "tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.rs", ); } glib-0.20.9/tests/unicollate.rs000064400000000000000000000043421046102023000145030ustar 00000000000000use glib::{CollationKey, FilenameCollationKey}; fn init() { use std::sync::Once; static ONCE: Once = Once::new(); // Make sure that all tests below are running with the system // locale and not the "C" locale. ONCE.call_once(|| unsafe { libc::setlocale(libc::LC_ALL, b"\0".as_ptr() as *const _); }); } #[test] fn collate() { init(); let mut unsorted = vec![ String::from("bcd"), String::from("cde"), String::from("abc"), ]; let sorted = vec![ String::from("abc"), String::from("bcd"), String::from("cde"), ]; unsorted.sort_by(|s1, s2| CollationKey::from(&s1).cmp(&CollationKey::from(&s2))); assert_eq!(unsorted, sorted); } #[test] fn collate_non_ascii() { init(); let mut unsorted = vec![ String::from("猫の手も借りたい"), String::from("日本語は難しい"), String::from("ありがとう"), ]; let sorted = vec![ String::from("ありがとう"), String::from("日本語は難しい"), String::from("猫の手も借りたい"), ]; unsorted.sort_by(|s1, s2| CollationKey::from(&s1).cmp(&CollationKey::from(&s2))); assert_eq!(unsorted, sorted); } #[test] fn collate_filenames() { init(); let mut unsorted = vec![ String::from("bcd.a"), String::from("cde.b"), String::from("abc.c"), ]; let sorted = vec![ String::from("abc.c"), String::from("bcd.a"), String::from("cde.b"), ]; unsorted .sort_by(|s1, s2| FilenameCollationKey::from(&s1).cmp(&FilenameCollationKey::from(&s2))); assert_eq!(unsorted, sorted); } #[test] fn collate_filenames_non_ascii() { init(); let mut unsorted = vec![ String::from("猫の手も借りたい.foo"), String::from("日本語は難しい.bar"), String::from("ありがとう.baz"), ]; let sorted = vec![ String::from("ありがとう.baz"), String::from("日本語は難しい.bar"), String::from("猫の手も借りたい.foo"), ]; unsorted .sort_by(|s1, s2| FilenameCollationKey::from(&s1).cmp(&FilenameCollationKey::from(&s2))); assert_eq!(unsorted, sorted); } glib-0.20.9/tests/value.rs000064400000000000000000000033111046102023000134530ustar 00000000000000use std::ops::Deref; use glib::{prelude::*, BoxedValue, Value}; // FIXME all .get::() should be replaced with .get(); the compiler is totally able to infer the type itself. // But somehow without some tests are failing on Windows because the type inference doesn't work or something. // Test that `ToValue` (and conversely, `FromValue`) uphold the promised invariants #[test] pub fn to_value_invariants() { // Inverse assert_eq!(0i32, 0i32.to_value().get::().unwrap()); assert_eq!(0i32, 0i32.to_value().get::().unwrap()); // Idempotence assert_eq!( &0i32.to_value().type_(), &0i32.to_value().to_value().type_() ); assert_eq!(0i32, 0i32.to_value().to_value().get::().unwrap()); assert_eq!( 0i32, 0i32.to_value() .get::() .unwrap() .get::() .unwrap() ); assert_eq!( 0i32, 0i32.to_value() .get::() .unwrap() .get::() .unwrap() ); } // Test that `ToValue` and `FromValue` handle nexted boxed values correctly (as per the documentation) #[test] pub fn to_value_boxed() { let x = 0i32.to_value(); let boxed = BoxedValue(x); assert_eq!( 0i32, boxed .to_value() .to_value() .get::() .unwrap() .deref() .get::() .unwrap() ); assert_eq!( 0i32, boxed .to_value() .get::() .unwrap() .get::() .unwrap() .deref() .get::() .unwrap() ); }