From 196b29bd2f33d1d7fb77019e8c60181feff994c0 Mon Sep 17 00:00:00 2001 From: Kurt Landman Date: Sat, 18 Jul 2026 15:28:16 +0800 Subject: [PATCH 1/2] Backport glib VariantStrIter security fix --- .github/workflows/ci.yml | 1 + .../release/test_rust_dependency_security.py | 39 + walletapp/src-tauri/Cargo.lock | 2 - walletapp/src-tauri/Cargo.toml | 3 + .../glib-0.18.5-btc09/.cargo_vcs_info.json | 6 + .../vendor/glib-0.18.5-btc09/BTC09-PATCH.md | 20 + walletapp/vendor/glib-0.18.5-btc09/COPYRIGHT | 14 + walletapp/vendor/glib-0.18.5-btc09/Cargo.toml | 185 + .../vendor/glib-0.18.5-btc09/Cargo.toml.orig | 74 + walletapp/vendor/glib-0.18.5-btc09/Gir.toml | 816 +++ .../vendor/glib-0.18.5-btc09/Gir_GObject.toml | 149 + walletapp/vendor/glib-0.18.5-btc09/LICENSE | 18 + walletapp/vendor/glib-0.18.5-btc09/README.md | 101 + .../glib-0.18.5-btc09/benches/gstring.rs | 46 + .../glib-0.18.5-btc09/src/auto/alias.rs | 13 + .../glib-0.18.5-btc09/src/auto/checksum.rs | 46 + .../glib-0.18.5-btc09/src/auto/constants.rs | 105 + .../glib-0.18.5-btc09/src/auto/date_time.rs | 502 ++ .../glib-0.18.5-btc09/src/auto/enums.rs | 2661 ++++++++++ .../glib-0.18.5-btc09/src/auto/flags.rs | 636 +++ .../glib-0.18.5-btc09/src/auto/functions.rs | 863 ++++ .../glib-0.18.5-btc09/src/auto/key_file.rs | 487 ++ .../src/auto/main_context.rs | 142 + .../glib-0.18.5-btc09/src/auto/main_loop.rs | 56 + .../src/auto/markup_parse_context.rs | 99 + .../vendor/glib-0.18.5-btc09/src/auto/mod.rs | 123 + .../glib-0.18.5-btc09/src/auto/source.rs | 128 + .../glib-0.18.5-btc09/src/auto/time_zone.rs | 91 + .../vendor/glib-0.18.5-btc09/src/auto/uri.rs | 535 ++ .../glib-0.18.5-btc09/src/auto/versions.txt | 2 + .../vendor/glib-0.18.5-btc09/src/boxed.rs | 606 +++ .../glib-0.18.5-btc09/src/boxed_any_object.rs | 191 + .../glib-0.18.5-btc09/src/boxed_inline.rs | 643 +++ .../glib-0.18.5-btc09/src/bridged_logging.rs | 385 ++ .../glib-0.18.5-btc09/src/byte_array.rs | 160 + .../vendor/glib-0.18.5-btc09/src/bytes.rs | 277 + .../vendor/glib-0.18.5-btc09/src/char.rs | 220 + .../vendor/glib-0.18.5-btc09/src/checksum.rs | 74 + .../vendor/glib-0.18.5-btc09/src/clone.rs | 101 + .../vendor/glib-0.18.5-btc09/src/closure.rs | 447 ++ .../glib-0.18.5-btc09/src/collections/list.rs | 894 ++++ .../glib-0.18.5-btc09/src/collections/mod.rs | 16 + .../src/collections/ptr_slice.rs | 1371 +++++ .../src/collections/slice.rs | 991 ++++ .../src/collections/slist.rs | 887 ++++ .../glib-0.18.5-btc09/src/collections/strv.rs | 1544 ++++++ .../glib-0.18.5-btc09/src/control_flow.rs | 103 + .../vendor/glib-0.18.5-btc09/src/convert.rs | 448 ++ .../vendor/glib-0.18.5-btc09/src/date.rs | 443 ++ .../vendor/glib-0.18.5-btc09/src/date_time.rs | 15 + .../vendor/glib-0.18.5-btc09/src/enums.rs | 966 ++++ .../vendor/glib-0.18.5-btc09/src/error.rs | 325 ++ .../vendor/glib-0.18.5-btc09/src/exit_code.rs | 33 + .../src/future_with_timeout.rs | 103 + .../src/gobject/auto/binding.rs | 59 + .../src/gobject/auto/binding_group.rs | 94 + .../src/gobject/auto/flags.rs | 152 + .../glib-0.18.5-btc09/src/gobject/auto/mod.rs | 24 + .../src/gobject/auto/signal_group.rs | 73 + .../glib-0.18.5-btc09/src/gobject/binding.rs | 307 ++ .../src/gobject/binding_group.rs | 507 ++ .../glib-0.18.5-btc09/src/gobject/flags.rs | 59 + .../glib-0.18.5-btc09/src/gobject/mod.rs | 22 + .../src/gobject/signal_group.rs | 248 + .../vendor/glib-0.18.5-btc09/src/gstring.rs | 2547 +++++++++ .../glib-0.18.5-btc09/src/gstring_builder.rs | 367 ++ .../vendor/glib-0.18.5-btc09/src/key_file.rs | 282 + walletapp/vendor/glib-0.18.5-btc09/src/lib.rs | 231 + walletapp/vendor/glib-0.18.5-btc09/src/log.rs | 1069 ++++ .../glib-0.18.5-btc09/src/main_context.rs | 279 + .../src/main_context_channel.rs | 896 ++++ .../src/main_context_futures.rs | 810 +++ .../glib-0.18.5-btc09/src/manual_functions.rs | 288 ++ .../vendor/glib-0.18.5-btc09/src/object.rs | 4542 +++++++++++++++++ .../glib-0.18.5-btc09/src/param_spec.rs | 2316 +++++++++ .../vendor/glib-0.18.5-btc09/src/prelude.rs | 9 + .../vendor/glib-0.18.5-btc09/src/property.rs | 303 ++ .../vendor/glib-0.18.5-btc09/src/quark.rs | 103 + .../vendor/glib-0.18.5-btc09/src/shared.rs | 588 +++ .../vendor/glib-0.18.5-btc09/src/signal.rs | 226 + .../vendor/glib-0.18.5-btc09/src/source.rs | 1197 +++++ .../glib-0.18.5-btc09/src/source_futures.rs | 482 ++ .../glib-0.18.5-btc09/src/subclass/basic.rs | 72 + .../glib-0.18.5-btc09/src/subclass/boxed.rs | 109 + .../src/subclass/interface.rs | 217 + .../glib-0.18.5-btc09/src/subclass/mod.rs | 267 + .../glib-0.18.5-btc09/src/subclass/object.rs | 717 +++ .../src/subclass/object_impl_ref.rs | 163 + .../glib-0.18.5-btc09/src/subclass/shared.rs | 295 ++ .../glib-0.18.5-btc09/src/subclass/signal.rs | 715 +++ .../glib-0.18.5-btc09/src/subclass/types.rs | 1127 ++++ .../glib-0.18.5-btc09/src/thread_guard.rs | 114 + .../glib-0.18.5-btc09/src/thread_pool.rs | 254 + .../vendor/glib-0.18.5-btc09/src/time_span.rs | 99 + .../vendor/glib-0.18.5-btc09/src/time_zone.rs | 15 + .../vendor/glib-0.18.5-btc09/src/translate.rs | 2969 +++++++++++ .../vendor/glib-0.18.5-btc09/src/types.rs | 678 +++ .../vendor/glib-0.18.5-btc09/src/unichar.rs | 243 + .../glib-0.18.5-btc09/src/unicollate.rs | 88 + .../vendor/glib-0.18.5-btc09/src/utils.rs | 278 + .../vendor/glib-0.18.5-btc09/src/value.rs | 1665 ++++++ .../glib-0.18.5-btc09/src/value_array.rs | 251 + .../vendor/glib-0.18.5-btc09/src/variant.rs | 2520 +++++++++ .../glib-0.18.5-btc09/src/variant_dict.rs | 293 ++ .../glib-0.18.5-btc09/src/variant_iter.rs | 371 ++ .../glib-0.18.5-btc09/src/variant_type.rs | 1083 ++++ .../vendor/glib-0.18.5-btc09/src/win32.rs | 95 + .../vendor/glib-0.18.5-btc09/src/wrapper.rs | 445 ++ .../glib-0.18.5-btc09/tests/check_gir.rs | 8 + .../vendor/glib-0.18.5-btc09/tests/clone.rs | 635 +++ .../vendor/glib-0.18.5-btc09/tests/derive.rs | 33 + .../vendor/glib-0.18.5-btc09/tests/log.rs | 106 + .../vendor/glib-0.18.5-btc09/tests/print.rs | 49 + .../glib-0.18.5-btc09/tests/structured_log.rs | 152 + .../tests/subclass_compiletest.rs | 13 + .../subclass_compiletest/01-auto-send-sync.rs | 33 + .../02-no-auto-send-sync.rs | 34 + .../02-no-auto-send-sync.stderr | 26 + .../03-object-no-auto-send-sync.rs | 6 + .../03-object-no-auto-send-sync.stderr | 41 + ...04-auto-send-sync-with-send-sync-parent.rs | 69 + ...uto-send-sync-with-non-send-sync-parent.rs | 67 + ...send-sync-with-non-send-sync-parent.stderr | 32 + ...send-sync-with-non-send-sync-ffi-parent.rs | 51 + ...-sync-with-non-send-sync-ffi-parent.stderr | 53 + .../vendor/glib-0.18.5-btc09/tests/value.rs | 67 + 126 files changed, 53902 insertions(+), 2 deletions(-) create mode 100644 tools/release/test_rust_dependency_security.py create mode 100644 walletapp/vendor/glib-0.18.5-btc09/.cargo_vcs_info.json create mode 100644 walletapp/vendor/glib-0.18.5-btc09/BTC09-PATCH.md create mode 100644 walletapp/vendor/glib-0.18.5-btc09/COPYRIGHT create mode 100644 walletapp/vendor/glib-0.18.5-btc09/Cargo.toml create mode 100644 walletapp/vendor/glib-0.18.5-btc09/Cargo.toml.orig create mode 100644 walletapp/vendor/glib-0.18.5-btc09/Gir.toml create mode 100644 walletapp/vendor/glib-0.18.5-btc09/Gir_GObject.toml create mode 100644 walletapp/vendor/glib-0.18.5-btc09/LICENSE create mode 100644 walletapp/vendor/glib-0.18.5-btc09/README.md create mode 100644 walletapp/vendor/glib-0.18.5-btc09/benches/gstring.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/auto/alias.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/auto/checksum.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/auto/constants.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/auto/date_time.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/auto/enums.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/auto/flags.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/auto/functions.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/auto/key_file.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/auto/main_context.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/auto/main_loop.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/auto/markup_parse_context.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/auto/mod.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/auto/source.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/auto/time_zone.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/auto/uri.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/auto/versions.txt create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/boxed.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/boxed_any_object.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/boxed_inline.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/bridged_logging.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/byte_array.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/bytes.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/char.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/checksum.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/clone.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/closure.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/collections/list.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/collections/mod.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/collections/ptr_slice.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/collections/slice.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/collections/slist.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/collections/strv.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/control_flow.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/convert.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/date.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/date_time.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/enums.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/error.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/exit_code.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/future_with_timeout.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/binding.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/binding_group.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/flags.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/mod.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/signal_group.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/gobject/binding.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/gobject/binding_group.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/gobject/flags.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/gobject/mod.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/gobject/signal_group.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/gstring.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/gstring_builder.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/key_file.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/lib.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/log.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/main_context.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/main_context_channel.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/main_context_futures.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/manual_functions.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/object.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/param_spec.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/prelude.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/property.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/quark.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/shared.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/signal.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/source.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/source_futures.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/subclass/basic.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/subclass/boxed.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/subclass/interface.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/subclass/mod.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/subclass/object.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/subclass/object_impl_ref.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/subclass/shared.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/subclass/signal.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/subclass/types.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/thread_guard.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/thread_pool.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/time_span.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/time_zone.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/translate.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/types.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/unichar.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/unicollate.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/utils.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/value.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/value_array.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/variant.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/variant_dict.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/variant_iter.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/variant_type.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/win32.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/src/wrapper.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/tests/check_gir.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/tests/clone.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/tests/derive.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/tests/log.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/tests/print.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/tests/structured_log.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/01-auto-send-sync.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/02-no-auto-send-sync.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/02-no-auto-send-sync.stderr create mode 100644 walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/03-object-no-auto-send-sync.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/03-object-no-auto-send-sync.stderr create mode 100644 walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/04-auto-send-sync-with-send-sync-parent.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.stderr create mode 100644 walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.rs create mode 100644 walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.stderr create mode 100644 walletapp/vendor/glib-0.18.5-btc09/tests/value.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1259650..f8cf15a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,6 +71,7 @@ jobs: tools.release.test_direct_distribution \ tools.release.test_package_macos \ tools.release.test_package_windows_store \ + tools.release.test_rust_dependency_security \ tools.site.test_index_contract \ tools.site.test_store_readiness_contract \ tools.deploy.test_nine_inbox_contract \ diff --git a/tools/release/test_rust_dependency_security.py b/tools/release/test_rust_dependency_security.py new file mode 100644 index 0000000..43d1cf0 --- /dev/null +++ b/tools/release/test_rust_dependency_security.py @@ -0,0 +1,39 @@ +import pathlib +import tomllib +import unittest + + +ROOT = pathlib.Path(__file__).resolve().parents[2] +TAURI_MANIFEST = ROOT / "walletapp" / "src-tauri" / "Cargo.toml" +TAURI_LOCK = ROOT / "walletapp" / "src-tauri" / "Cargo.lock" +VENDORED_GLIB = ROOT / "walletapp" / "vendor" / "glib-0.18.5-btc09" + + +class RustDependencySecurityTests(unittest.TestCase): + def test_patched_glib_source_is_locked(self): + manifest = tomllib.loads(TAURI_MANIFEST.read_text(encoding="utf-8")) + patch = manifest["patch"]["crates-io"]["glib"] + self.assertEqual(patch, {"path": "../vendor/glib-0.18.5-btc09"}) + + lock = tomllib.loads(TAURI_LOCK.read_text(encoding="utf-8")) + packages = [package for package in lock["package"] if package["name"] == "glib"] + self.assertEqual(len(packages), 1) + self.assertEqual(packages[0]["version"], "0.18.5") + self.assertNotIn("source", packages[0]) + self.assertNotIn("checksum", packages[0]) + + def test_variant_string_iterator_uses_mutable_out_pointer(self): + source = (VENDORED_GLIB / "src" / "variant_iter.rs").read_text(encoding="utf-8") + self.assertIn("let mut p: *mut libc::c_char = std::ptr::null_mut();", source) + self.assertIn("&mut p,", source) + self.assertNotIn("\n &p,", source) + + def test_backport_provenance_is_recorded(self): + provenance = (VENDORED_GLIB / "BTC09-PATCH.md").read_text(encoding="utf-8") + self.assertIn("GHSA-wrw7-89jp-8q8g", provenance) + self.assertIn("05dff0ee696f9bcd8617cd48c4b812d046d440cb", provenance) + self.assertIn("233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5", provenance) + + +if __name__ == "__main__": + unittest.main() diff --git a/walletapp/src-tauri/Cargo.lock b/walletapp/src-tauri/Cargo.lock index e43237f..0d4d055 100644 --- a/walletapp/src-tauri/Cargo.lock +++ b/walletapp/src-tauri/Cargo.lock @@ -1069,8 +1069,6 @@ dependencies = [ [[package]] name = "glib" version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" dependencies = [ "bitflags 2.13.1", "futures-channel", diff --git a/walletapp/src-tauri/Cargo.toml b/walletapp/src-tauri/Cargo.toml index 691cf87..8570a31 100644 --- a/walletapp/src-tauri/Cargo.toml +++ b/walletapp/src-tauri/Cargo.toml @@ -27,3 +27,6 @@ url = "2.5.8" [target.'cfg(any(target_os = "android", target_os = "ios"))'.dependencies] tauri-plugin-wallet-core = { path = "../plugins/tauri-plugin-wallet-core" } tauri-plugin-barcode-scanner = "=2.4.5" + +[patch.crates-io] +glib = { path = "../vendor/glib-0.18.5-btc09" } diff --git a/walletapp/vendor/glib-0.18.5-btc09/.cargo_vcs_info.json b/walletapp/vendor/glib-0.18.5-btc09/.cargo_vcs_info.json new file mode 100644 index 0000000..1af96a8 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "42b9caf98e03ded086362d9653ca58fe94dc8658" + }, + "path_in_vcs": "glib" +} \ No newline at end of file diff --git a/walletapp/vendor/glib-0.18.5-btc09/BTC09-PATCH.md b/walletapp/vendor/glib-0.18.5-btc09/BTC09-PATCH.md new file mode 100644 index 0000000..e591c85 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/BTC09-PATCH.md @@ -0,0 +1,20 @@ +# BTC09 glib security backport + +This directory contains the official `glib` 0.18.5 crate with the upstream +`VariantStrIter::impl_get` security fix backported. It is used only by the +Linux Tauri/GTK wallet dependency graph. + +- Upstream crate: https://crates.io/crates/glib/0.18.5 +- Archive SHA-256: `233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5` +- Advisory: https://github.com/advisories/GHSA-wrw7-89jp-8q8g +- Upstream fix: https://github.com/gtk-rs/gtk-rs-core/pull/1343 +- Upstream merge commit: `05dff0ee696f9bcd8617cd48c4b812d046d440cb` +- License: MIT, preserved in `LICENSE` + +The backport changes the C out-argument from `&p` to `&mut p` and makes the +pointer binding mutable. No other upstream source is modified. + +Tauri 2.11 still depends on the GTK3 crate line that requires `glib` 0.18, so +the patched upstream `glib` 0.20 release cannot replace it through a normal +semver update. Remove this override when the supported Tauri Linux dependency +graph moves to `glib` 0.20 or newer. diff --git a/walletapp/vendor/glib-0.18.5-btc09/COPYRIGHT b/walletapp/vendor/glib-0.18.5-btc09/COPYRIGHT new file mode 100644 index 0000000..aabc43f --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/COPYRIGHT @@ -0,0 +1,14 @@ +The 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. diff --git a/walletapp/vendor/glib-0.18.5-btc09/Cargo.toml b/walletapp/vendor/glib-0.18.5-btc09/Cargo.toml new file mode 100644 index 0000000..132e07d --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/Cargo.toml @@ -0,0 +1,185 @@ +# 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.18.5" +authors = ["The gtk-rs Project Developers"] +exclude = ["gir-files/*"] +description = "Rust bindings for the GLib library" +homepage = "https://gtk-rs.org/" +documentation = "https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/" +readme = "README.md" +keywords = [ + "glib", + "gtk-rs", + "gnome", + "GUI", +] +license = "MIT" +repository = "https://github.com/gtk-rs/gtk-rs-core" + +[package.metadata.docs.rs] +all-features = true +rustc-args = [ + "--cfg", + "docsrs", +] +rustdoc-args = [ + "--cfg", + "docsrs", + "--generate-link-to-definition", +] + +[lib] +name = "glib" + +[[test]] +name = "subclass_compiletest" +required-features = ["compiletests"] + +[[bench]] +name = "gstring" +harness = false + +[dependencies.bitflags] +version = "2.3" + +[dependencies.ffi] +version = "0.18" +package = "glib-sys" + +[dependencies.futures-channel] +version = "0.3" + +[dependencies.futures-core] +version = "0.3" +default-features = false + +[dependencies.futures-executor] +version = "0.3" + +[dependencies.futures-task] +version = "0.3" +default-features = false + +[dependencies.futures-util] +version = "0.3" + +[dependencies.gio_ffi] +version = "0.18" +optional = true +package = "gio-sys" + +[dependencies.glib-macros] +version = "0.18" + +[dependencies.gobject_ffi] +version = "0.18" +package = "gobject-sys" + +[dependencies.libc] +version = "0.2" + +[dependencies.memchr] +version = "2.5.0" + +[dependencies.once_cell] +version = "1.0" + +[dependencies.rs-log] +version = "0.4" +optional = true +package = "log" + +[dependencies.smallvec] +version = "1.0" +features = [ + "union", + "const_generics", + "const_new", +] + +[dependencies.thiserror] +version = "1" + +[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_ffi"] +log = ["rs-log"] +log_macros = ["log"] +v2_58 = [ + "ffi/v2_58", + "gobject_ffi/v2_58", +] +v2_60 = [ + "v2_58", + "ffi/v2_60", +] +v2_62 = [ + "v2_60", + "ffi/v2_62", + "gobject_ffi/v2_62", +] +v2_64 = [ + "v2_62", + "ffi/v2_64", +] +v2_66 = [ + "v2_64", + "ffi/v2_66", + "gobject_ffi/v2_66", +] +v2_68 = [ + "v2_66", + "ffi/v2_68", + "gobject_ffi/v2_68", +] +v2_70 = [ + "v2_68", + "ffi/v2_70", + "gobject_ffi/v2_70", +] +v2_72 = [ + "v2_70", + "ffi/v2_72", + "gobject_ffi/v2_72", +] +v2_74 = [ + "v2_72", + "ffi/v2_74", + "gobject_ffi/v2_74", +] +v2_76 = [ + "v2_74", + "ffi/v2_76", + "gobject_ffi/v2_76", +] +v2_78 = [ + "v2_76", + "ffi/v2_78", + "gobject_ffi/v2_78", +] diff --git a/walletapp/vendor/glib-0.18.5-btc09/Cargo.toml.orig b/walletapp/vendor/glib-0.18.5-btc09/Cargo.toml.orig new file mode 100644 index 0000000..f6b791e --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/Cargo.toml.orig @@ -0,0 +1,74 @@ +[package] +name = "glib" +documentation = "https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/" +homepage = "https://gtk-rs.org/" +authors = ["The gtk-rs Project Developers"] +description = "Rust bindings for the GLib library" +readme = "README.md" +version = "0.18.5" +keywords = ["glib", "gtk-rs", "gnome", "GUI"] +repository = "https://github.com/gtk-rs/gtk-rs-core" +license = "MIT" +exclude = [ + "gir-files/*", +] +edition = "2021" +rust-version = "1.70" + +[lib] +name = "glib" + +[dependencies] +once_cell = "1.0" +libc = "0.2" +bitflags = "2.3" +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" +ffi = { package = "glib-sys", version = "0.18", path = "sys" } +gobject_ffi = { package = "gobject-sys", version = "0.18", path = "gobject-sys" } +glib-macros = { path = "../glib-macros", version = "0.18" } +rs-log = { package = "log", version = "0.4", optional = true } +smallvec = { version = "1.0", features = ["union", "const_generics", "const_new"] } +thiserror = "1" +gio_ffi = { package = "gio-sys", path = "../gio/sys", version = "0.18", optional = true } +memchr = "2.5.0" + +[dev-dependencies] +tempfile = "3" +gir-format-check = "^0.1" +trybuild2 = "1" +criterion = "0.5.1" + +[features] +default = ["gio"] +v2_58 = ["ffi/v2_58", "gobject_ffi/v2_58"] +v2_60 = ["v2_58", "ffi/v2_60"] +v2_62 = ["v2_60", "ffi/v2_62", "gobject_ffi/v2_62"] +v2_64 = ["v2_62", "ffi/v2_64"] +v2_66 = ["v2_64", "ffi/v2_66", "gobject_ffi/v2_66"] +v2_68 = ["v2_66", "ffi/v2_68", "gobject_ffi/v2_68"] +v2_70 = ["v2_68", "ffi/v2_70", "gobject_ffi/v2_70"] +v2_72 = ["v2_70", "ffi/v2_72", "gobject_ffi/v2_72"] +v2_74 = ["v2_72", "ffi/v2_74", "gobject_ffi/v2_74"] +v2_76 = ["v2_74", "ffi/v2_76", "gobject_ffi/v2_76"] +v2_78 = ["v2_76", "ffi/v2_78", "gobject_ffi/v2_78"] +log = ["rs-log"] +log_macros = ["log"] +compiletests = [] +gio = ["gio_ffi"] + +[package.metadata.docs.rs] +all-features = true +rustc-args = ["--cfg", "docsrs"] +rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"] + +[[test]] +name = "subclass_compiletest" +required-features = ["compiletests"] + +[[bench]] +name = "gstring" +harness = false diff --git a/walletapp/vendor/glib-0.18.5-btc09/Gir.toml b/walletapp/vendor/glib-0.18.5-btc09/Gir.toml new file mode 100644 index 0000000..8dfe2f7 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/Gir.toml @@ -0,0 +1,816 @@ +[options] +girs_directories = ["../gir-files"] +library = "GLib" +version = "2.0" +min_cfg_version = "2.56" +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.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.UserDirectory", + "GLib.Variant", + "GLib.VariantType", + "GObject.Object", +] + +[[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 = "(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 unecessary copy of the string + [[object.function]] + pattern = "(idle_remove_by_data|qsort_with_data)" + ignore = true # Unsafe functions + [[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.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]] +name = "GLib.UnicodeScript" +status = "generate" + [[object.member]] + name = "cypro_minoan" + version = "2.72" + [[object.member]] + name = "old_uyghur" + version = "2.72" + [[object.member]] + name = "tangsa" + version = "2.72" + [[object.member]] + name = "toto" + version = "2.72" + [[object.member]] + name = "vithkuqi" + version = "2.72" + [[object.member]] + name = "math" + version = "2.72" + [[object.member]] + name = "kawi" + version = "2.74" + [[object.member]] + name = "nag_mundari" + version = "2.74" + +[[object]] +name = "GLib.Uri" +status = "generate" +concurrency = "send+sync" diff --git a/walletapp/vendor/glib-0.18.5-btc09/Gir_GObject.toml b/walletapp/vendor/glib-0.18.5-btc09/Gir_GObject.toml new file mode 100644 index 0000000..8b68456 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/Gir_GObject.toml @@ -0,0 +1,149 @@ +[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", +] + +ignore = [ +] + +manual = [ + "GLib.Quark", + "GObject.Object", + "GObject.Value", + "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", +] + +[[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" diff --git a/walletapp/vendor/glib-0.18.5-btc09/LICENSE b/walletapp/vendor/glib-0.18.5-btc09/LICENSE new file mode 100644 index 0000000..64a801a --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/LICENSE @@ -0,0 +1,18 @@ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/walletapp/vendor/glib-0.18.5-btc09/README.md b/walletapp/vendor/glib-0.18.5-btc09/README.md new file mode 100644 index 0000000..7a2493d --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/README.md @@ -0,0 +1,101 @@ +# 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`]. +[`Variant`](struct@Variant)s can carry values of [`StaticVariantType`]. + +## Errors + +Errors are represented by [`Error`], which can +carry values from various [error domains](error::ErrorDomain) such as +[`FileError`]. + +## Objects + +Each class and interface has a corresponding smart pointer struct +representing an instance of that type (e.g. [`Object`] for `GObject` or +`gtk::Widget` for `GtkWidget`). They are reference counted and feature +interior mutability similarly to Rust's `Rc>` idiom. +Consequently, cloning objects is cheap and their methods never require +mutable borrows. Two smart pointers are equal if they point to the same +object. + +The root of the object hierarchy is [`Object`]. +Inheritance and subtyping is denoted with the [`IsA`] +marker trait. The [`Cast`] trait enables upcasting +and downcasting. + +Interfaces and non-leaf classes also have corresponding traits (e.g. +[`ObjectExt`] or `gtk::WidgetExt`), which are blanketly implemented for all +their subtypes. + +You can create new subclasses of [`Object`] or other object types. Look at +the module's documentation for further details and a code example. + +## Under the hood + +GLib-based libraries largely operate on pointers to various boxed or +reference counted structures so the bindings have to implement corresponding +smart pointers (wrappers), which encapsulate resource management and safety +checks. Such wrappers are defined via the +[`wrapper`][`macro@wrapper`] macro, which uses abstractions +defined in the [`wrapper`][`mod@wrapper`], [`boxed`][`mod@boxed`], +[`shared`][`mod@shared`] and [`object`][`mod@object`] modules. + +The [`translate`][`mod@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. diff --git a/walletapp/vendor/glib-0.18.5-btc09/benches/gstring.rs b/walletapp/vendor/glib-0.18.5-btc09/benches/gstring.rs new file mode 100644 index 0000000..a644ac0 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/benches/gstring.rs @@ -0,0 +1,46 @@ +use 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); diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/auto/alias.rs b/walletapp/vendor/glib-0.18.5-btc09/src/auto/alias.rs new file mode 100644 index 0000000..cd6abd2 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/auto/alias.rs @@ -0,0 +1,13 @@ +// 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; diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/auto/checksum.rs b/walletapp/vendor/glib-0.18.5-btc09/src/auto/checksum.rs new file mode 100644 index 0000000..6e8dbeb --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/auto/checksum.rs @@ -0,0 +1,46 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files (https://github.com/gtk-rs/gir-files) +// DO NOT EDIT + +use crate::{translate::*, 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 {} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/auto/constants.rs b/walletapp/vendor/glib-0.18.5-btc09/src/auto/constants.rs new file mode 100644 index 0000000..02a07d1 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/auto/constants.rs @@ -0,0 +1,105 @@ +// 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::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) }; +#[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) +}; diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/auto/date_time.rs b/walletapp/vendor/glib-0.18.5-btc09/src/auto/date_time.rs new file mode 100644 index 0000000..da0c3fc --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/auto/date_time.rs @@ -0,0 +1,502 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files (https://github.com/gtk-rs/gir-files) +// DO NOT EDIT + +use crate::{translate::*, BoolError, TimeSpan, TimeZone}; +use std::{cmp, hash, mem}; + +crate::wrapper! { + #[derive(Debug)] + pub struct DateTime(Shared); + + match fn { + ref => |ptr| ffi::g_date_time_ref(ptr), + unref => |ptr| ffi::g_date_time_unref(ptr), + type_ => || ffi::g_date_time_get_type(), + } +} + +impl DateTime { + #[doc(alias = "g_date_time_new")] + pub fn new( + tz: &TimeZone, + year: i32, + month: i32, + day: i32, + hour: i32, + minute: i32, + seconds: f64, + ) -> Result { + unsafe { + Option::<_>::from_glib_full(ffi::g_date_time_new( + tz.to_glib_none().0, + year, + month, + day, + hour, + minute, + seconds, + )) + .ok_or_else(|| crate::bool_error!("Invalid date")) + } + } + + #[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")) + } + } + + #[doc(alias = "g_date_time_new_from_unix_utc")] + #[doc(alias = "new_from_unix_utc")] + pub fn from_unix_utc(t: i64) -> Result { + unsafe { + Option::<_>::from_glib_full(ffi::g_date_time_new_from_unix_utc(t)) + .ok_or_else(|| crate::bool_error!("Invalid date")) + } + } + + #[doc(alias = "g_date_time_new_local")] + #[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 = mem::MaybeUninit::uninit(); + let mut month = mem::MaybeUninit::uninit(); + let mut day = mem::MaybeUninit::uninit(); + ffi::g_date_time_get_ymd( + self.to_glib_none().0, + year.as_mut_ptr(), + month.as_mut_ptr(), + day.as_mut_ptr(), + ); + (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) } + } + + #[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) -> cmp::Ordering { + self.compare(other).cmp(&0) + } +} + +impl PartialEq for DateTime { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.equal(other) + } +} + +impl Eq for DateTime {} + +impl hash::Hash for DateTime { + #[inline] + fn hash(&self, state: &mut H) + where + H: hash::Hasher, + { + hash::Hash::hash(&self.hash(), state) + } +} + +unsafe impl Send for DateTime {} +unsafe impl Sync for DateTime {} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/auto/enums.rs b/walletapp/vendor/glib-0.18.5-btc09/src/auto/enums.rs new file mode 100644 index 0000000..7b6706e --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/auto/enums.rs @@ -0,0 +1,2661 @@ +// 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::{prelude::*, translate::*}; +use std::fmt; + +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] +#[non_exhaustive] +#[doc(alias = "GChecksumType")] +pub enum ChecksumType { + #[doc(alias = "G_CHECKSUM_MD5")] + Md5, + #[doc(alias = "G_CHECKSUM_SHA1")] + Sha1, + #[doc(alias = "G_CHECKSUM_SHA256")] + Sha256, + #[doc(alias = "G_CHECKSUM_SHA512")] + Sha512, + #[doc(alias = "G_CHECKSUM_SHA384")] + Sha384, + #[doc(hidden)] + __Unknown(i32), +} + +impl fmt::Display for ChecksumType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "ChecksumType::{}", + match *self { + Self::Md5 => "Md5", + Self::Sha1 => "Sha1", + Self::Sha256 => "Sha256", + Self::Sha512 => "Sha512", + Self::Sha384 => "Sha384", + _ => "Unknown", + } + ) + } +} + +#[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), +} + +impl fmt::Display for ConvertError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "ConvertError::{}", + match *self { + Self::NoConversion => "NoConversion", + Self::IllegalSequence => "IllegalSequence", + Self::Failed => "Failed", + Self::PartialInput => "PartialInput", + Self::BadUri => "BadUri", + Self::NotAbsolutePath => "NotAbsolutePath", + Self::NoMemory => "NoMemory", + Self::EmbeddedNul => "EmbeddedNul", + _ => "Unknown", + } + ) + } +} + +#[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), +} + +impl fmt::Display for DateMonth { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "DateMonth::{}", + match *self { + Self::BadMonth => "BadMonth", + Self::January => "January", + Self::February => "February", + Self::March => "March", + Self::April => "April", + Self::May => "May", + Self::June => "June", + Self::July => "July", + Self::August => "August", + Self::September => "September", + Self::October => "October", + Self::November => "November", + Self::December => "December", + _ => "Unknown", + } + ) + } +} + +#[doc(hidden)] +impl IntoGlib for DateMonth { + type GlibType = ffi::GDateMonth; + + fn into_glib(self) -> ffi::GDateMonth { + match self { + Self::BadMonth => ffi::G_DATE_BAD_MONTH, + Self::January => ffi::G_DATE_JANUARY, + Self::February => ffi::G_DATE_FEBRUARY, + Self::March => ffi::G_DATE_MARCH, + Self::April => ffi::G_DATE_APRIL, + Self::May => ffi::G_DATE_MAY, + Self::June => ffi::G_DATE_JUNE, + Self::July => ffi::G_DATE_JULY, + Self::August => ffi::G_DATE_AUGUST, + Self::September => ffi::G_DATE_SEPTEMBER, + Self::October => ffi::G_DATE_OCTOBER, + Self::November => ffi::G_DATE_NOVEMBER, + Self::December => ffi::G_DATE_DECEMBER, + Self::__Unknown(value) => value, + } + } +} + +#[doc(hidden)] +impl FromGlib for DateMonth { + unsafe fn from_glib(value: ffi::GDateMonth) -> Self { + match value { + ffi::G_DATE_BAD_MONTH => Self::BadMonth, + ffi::G_DATE_JANUARY => Self::January, + ffi::G_DATE_FEBRUARY => Self::February, + ffi::G_DATE_MARCH => Self::March, + ffi::G_DATE_APRIL => Self::April, + ffi::G_DATE_MAY => Self::May, + ffi::G_DATE_JUNE => Self::June, + ffi::G_DATE_JULY => Self::July, + ffi::G_DATE_AUGUST => Self::August, + ffi::G_DATE_SEPTEMBER => Self::September, + ffi::G_DATE_OCTOBER => Self::October, + ffi::G_DATE_NOVEMBER => Self::November, + ffi::G_DATE_DECEMBER => Self::December, + value => Self::__Unknown(value), + } + } +} + +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] +#[non_exhaustive] +#[doc(alias = "GDateWeekday")] +pub enum DateWeekday { + #[doc(alias = "G_DATE_BAD_WEEKDAY")] + BadWeekday, + #[doc(alias = "G_DATE_MONDAY")] + Monday, + #[doc(alias = "G_DATE_TUESDAY")] + Tuesday, + #[doc(alias = "G_DATE_WEDNESDAY")] + Wednesday, + #[doc(alias = "G_DATE_THURSDAY")] + Thursday, + #[doc(alias = "G_DATE_FRIDAY")] + Friday, + #[doc(alias = "G_DATE_SATURDAY")] + Saturday, + #[doc(alias = "G_DATE_SUNDAY")] + Sunday, + #[doc(hidden)] + __Unknown(i32), +} + +impl fmt::Display for DateWeekday { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "DateWeekday::{}", + match *self { + Self::BadWeekday => "BadWeekday", + Self::Monday => "Monday", + Self::Tuesday => "Tuesday", + Self::Wednesday => "Wednesday", + Self::Thursday => "Thursday", + Self::Friday => "Friday", + Self::Saturday => "Saturday", + Self::Sunday => "Sunday", + _ => "Unknown", + } + ) + } +} + +#[doc(hidden)] +impl IntoGlib for DateWeekday { + type GlibType = ffi::GDateWeekday; + + #[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), +} + +impl fmt::Display for FileError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "FileError::{}", + match *self { + Self::Exist => "Exist", + Self::Isdir => "Isdir", + Self::Acces => "Acces", + Self::Nametoolong => "Nametoolong", + Self::Noent => "Noent", + Self::Notdir => "Notdir", + Self::Nxio => "Nxio", + Self::Nodev => "Nodev", + Self::Rofs => "Rofs", + Self::Txtbsy => "Txtbsy", + Self::Fault => "Fault", + Self::Loop => "Loop", + Self::Nospc => "Nospc", + Self::Nomem => "Nomem", + Self::Mfile => "Mfile", + Self::Nfile => "Nfile", + Self::Badf => "Badf", + Self::Inval => "Inval", + Self::Pipe => "Pipe", + Self::Again => "Again", + Self::Intr => "Intr", + Self::Io => "Io", + Self::Perm => "Perm", + Self::Nosys => "Nosys", + Self::Failed => "Failed", + _ => "Unknown", + } + ) + } +} + +#[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), +} + +impl fmt::Display for KeyFileError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "KeyFileError::{}", + match *self { + Self::UnknownEncoding => "UnknownEncoding", + Self::Parse => "Parse", + Self::NotFound => "NotFound", + Self::KeyNotFound => "KeyNotFound", + Self::GroupNotFound => "GroupNotFound", + Self::InvalidValue => "InvalidValue", + _ => "Unknown", + } + ) + } +} + +#[doc(hidden)] +impl IntoGlib for KeyFileError { + type GlibType = ffi::GKeyFileError; + + #[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), +} + +impl fmt::Display for LogWriterOutput { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "LogWriterOutput::{}", + match *self { + Self::Handled => "Handled", + Self::Unhandled => "Unhandled", + _ => "Unknown", + } + ) + } +} + +#[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), +} + +impl fmt::Display for MarkupError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "MarkupError::{}", + match *self { + Self::BadUtf8 => "BadUtf8", + Self::Empty => "Empty", + Self::Parse => "Parse", + Self::UnknownElement => "UnknownElement", + Self::UnknownAttribute => "UnknownAttribute", + Self::InvalidContent => "InvalidContent", + Self::MissingAttribute => "MissingAttribute", + _ => "Unknown", + } + ) + } +} + +#[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), +} + +impl fmt::Display for NormalizeMode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "NormalizeMode::{}", + match *self { + Self::Default => "Default", + Self::DefaultCompose => "DefaultCompose", + Self::All => "All", + Self::AllCompose => "AllCompose", + _ => "Unknown", + } + ) + } +} + +#[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), + } + } +} + +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] +#[non_exhaustive] +#[doc(alias = "GOptionArg")] +pub enum OptionArg { + #[doc(alias = "G_OPTION_ARG_NONE")] + None, + #[doc(alias = "G_OPTION_ARG_STRING")] + String, + #[doc(alias = "G_OPTION_ARG_INT")] + Int, + #[doc(alias = "G_OPTION_ARG_CALLBACK")] + Callback, + #[doc(alias = "G_OPTION_ARG_FILENAME")] + Filename, + #[doc(alias = "G_OPTION_ARG_STRING_ARRAY")] + StringArray, + #[doc(alias = "G_OPTION_ARG_FILENAME_ARRAY")] + FilenameArray, + #[doc(alias = "G_OPTION_ARG_DOUBLE")] + Double, + #[doc(alias = "G_OPTION_ARG_INT64")] + Int64, + #[doc(hidden)] + __Unknown(i32), +} + +impl fmt::Display for OptionArg { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "OptionArg::{}", + match *self { + Self::None => "None", + Self::String => "String", + Self::Int => "Int", + Self::Callback => "Callback", + Self::Filename => "Filename", + Self::StringArray => "StringArray", + Self::FilenameArray => "FilenameArray", + Self::Double => "Double", + Self::Int64 => "Int64", + _ => "Unknown", + } + ) + } +} + +#[doc(hidden)] +impl IntoGlib for OptionArg { + type GlibType = ffi::GOptionArg; + + #[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), +} + +impl fmt::Display for SeekType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "SeekType::{}", + match *self { + Self::Cur => "Cur", + Self::Set => "Set", + Self::End => "End", + _ => "Unknown", + } + ) + } +} + +#[doc(hidden)] +impl IntoGlib for SeekType { + type GlibType = ffi::GSeekType; + + #[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), +} + +impl fmt::Display for TimeType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "TimeType::{}", + match *self { + Self::Standard => "Standard", + Self::Daylight => "Daylight", + Self::Universal => "Universal", + _ => "Unknown", + } + ) + } +} + +#[doc(hidden)] +impl IntoGlib for TimeType { + type GlibType = ffi::GTimeType; + + #[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, + #[doc(hidden)] + __Unknown(i32), +} + +impl fmt::Display for UnicodeBreakType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "UnicodeBreakType::{}", + match *self { + Self::Mandatory => "Mandatory", + Self::CarriageReturn => "CarriageReturn", + Self::LineFeed => "LineFeed", + Self::CombiningMark => "CombiningMark", + Self::Surrogate => "Surrogate", + Self::ZeroWidthSpace => "ZeroWidthSpace", + Self::Inseparable => "Inseparable", + Self::NonBreakingGlue => "NonBreakingGlue", + Self::Contingent => "Contingent", + Self::Space => "Space", + Self::After => "After", + Self::Before => "Before", + Self::BeforeAndAfter => "BeforeAndAfter", + Self::Hyphen => "Hyphen", + Self::NonStarter => "NonStarter", + Self::OpenPunctuation => "OpenPunctuation", + Self::ClosePunctuation => "ClosePunctuation", + Self::Quotation => "Quotation", + Self::Exclamation => "Exclamation", + Self::Ideographic => "Ideographic", + Self::Numeric => "Numeric", + Self::InfixSeparator => "InfixSeparator", + Self::Symbol => "Symbol", + Self::Alphabetic => "Alphabetic", + Self::Prefix => "Prefix", + Self::Postfix => "Postfix", + Self::ComplexContext => "ComplexContext", + Self::Ambiguous => "Ambiguous", + Self::Unknown => "Unknown", + Self::NextLine => "NextLine", + Self::WordJoiner => "WordJoiner", + Self::HangulLJamo => "HangulLJamo", + Self::HangulVJamo => "HangulVJamo", + Self::HangulTJamo => "HangulTJamo", + Self::HangulLvSyllable => "HangulLvSyllable", + Self::HangulLvtSyllable => "HangulLvtSyllable", + Self::CloseParenthesis => "CloseParenthesis", + Self::ConditionalJapaneseStarter => "ConditionalJapaneseStarter", + Self::HebrewLetter => "HebrewLetter", + Self::RegionalIndicator => "RegionalIndicator", + Self::EmojiBase => "EmojiBase", + Self::EmojiModifier => "EmojiModifier", + Self::ZeroWidthJoiner => "ZeroWidthJoiner", + _ => "Unknown", + } + ) + } +} + +#[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, + 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, + value => Self::__Unknown(value), + } + } +} + +#[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, + #[doc(hidden)] + __Unknown(i32), +} + +impl fmt::Display for UnicodeScript { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "UnicodeScript::{}", + match *self { + Self::InvalidCode => "InvalidCode", + Self::Common => "Common", + Self::Inherited => "Inherited", + Self::Arabic => "Arabic", + Self::Armenian => "Armenian", + Self::Bengali => "Bengali", + Self::Bopomofo => "Bopomofo", + Self::Cherokee => "Cherokee", + Self::Coptic => "Coptic", + Self::Cyrillic => "Cyrillic", + Self::Deseret => "Deseret", + Self::Devanagari => "Devanagari", + Self::Ethiopic => "Ethiopic", + Self::Georgian => "Georgian", + Self::Gothic => "Gothic", + Self::Greek => "Greek", + Self::Gujarati => "Gujarati", + Self::Gurmukhi => "Gurmukhi", + Self::Han => "Han", + Self::Hangul => "Hangul", + Self::Hebrew => "Hebrew", + Self::Hiragana => "Hiragana", + Self::Kannada => "Kannada", + Self::Katakana => "Katakana", + Self::Khmer => "Khmer", + Self::Lao => "Lao", + Self::Latin => "Latin", + Self::Malayalam => "Malayalam", + Self::Mongolian => "Mongolian", + Self::Myanmar => "Myanmar", + Self::Ogham => "Ogham", + Self::OldItalic => "OldItalic", + Self::Oriya => "Oriya", + Self::Runic => "Runic", + Self::Sinhala => "Sinhala", + Self::Syriac => "Syriac", + Self::Tamil => "Tamil", + Self::Telugu => "Telugu", + Self::Thaana => "Thaana", + Self::Thai => "Thai", + Self::Tibetan => "Tibetan", + Self::CanadianAboriginal => "CanadianAboriginal", + Self::Yi => "Yi", + Self::Tagalog => "Tagalog", + Self::Hanunoo => "Hanunoo", + Self::Buhid => "Buhid", + Self::Tagbanwa => "Tagbanwa", + Self::Braille => "Braille", + Self::Cypriot => "Cypriot", + Self::Limbu => "Limbu", + Self::Osmanya => "Osmanya", + Self::Shavian => "Shavian", + Self::LinearB => "LinearB", + Self::TaiLe => "TaiLe", + Self::Ugaritic => "Ugaritic", + Self::NewTaiLue => "NewTaiLue", + Self::Buginese => "Buginese", + Self::Glagolitic => "Glagolitic", + Self::Tifinagh => "Tifinagh", + Self::SylotiNagri => "SylotiNagri", + Self::OldPersian => "OldPersian", + Self::Kharoshthi => "Kharoshthi", + Self::Unknown => "Unknown", + Self::Balinese => "Balinese", + Self::Cuneiform => "Cuneiform", + Self::Phoenician => "Phoenician", + Self::PhagsPa => "PhagsPa", + Self::Nko => "Nko", + Self::KayahLi => "KayahLi", + Self::Lepcha => "Lepcha", + Self::Rejang => "Rejang", + Self::Sundanese => "Sundanese", + Self::Saurashtra => "Saurashtra", + Self::Cham => "Cham", + Self::OlChiki => "OlChiki", + Self::Vai => "Vai", + Self::Carian => "Carian", + Self::Lycian => "Lycian", + Self::Lydian => "Lydian", + Self::Avestan => "Avestan", + Self::Bamum => "Bamum", + Self::EgyptianHieroglyphs => "EgyptianHieroglyphs", + Self::ImperialAramaic => "ImperialAramaic", + Self::InscriptionalPahlavi => "InscriptionalPahlavi", + Self::InscriptionalParthian => "InscriptionalParthian", + Self::Javanese => "Javanese", + Self::Kaithi => "Kaithi", + Self::Lisu => "Lisu", + Self::MeeteiMayek => "MeeteiMayek", + Self::OldSouthArabian => "OldSouthArabian", + Self::OldTurkic => "OldTurkic", + Self::Samaritan => "Samaritan", + Self::TaiTham => "TaiTham", + Self::TaiViet => "TaiViet", + Self::Batak => "Batak", + Self::Brahmi => "Brahmi", + Self::Mandaic => "Mandaic", + Self::Chakma => "Chakma", + Self::MeroiticCursive => "MeroiticCursive", + Self::MeroiticHieroglyphs => "MeroiticHieroglyphs", + Self::Miao => "Miao", + Self::Sharada => "Sharada", + Self::SoraSompeng => "SoraSompeng", + Self::Takri => "Takri", + Self::BassaVah => "BassaVah", + Self::CaucasianAlbanian => "CaucasianAlbanian", + Self::Duployan => "Duployan", + Self::Elbasan => "Elbasan", + Self::Grantha => "Grantha", + Self::Khojki => "Khojki", + Self::Khudawadi => "Khudawadi", + Self::LinearA => "LinearA", + Self::Mahajani => "Mahajani", + Self::Manichaean => "Manichaean", + Self::MendeKikakui => "MendeKikakui", + Self::Modi => "Modi", + Self::Mro => "Mro", + Self::Nabataean => "Nabataean", + Self::OldNorthArabian => "OldNorthArabian", + Self::OldPermic => "OldPermic", + Self::PahawhHmong => "PahawhHmong", + Self::Palmyrene => "Palmyrene", + Self::PauCinHau => "PauCinHau", + Self::PsalterPahlavi => "PsalterPahlavi", + Self::Siddham => "Siddham", + Self::Tirhuta => "Tirhuta", + Self::WarangCiti => "WarangCiti", + Self::Ahom => "Ahom", + Self::AnatolianHieroglyphs => "AnatolianHieroglyphs", + Self::Hatran => "Hatran", + Self::Multani => "Multani", + Self::OldHungarian => "OldHungarian", + Self::Signwriting => "Signwriting", + Self::Adlam => "Adlam", + Self::Bhaiksuki => "Bhaiksuki", + Self::Marchen => "Marchen", + Self::Newa => "Newa", + Self::Osage => "Osage", + Self::Tangut => "Tangut", + Self::MasaramGondi => "MasaramGondi", + Self::Nushu => "Nushu", + Self::Soyombo => "Soyombo", + Self::ZanabazarSquare => "ZanabazarSquare", + Self::Dogra => "Dogra", + Self::GunjalaGondi => "GunjalaGondi", + Self::HanifiRohingya => "HanifiRohingya", + Self::Makasar => "Makasar", + Self::Medefaidrin => "Medefaidrin", + Self::OldSogdian => "OldSogdian", + Self::Sogdian => "Sogdian", + Self::Elymaic => "Elymaic", + Self::Nandinagari => "Nandinagari", + Self::NyiakengPuachueHmong => "NyiakengPuachueHmong", + Self::Wancho => "Wancho", + Self::Chorasmian => "Chorasmian", + Self::DivesAkuru => "DivesAkuru", + Self::KhitanSmallScript => "KhitanSmallScript", + Self::Yezidi => "Yezidi", + #[cfg(feature = "v2_72")] + Self::CyproMinoan => "CyproMinoan", + #[cfg(feature = "v2_72")] + Self::OldUyghur => "OldUyghur", + #[cfg(feature = "v2_72")] + Self::Tangsa => "Tangsa", + #[cfg(feature = "v2_72")] + Self::Toto => "Toto", + #[cfg(feature = "v2_72")] + Self::Vithkuqi => "Vithkuqi", + #[cfg(feature = "v2_72")] + Self::Math => "Math", + #[cfg(feature = "v2_74")] + Self::Kawi => "Kawi", + #[cfg(feature = "v2_74")] + Self::NagMundari => "NagMundari", + _ => "Unknown", + } + ) + } +} + +#[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, + 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, + value => Self::__Unknown(value), + } + } +} + +#[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), +} + +impl fmt::Display for UnicodeType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "UnicodeType::{}", + match *self { + Self::Control => "Control", + Self::Format => "Format", + Self::Unassigned => "Unassigned", + Self::PrivateUse => "PrivateUse", + Self::Surrogate => "Surrogate", + Self::LowercaseLetter => "LowercaseLetter", + Self::ModifierLetter => "ModifierLetter", + Self::OtherLetter => "OtherLetter", + Self::TitlecaseLetter => "TitlecaseLetter", + Self::UppercaseLetter => "UppercaseLetter", + Self::SpacingMark => "SpacingMark", + Self::EnclosingMark => "EnclosingMark", + Self::NonSpacingMark => "NonSpacingMark", + Self::DecimalNumber => "DecimalNumber", + Self::LetterNumber => "LetterNumber", + Self::OtherNumber => "OtherNumber", + Self::ConnectPunctuation => "ConnectPunctuation", + Self::DashPunctuation => "DashPunctuation", + Self::ClosePunctuation => "ClosePunctuation", + Self::FinalPunctuation => "FinalPunctuation", + Self::InitialPunctuation => "InitialPunctuation", + Self::OtherPunctuation => "OtherPunctuation", + Self::OpenPunctuation => "OpenPunctuation", + Self::CurrencySymbol => "CurrencySymbol", + Self::ModifierSymbol => "ModifierSymbol", + Self::MathSymbol => "MathSymbol", + Self::OtherSymbol => "OtherSymbol", + Self::LineSeparator => "LineSeparator", + Self::ParagraphSeparator => "ParagraphSeparator", + Self::SpaceSeparator => "SpaceSeparator", + _ => "Unknown", + } + ) + } +} + +#[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), + } + } +} + +#[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")))] +impl fmt::Display for UriError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "UriError::{}", + match *self { + Self::Failed => "Failed", + Self::BadScheme => "BadScheme", + Self::BadUser => "BadUser", + Self::BadPassword => "BadPassword", + Self::BadAuthParams => "BadAuthParams", + Self::BadHost => "BadHost", + Self::BadPort => "BadPort", + Self::BadPath => "BadPath", + Self::BadQuery => "BadQuery", + Self::BadFragment => "BadFragment", + _ => "Unknown", + } + ) + } +} + +#[cfg(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), +} + +impl fmt::Display for VariantClass { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "VariantClass::{}", + match *self { + Self::Boolean => "Boolean", + Self::Byte => "Byte", + Self::Int16 => "Int16", + Self::Uint16 => "Uint16", + Self::Int32 => "Int32", + Self::Uint32 => "Uint32", + Self::Int64 => "Int64", + Self::Uint64 => "Uint64", + Self::Handle => "Handle", + Self::Double => "Double", + Self::String => "String", + Self::ObjectPath => "ObjectPath", + Self::Signature => "Signature", + Self::Variant => "Variant", + Self::Maybe => "Maybe", + Self::Array => "Array", + Self::Tuple => "Tuple", + Self::DictEntry => "DictEntry", + _ => "Unknown", + } + ) + } +} + +#[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), + } + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/auto/flags.rs b/walletapp/vendor/glib-0.18.5-btc09/src/auto/flags.rs new file mode 100644 index 0000000..0ff8baa --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/auto/flags.rs @@ -0,0 +1,636 @@ +// 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, prelude::*, translate::*}; +use std::fmt; + +#[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")))] +impl fmt::Display for FileSetContentsFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(self, f) + } +} + +#[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 _; + } +} + +impl fmt::Display for FileTest { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(self, f) + } +} + +#[doc(hidden)] +impl IntoGlib for FileTest { + type GlibType = ffi::GFileTest; + + #[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 _; + } +} + +impl fmt::Display for FormatSizeFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(self, f) + } +} + +#[doc(hidden)] +impl IntoGlib for FormatSizeFlags { + type GlibType = ffi::GFormatSizeFlags; + + #[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 _; + } +} + +impl fmt::Display for IOCondition { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(self, f) + } +} + +#[doc(hidden)] +impl IntoGlib for IOCondition { + type GlibType = ffi::GIOCondition; + + #[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 _; + } +} + +impl fmt::Display for KeyFileFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(self, f) + } +} + +#[doc(hidden)] +impl IntoGlib for KeyFileFlags { + type GlibType = ffi::GKeyFileFlags; + + #[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 _; + } +} + +impl fmt::Display for LogLevelFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(self, f) + } +} + +#[doc(hidden)] +impl IntoGlib for LogLevelFlags { + type GlibType = ffi::GLogLevelFlags; + + #[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")))] +impl fmt::Display for MainContextFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(self, f) + } +} + +#[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 _; + } +} + +impl fmt::Display for OptionFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(self, f) + } +} + +#[doc(hidden)] +impl IntoGlib for OptionFlags { + type GlibType = ffi::GOptionFlags; + + #[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 = "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 _; + } +} + +impl fmt::Display for SpawnFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(self, f) + } +} + +#[doc(hidden)] +impl IntoGlib for SpawnFlags { + type GlibType = ffi::GSpawnFlags; + + #[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")))] +impl fmt::Display for UriFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(self, f) + } +} + +#[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")))] +impl fmt::Display for UriHideFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(self, f) + } +} + +#[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")))] +impl fmt::Display for UriParamsFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(self, f) + } +} + +#[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) + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/auto/functions.rs b/walletapp/vendor/glib-0.18.5-btc09/src/auto/functions.rs new file mode 100644 index 0000000..7d569ad --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/auto/functions.rs @@ -0,0 +1,863 @@ +// 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::{ + translate::*, Bytes, ChecksumType, Error, FileTest, FormatSizeFlags, Pid, Source, SpawnFlags, + UnicodeScript, UserDirectory, +}; +use std::{boxed::Box as Box_, mem, ptr}; + +#[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 = 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 = 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 = 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 = ptr::null_mut(); + let mut error = 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 = 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 = 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: &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 = mem::MaybeUninit::uninit(); + let mut argvp = ptr::null_mut(); + let mut error = 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 = ptr::null_mut(); + let ret = ffi::g_shell_unquote(quoted_string.as_ref().to_glib_none().0, &mut error); + if error.is_null() { + Ok(from_glib_full(ret)) + } else { + Err(from_glib_full(error)) + } + } +} + +#[doc(alias = "g_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_>> = Box_::from_raw(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 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 = 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 = 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 = 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_unicode_script_from_iso15924")] +pub fn unicode_script_from_iso15924(iso15924: u32) -> UnicodeScript { + unsafe { from_glib(ffi::g_unicode_script_from_iso15924(iso15924)) } +} + +#[doc(alias = "g_unicode_script_to_iso15924")] +pub fn unicode_script_to_iso15924(script: UnicodeScript) -> u32 { + unsafe { ffi::g_unicode_script_to_iso15924(script.into_glib()) } +} + +//#[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()) } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/auto/key_file.rs b/walletapp/vendor/glib-0.18.5-btc09/src/auto/key_file.rs new file mode 100644 index 0000000..8c7986e --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/auto/key_file.rs @@ -0,0 +1,487 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files (https://github.com/gtk-rs/gir-files) +// DO NOT EDIT + +use crate::{translate::*, Bytes, Error, KeyFileFlags}; +use std::{mem, ptr}; + +crate::wrapper! { + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct KeyFile(Shared); + + match fn { + ref => |ptr| ffi::g_key_file_ref(ptr), + unref => |ptr| ffi::g_key_file_unref(ptr), + type_ => || ffi::g_key_file_get_type(), + } +} + +impl KeyFile { + #[doc(alias = "g_key_file_new")] + pub fn new() -> KeyFile { + unsafe { from_glib_full(ffi::g_key_file_new()) } + } + + #[doc(alias = "g_key_file_get_comment")] + #[doc(alias = "get_comment")] + pub fn comment( + &self, + group_name: Option<&str>, + key: Option<&str>, + ) -> Result { + unsafe { + let mut error = ptr::null_mut(); + let ret = ffi::g_key_file_get_comment( + self.to_glib_none().0, + group_name.to_glib_none().0, + key.to_glib_none().0, + &mut error, + ); + if error.is_null() { + Ok(from_glib_full(ret)) + } else { + Err(from_glib_full(error)) + } + } + } + + #[doc(alias = "g_key_file_get_double")] + #[doc(alias = "get_double")] + pub fn double(&self, group_name: &str, key: &str) -> Result { + unsafe { + let mut error = ptr::null_mut(); + let ret = ffi::g_key_file_get_double( + self.to_glib_none().0, + group_name.to_glib_none().0, + key.to_glib_none().0, + &mut error, + ); + if error.is_null() { + Ok(ret) + } else { + Err(from_glib_full(error)) + } + } + } + + #[doc(alias = "g_key_file_get_double_list")] + #[doc(alias = "get_double_list")] + pub fn double_list(&self, group_name: &str, key: &str) -> Result, crate::Error> { + unsafe { + let mut length = mem::MaybeUninit::uninit(); + let mut error = ptr::null_mut(); + let ret = ffi::g_key_file_get_double_list( + self.to_glib_none().0, + group_name.to_glib_none().0, + key.to_glib_none().0, + length.as_mut_ptr(), + &mut error, + ); + if error.is_null() { + Ok(FromGlibContainer::from_glib_container_num( + ret, + length.assume_init() as _, + )) + } 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 = ptr::null_mut(); + let ret = ffi::g_key_file_get_int64( + self.to_glib_none().0, + group_name.to_glib_none().0, + key.to_glib_none().0, + &mut error, + ); + if error.is_null() { + Ok(ret) + } else { + Err(from_glib_full(error)) + } + } + } + + #[doc(alias = "g_key_file_get_integer")] + #[doc(alias = "get_integer")] + pub fn integer(&self, group_name: &str, key: &str) -> Result { + unsafe { + let mut error = ptr::null_mut(); + let ret = ffi::g_key_file_get_integer( + self.to_glib_none().0, + group_name.to_glib_none().0, + key.to_glib_none().0, + &mut error, + ); + if error.is_null() { + Ok(ret) + } else { + Err(from_glib_full(error)) + } + } + } + + #[doc(alias = "g_key_file_get_integer_list")] + #[doc(alias = "get_integer_list")] + pub fn integer_list(&self, group_name: &str, key: &str) -> Result, crate::Error> { + unsafe { + let mut length = mem::MaybeUninit::uninit(); + let mut error = ptr::null_mut(); + let ret = ffi::g_key_file_get_integer_list( + self.to_glib_none().0, + group_name.to_glib_none().0, + key.to_glib_none().0, + length.as_mut_ptr(), + &mut error, + ); + if error.is_null() { + Ok(FromGlibContainer::from_glib_container_num( + ret, + length.assume_init() as _, + )) + } 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 = ptr::null_mut(); + let ret = ffi::g_key_file_get_uint64( + self.to_glib_none().0, + group_name.to_glib_none().0, + key.to_glib_none().0, + &mut error, + ); + if error.is_null() { + Ok(ret) + } else { + Err(from_glib_full(error)) + } + } + } + + #[doc(alias = "g_key_file_get_value")] + #[doc(alias = "get_value")] + pub fn value(&self, group_name: &str, key: &str) -> Result { + unsafe { + let mut error = ptr::null_mut(); + let ret = ffi::g_key_file_get_value( + self.to_glib_none().0, + group_name.to_glib_none().0, + key.to_glib_none().0, + &mut error, + ); + if error.is_null() { + Ok(from_glib_full(ret)) + } else { + Err(from_glib_full(error)) + } + } + } + + #[doc(alias = "g_key_file_has_group")] + pub fn has_group(&self, group_name: &str) -> bool { + unsafe { + from_glib(ffi::g_key_file_has_group( + self.to_glib_none().0, + group_name.to_glib_none().0, + )) + } + } + + #[doc(alias = "g_key_file_load_from_bytes")] + pub fn load_from_bytes(&self, bytes: &Bytes, flags: KeyFileFlags) -> Result<(), crate::Error> { + unsafe { + let mut error = ptr::null_mut(); + let 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 = 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 = 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 = 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 = 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 = 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 = 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() + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/auto/main_context.rs b/walletapp/vendor/glib-0.18.5-btc09/src/auto/main_context.rs new file mode 100644 index 0000000..cc4da92 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/auto/main_context.rs @@ -0,0 +1,142 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files (https://github.com/gtk-rs/gir-files) +// DO NOT EDIT + +use crate::translate::*; +#[cfg(feature = "v2_72")] +#[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))] +use crate::MainContextFlags; + +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)) } + } + + //#[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()) } + } + + #[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 {} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/auto/main_loop.rs b/walletapp/vendor/glib-0.18.5-btc09/src/auto/main_loop.rs new file mode 100644 index 0000000..64a27a1 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/auto/main_loop.rs @@ -0,0 +1,56 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files (https://github.com/gtk-rs/gir-files) +// DO NOT EDIT + +use crate::{translate::*, 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 {} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/auto/markup_parse_context.rs b/walletapp/vendor/glib-0.18.5-btc09/src/auto/markup_parse_context.rs new file mode 100644 index 0000000..f071797 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/auto/markup_parse_context.rs @@ -0,0 +1,99 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files (https://github.com/gtk-rs/gir-files) +// DO NOT EDIT + +use crate::{translate::*, Error}; +use std::{mem, ptr}; + +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 = 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) -> /*Unimplemented*/Vec { + // unsafe { TODO: call ffi:g_markup_parse_context_get_element_stack() } + //} + + #[doc(alias = "g_markup_parse_context_get_position")] + #[doc(alias = "get_position")] + pub fn position(&self) -> (i32, i32) { + unsafe { + let mut line_number = mem::MaybeUninit::uninit(); + let mut char_number = 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 = 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() } + //} +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/auto/mod.rs b/walletapp/vendor/glib-0.18.5-btc09/src/auto/mod.rs new file mode 100644 index 0000000..bbe89c8 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/auto/mod.rs @@ -0,0 +1,123 @@ +// 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 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::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 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; +pub use self::constants::URI_RESERVED_CHARS_GENERIC_DELIMITERS; +pub use self::constants::URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS; diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/auto/source.rs b/walletapp/vendor/glib-0.18.5-btc09/src/auto/source.rs new file mode 100644 index 0000000..e1418ba --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/auto/source.rs @@ -0,0 +1,128 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files (https://github.com/gtk-rs/gir-files) +// DO NOT EDIT + +use crate::{translate::*, 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 {} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/auto/time_zone.rs b/walletapp/vendor/glib-0.18.5-btc09/src/auto/time_zone.rs new file mode 100644 index 0000000..23d3cef --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/auto/time_zone.rs @@ -0,0 +1,91 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files (https://github.com/gtk-rs/gir-files) +// DO NOT EDIT + +use crate::{translate::*, 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 {} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/auto/uri.rs b/walletapp/vendor/glib-0.18.5-btc09/src/auto/uri.rs new file mode 100644 index 0000000..d1e2c37 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/auto/uri.rs @@ -0,0 +1,535 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files (https://github.com/gtk-rs/gir-files) +// DO NOT EDIT + +use crate::{translate::*, Bytes, Error, UriFlags, UriHideFlags}; +use std::{fmt, mem, ptr}; + +crate::wrapper! { + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct Uri(Shared); + + match fn { + ref => |ptr| ffi::g_uri_ref(ptr), + unref => |ptr| ffi::g_uri_unref(ptr), + type_ => || ffi::g_uri_get_type(), + } +} + +impl Uri { + #[doc(alias = "g_uri_get_auth_params")] + #[doc(alias = "get_auth_params")] + pub fn auth_params(&self) -> Option { + unsafe { from_glib_none(ffi::g_uri_get_auth_params(self.to_glib_none().0)) } + } + + #[doc(alias = "g_uri_get_flags")] + #[doc(alias = "get_flags")] + pub fn flags(&self) -> UriFlags { + unsafe { from_glib(ffi::g_uri_get_flags(self.to_glib_none().0)) } + } + + #[doc(alias = "g_uri_get_fragment")] + #[doc(alias = "get_fragment")] + pub fn fragment(&self) -> Option { + unsafe { from_glib_none(ffi::g_uri_get_fragment(self.to_glib_none().0)) } + } + + #[doc(alias = "g_uri_get_host")] + #[doc(alias = "get_host")] + pub fn host(&self) -> Option { + unsafe { from_glib_none(ffi::g_uri_get_host(self.to_glib_none().0)) } + } + + #[doc(alias = "g_uri_get_password")] + #[doc(alias = "get_password")] + pub fn password(&self) -> Option { + unsafe { from_glib_none(ffi::g_uri_get_password(self.to_glib_none().0)) } + } + + #[doc(alias = "g_uri_get_path")] + #[doc(alias = "get_path")] + pub fn path(&self) -> crate::GString { + unsafe { from_glib_none(ffi::g_uri_get_path(self.to_glib_none().0)) } + } + + #[doc(alias = "g_uri_get_port")] + #[doc(alias = "get_port")] + pub fn port(&self) -> i32 { + unsafe { ffi::g_uri_get_port(self.to_glib_none().0) } + } + + #[doc(alias = "g_uri_get_query")] + #[doc(alias = "get_query")] + pub fn query(&self) -> Option { + unsafe { from_glib_none(ffi::g_uri_get_query(self.to_glib_none().0)) } + } + + #[doc(alias = "g_uri_get_scheme")] + #[doc(alias = "get_scheme")] + pub fn scheme(&self) -> crate::GString { + unsafe { from_glib_none(ffi::g_uri_get_scheme(self.to_glib_none().0)) } + } + + #[doc(alias = "g_uri_get_user")] + #[doc(alias = "get_user")] + pub fn user(&self) -> Option { + unsafe { from_glib_none(ffi::g_uri_get_user(self.to_glib_none().0)) } + } + + #[doc(alias = "g_uri_get_userinfo")] + #[doc(alias = "get_userinfo")] + pub fn userinfo(&self) -> Option { + unsafe { from_glib_none(ffi::g_uri_get_userinfo(self.to_glib_none().0)) } + } + + #[doc(alias = "g_uri_parse_relative")] + pub fn parse_relative(&self, uri_ref: &str, flags: UriFlags) -> Result { + unsafe { + let mut error = ptr::null_mut(); + let ret = ffi::g_uri_parse_relative( + self.to_glib_none().0, + uri_ref.to_glib_none().0, + flags.into_glib(), + &mut error, + ); + if error.is_null() { + Ok(from_glib_full(ret)) + } else { + Err(from_glib_full(error)) + } + } + } + + #[doc(alias = "g_uri_to_string")] + #[doc(alias = "to_string")] + pub fn to_str(&self) -> crate::GString { + unsafe { from_glib_full(ffi::g_uri_to_string(self.to_glib_none().0)) } + } + + #[doc(alias = "g_uri_to_string_partial")] + pub fn to_string_partial(&self, flags: UriHideFlags) -> crate::GString { + unsafe { + from_glib_full(ffi::g_uri_to_string_partial( + self.to_glib_none().0, + flags.into_glib(), + )) + } + } + + #[doc(alias = "g_uri_build")] + pub fn build( + flags: UriFlags, + scheme: &str, + userinfo: Option<&str>, + host: Option<&str>, + port: i32, + path: &str, + query: Option<&str>, + fragment: Option<&str>, + ) -> Uri { + unsafe { + from_glib_full(ffi::g_uri_build( + flags.into_glib(), + scheme.to_glib_none().0, + userinfo.to_glib_none().0, + host.to_glib_none().0, + port, + path.to_glib_none().0, + query.to_glib_none().0, + fragment.to_glib_none().0, + )) + } + } + + #[doc(alias = "g_uri_build_with_user")] + pub fn build_with_user( + flags: UriFlags, + scheme: &str, + user: Option<&str>, + password: Option<&str>, + auth_params: Option<&str>, + host: Option<&str>, + port: i32, + path: &str, + query: Option<&str>, + fragment: Option<&str>, + ) -> Uri { + unsafe { + from_glib_full(ffi::g_uri_build_with_user( + flags.into_glib(), + scheme.to_glib_none().0, + user.to_glib_none().0, + password.to_glib_none().0, + auth_params.to_glib_none().0, + host.to_glib_none().0, + port, + path.to_glib_none().0, + query.to_glib_none().0, + fragment.to_glib_none().0, + )) + } + } + + #[doc(alias = "g_uri_escape_bytes")] + pub fn escape_bytes(unescaped: &[u8], reserved_chars_allowed: Option<&str>) -> crate::GString { + let length = unescaped.len() as _; + unsafe { + from_glib_full(ffi::g_uri_escape_bytes( + unescaped.to_glib_none().0, + length, + reserved_chars_allowed.to_glib_none().0, + )) + } + } + + #[doc(alias = "g_uri_escape_string")] + pub fn escape_string( + unescaped: &str, + reserved_chars_allowed: Option<&str>, + allow_utf8: bool, + ) -> crate::GString { + unsafe { + from_glib_full(ffi::g_uri_escape_string( + unescaped.to_glib_none().0, + reserved_chars_allowed.to_glib_none().0, + allow_utf8.into_glib(), + )) + } + } + + #[doc(alias = "g_uri_is_valid")] + pub fn is_valid(uri_string: &str, flags: UriFlags) -> Result<(), crate::Error> { + unsafe { + let mut error = ptr::null_mut(); + let 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 = ptr::null_mut(); + let ret = ffi::g_uri_parse(uri_string.to_glib_none().0, flags.into_glib(), &mut error); + if error.is_null() { + Ok(from_glib_full(ret)) + } else { + Err(from_glib_full(error)) + } + } + } + + //#[doc(alias = "g_uri_parse_params")] + //pub fn parse_params(params: &str, separators: &str, flags: UriParamsFlags) -> Result { + // unsafe { TODO: call ffi:g_uri_parse_params() } + //} + + #[doc(alias = "g_uri_parse_scheme")] + pub fn parse_scheme(uri: &str) -> Option { + unsafe { from_glib_full(ffi::g_uri_parse_scheme(uri.to_glib_none().0)) } + } + + #[doc(alias = "g_uri_peek_scheme")] + pub fn peek_scheme(uri: &str) -> Option { + unsafe { from_glib_none(ffi::g_uri_peek_scheme(uri.to_glib_none().0)) } + } + + #[doc(alias = "g_uri_resolve_relative")] + pub fn resolve_relative( + base_uri_string: Option<&str>, + uri_ref: &str, + flags: UriFlags, + ) -> Result { + unsafe { + let mut error = ptr::null_mut(); + let ret = ffi::g_uri_resolve_relative( + base_uri_string.to_glib_none().0, + uri_ref.to_glib_none().0, + flags.into_glib(), + &mut error, + ); + if error.is_null() { + Ok(from_glib_full(ret)) + } else { + Err(from_glib_full(error)) + } + } + } + + #[doc(alias = "g_uri_split")] + pub fn split( + uri_ref: &str, + flags: UriFlags, + ) -> Result< + ( + Option, + Option, + Option, + i32, + crate::GString, + Option, + Option, + ), + crate::Error, + > { + unsafe { + let mut scheme = ptr::null_mut(); + let mut userinfo = ptr::null_mut(); + let mut host = ptr::null_mut(); + let mut port = mem::MaybeUninit::uninit(); + let mut path = ptr::null_mut(); + let mut query = ptr::null_mut(); + let mut fragment = ptr::null_mut(); + let mut error = ptr::null_mut(); + let 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 = ptr::null_mut(); + let mut host = ptr::null_mut(); + let mut port = mem::MaybeUninit::uninit(); + let mut error = 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 = ptr::null_mut(); + let mut user = ptr::null_mut(); + let mut password = ptr::null_mut(); + let mut auth_params = ptr::null_mut(); + let mut host = ptr::null_mut(); + let mut port = mem::MaybeUninit::uninit(); + let mut path = ptr::null_mut(); + let mut query = ptr::null_mut(); + let mut fragment = ptr::null_mut(); + let mut error = ptr::null_mut(); + let 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 = ptr::null_mut(); + let ret = ffi::g_uri_unescape_bytes( + escaped_string.to_glib_none().0, + length, + illegal_characters.to_glib_none().0, + &mut error, + ); + if error.is_null() { + Ok(from_glib_full(ret)) + } else { + Err(from_glib_full(error)) + } + } + } + + #[doc(alias = "g_uri_unescape_segment")] + pub fn unescape_segment( + escaped_string: Option<&str>, + escaped_string_end: Option<&str>, + illegal_characters: Option<&str>, + ) -> Option { + unsafe { + from_glib_full(ffi::g_uri_unescape_segment( + escaped_string.to_glib_none().0, + escaped_string_end.to_glib_none().0, + illegal_characters.to_glib_none().0, + )) + } + } + + #[doc(alias = "g_uri_unescape_string")] + pub fn unescape_string( + escaped_string: &str, + illegal_characters: Option<&str>, + ) -> Option { + unsafe { + from_glib_full(ffi::g_uri_unescape_string( + escaped_string.to_glib_none().0, + illegal_characters.to_glib_none().0, + )) + } + } +} + +impl fmt::Display for Uri { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.to_str()) + } +} + +unsafe impl Send for Uri {} +unsafe impl Sync for Uri {} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/auto/versions.txt b/walletapp/vendor/glib-0.18.5-btc09/src/auto/versions.txt new file mode 100644 index 0000000..8871d4e --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/auto/versions.txt @@ -0,0 +1,2 @@ +Generated by gir (https://github.com/gtk-rs/gir @ 23d7c100187c) +from gir-files (https://github.com/gtk-rs/gir-files @ 6415239ef435) diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/boxed.rs b/walletapp/vendor/glib-0.18.5-btc09/src/boxed.rs new file mode 100644 index 0000000..70d6a23 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/boxed.rs @@ -0,0 +1,606 @@ +// 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])* + #[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<'a>(ptr: *const *const $ffi_name) -> &'a Self { + &*(ptr as *const Self) + } + + #[doc = "Borrows the underlying C value mutably."] + #[inline] + pub unsafe fn from_glib_ptr_borrow_mut<'a>(ptr: *mut *mut $ffi_name) -> &'a mut Self { + &mut *(ptr as *mut Self) + } + } + + impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::clone::Clone for $name $(<$($generic),+>)? { + #[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::types::StaticType for $name $(<$($generic),+>)? { + #[inline] + fn static_type() -> $crate::types::Type { + #[allow(unused_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 { + debug_assert_eq!(std::mem::size_of::(), std::mem::size_of::<$crate::ffi::gpointer>()); + let value = &*(value as *const $crate::Value as *const $crate::gobject_ffi::GValue); + debug_assert!(!value.data[0].v_pointer.is_null()); + <$name $(<$($generic),+>)?>::from_glib_ptr_borrow(&value.data[0].v_pointer as *const $crate::ffi::gpointer as *const *const $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::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::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<$ffi_name> for $name $(<$($generic),+>)? { + #[inline] + unsafe fn copy($copy_arg: *const $ffi_name) -> *mut $ffi_name { + $copy_expr + } + + #[inline] + #[allow(clippy::no_effect)] + unsafe fn free($free_arg: *mut $ffi_name) { + $free_expr; + } + } + }; +} + +// The safety docs really belong in the wrapper!() macro for Boxed +/// Memory management functions for a boxed type. +pub trait BoxedMemoryManager: 'static { + /// Makes a copy. + unsafe fn copy(ptr: *const T) -> *mut T; + /// Frees the object. + unsafe fn free(ptr: *mut T); +} + +/// 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 + } + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/boxed_any_object.rs b/walletapp/vendor/glib-0.18.5-btc09/src/boxed_any_object.rs new file mode 100644 index 0000000..ef7db2d --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/boxed_any_object.rs @@ -0,0 +1,191 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{ + any::Any, + cell::{Ref, RefMut}, +}; + +use crate as glib; +use crate::{subclass::prelude::*, Object}; + +#[derive(thiserror::Error, Debug)] +pub enum BorrowError { + #[error("type of the inner value is not as requested")] + InvalidType, + #[error("value is already mutably borrowed")] + AlreadyBorrowed(#[from] std::cell::BorrowError), +} +#[derive(thiserror::Error, Debug)] +pub enum BorrowMutError { + #[error("type of the inner value is not as requested")] + InvalidType, + #[error("value is already immutably borrowed")] + AlreadyMutBorrowed(#[from] std::cell::BorrowMutError), +} + +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"; + 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. + 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). + 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). + 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") + }) + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/boxed_inline.rs b/walletapp/vendor/glib-0.18.5-btc09/src/boxed_inline.rs new file mode 100644 index 0000000..6cae416 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/boxed_inline.rs @@ -0,0 +1,643 @@ +// 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])* + #[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),+>)? { + #[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])* + #[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),+>)? { + #[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])* + #[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),+>)? { + #[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])* + #[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),+>)? { + #[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 { + &*(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 { + &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::types::StaticType for $name $(<$($generic),+>)? { + #[inline] + fn static_type() -> $crate::types::Type { + #[allow(unused_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::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) + } + } + }; +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/bridged_logging.rs b/walletapp/vendor/glib-0.18.5-btc09/src/bridged_logging.rs new file mode 100644 index 0000000..4573c83 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/bridged_logging.rs @@ -0,0 +1,385 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use crate::{log as glib_log, translate::*}; + +// 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, + ) { + let line = line.map(|l| l.to_string()); + let line = line.as_deref(); + + crate::log_structured!( + domain.unwrap_or("default"), + GlibLogger::level_to_glib(level), + { + "CODE_FILE" => file.unwrap_or(""); + "CODE_LINE" => line.unwrap_or(""); + "CODE_FUNC" => func.unwrap_or(""); + "MESSAGE" => message; + } + ); + } +} + +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(); + if let Some(s) = args.as_str() { + GlibLogger::write_log_structured( + domain, + record.level(), + record.file(), + record.line(), + record.module_path(), + s, + ); + } else { + GlibLogger::write_log_structured( + domain, + record.level(), + record.file(), + record.line(), + record.module_path(), + &args.to_string(), + ); + } + } + }; + } + + 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)+); + ) +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/byte_array.rs b/walletapp/vendor/glib-0.18.5-btc09/src/byte_array.rs new file mode 100644 index 0000000..4c07547 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/byte_array.rs @@ -0,0 +1,160 @@ +// 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::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)); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/bytes.rs b/walletapp/vendor/glib-0.18.5-btc09/src/bytes.rs new file mode 100644 index 0000000..8f02125 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/bytes.rs @@ -0,0 +1,277 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{ + borrow::Borrow, + cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}, + fmt, + hash::{Hash, Hasher}, + ops::Deref, + slice, +}; + +use crate::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. + pub fn from_owned + Send + 'static>(data: T) -> Bytes { + let data: Box = Box::new(data); + let (size, data_ptr) = { + let data = (*data).as_ref(); + (data.len(), data.as_ptr()) + }; + + unsafe extern "C" fn drop_box + Send + 'static>(b: ffi::gpointer) { + let _: Box = Box::from_raw(b as *mut _); + } + + unsafe { + from_glib_full(ffi::g_bytes_new_with_free_func( + data_ptr as *const _, + size, + Some(drop_box::), + Box::into_raw(data) as *mut _, + )) + } + } +} + +unsafe impl Send for Bytes {} +unsafe impl Sync for Bytes {} + +impl<'a, T: ?Sized + Borrow<[u8]> + 'a> From<&'a T> for Bytes { + #[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()); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/char.rs b/walletapp/vendor/glib-0.18.5-btc09/src/char.rs new file mode 100644 index 0000000..5bc46db --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/char.rs @@ -0,0 +1,220 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{convert::TryFrom, 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) }); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/checksum.rs b/walletapp/vendor/glib-0.18.5-btc09/src/checksum.rs new file mode 100644 index 0000000..02f681f --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/checksum.rs @@ -0,0 +1,74 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::vec::Vec; + +use libc::size_t; + +use crate::{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); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/clone.rs b/walletapp/vendor/glib-0.18.5-btc09/src/clone.rs new file mode 100644 index 0000000..598ca8b --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/clone.rs @@ -0,0 +1,101 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +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; + + // 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() + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/closure.rs b/walletapp/vendor/glib-0.18.5-btc09/src/closure.rs new file mode 100644 index 0000000..789cbd0 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/closure.rs @@ -0,0 +1,447 @@ +// 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::{prelude::*, translate::*, value::FromValue, 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 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); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/collections/list.rs b/walletapp/vendor/glib-0.18.5-btc09/src/collections/list.rs new file mode 100644 index 0000000..71bf92b --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/collections/list.rs @@ -0,0 +1,894 @@ +// 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::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 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<'a, T: TransparentPtrType> FusedIterator for Iter<'a, 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<'a, T: TransparentPtrType> FusedIterator for IterMut<'a, 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); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/collections/mod.rs b/walletapp/vendor/glib-0.18.5-btc09/src/collections/mod.rs new file mode 100644 index 0000000..9f775cd --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/collections/mod.rs @@ -0,0 +1,16 @@ +// 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; diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/collections/ptr_slice.rs b/walletapp/vendor/glib-0.18.5-btc09/src/collections/ptr_slice.rs new file mode 100644 index 0000000..e925d98 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/collections/ptr_slice.rs @@ -0,0 +1,1371 @@ +// 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::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`] +/// 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 { + 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; + 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<'a, T: TransparentPtrType> IntoPtrSlice for &'a 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<'a, T: TransparentPtrType> IntoPtrSlice for &'a [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() + ); + } + }); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/collections/slice.rs b/walletapp/vendor/glib-0.18.5-btc09/src/collections/slice.rs new file mode 100644 index 0000000..82ef541 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/collections/slice.rs @@ -0,0 +1,991 @@ +// 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::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!(!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!(!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!(!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!(!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 { + 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); + } + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/collections/slist.rs b/walletapp/vendor/glib-0.18.5-btc09/src/collections/slist.rs new file mode 100644 index 0000000..70f013b --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/collections/slist.rs @@ -0,0 +1,887 @@ +// 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::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 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<'a, T: TransparentPtrType> FusedIterator for Iter<'a, 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<'a, T: TransparentPtrType> FusedIterator for IterMut<'a, 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); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/collections/strv.rs b/walletapp/vendor/glib-0.18.5-btc09/src/collections/strv.rs new file mode 100644 index 0000000..85b288e --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/collections/strv.rs @@ -0,0 +1,1544 @@ +// 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::{translate::*, GStr, GString, GStringPtr, IntoGStr, IntoOptionalGStr}; + +// 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<'a> PartialEq<[&'a str]> for StrV { + fn eq(&self, other: &[&'a str]) -> bool { + for (a, b) in Iterator::zip(self.iter(), other.iter()) { + if a != b { + return false; + } + } + + true + } +} + +impl<'a> PartialEq for [&'a 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<'a> From> for StrV { + #[inline] + fn from(value: Vec<&'a 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<'a, const N: usize> From<[&'a str; N]> for StrV { + #[inline] + fn from(value: [&'a 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<'a, const N: usize> From<[&'a GStr; N]> for StrV { + #[inline] + fn from(value: [&'a 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<'a> From<&'a [&'a str]> for StrV { + #[inline] + fn from(value: &'a [&'a 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<'a> From<&'a [&'a GStr]> for StrV { + #[inline] + fn from(value: &'a [&'a 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; + 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 crate::StaticType for StrV { + #[inline] + fn static_type() -> crate::Type { + >::static_type() + } +} + +impl<'a> crate::StaticType for &'a [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<'a> IntoStrV for &'a 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<'a> IntoStrV for Vec<&'a GString> { + #[inline] + fn run_with_strv R>(self, f: F) -> R { + self.as_slice().run_with_strv(f) + } +} + +impl<'a> IntoStrV for Vec<&'a GStr> { + #[inline] + fn run_with_strv R>(self, f: F) -> R { + self.as_slice().run_with_strv(f) + } +} + +impl<'a> IntoStrV for Vec<&'a 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<'a> IntoStrV for Vec<&'a 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<'a> IntoStrV for &[&'a 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<'a> IntoStrV for &[&'a 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<'a> IntoStrV for &[&'a 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<'a> IntoStrV for &[&'a 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<'a, const N: usize> IntoStrV for [&'a GString; N] { + #[inline] + fn run_with_strv R>(self, f: F) -> R { + self.as_slice().run_with_strv(f) + } +} + +impl<'a, const N: usize> IntoStrV for [&'a GStr; N] { + #[inline] + fn run_with_strv R>(self, f: F) -> R { + self.as_slice().run_with_strv(f) + } +} + +impl<'a, const N: usize> IntoStrV for [&'a 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<'a, const N: usize> IntoStrV for [&'a 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.get_unchecked(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.get_unchecked(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.get_unchecked(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.get_unchecked(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.get_unchecked(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")); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/control_flow.rs b/walletapp/vendor/glib-0.18.5-btc09/src/control_flow.rs new file mode 100644 index 0000000..6888d62 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/control_flow.rs @@ -0,0 +1,103 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use crate::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. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ControlFlow { + Continue, + 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::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() + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/convert.rs b/walletapp/vendor/glib-0.18.5-btc09/src/convert.rs new file mode 100644 index 0000000..94e769d --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/convert.rs @@ -0,0 +1,448 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{io, os::raw::c_char, path::PathBuf, ptr}; + +use crate::{ + translate::*, ConvertError, Error, GString, IntoGStr, IntoOptionalGStr, NormalizeMode, Slice, +}; + +// rustdoc-stripper-ignore-next +/// A wrapper for [`ConvertError`](crate::ConvertError) that can hold an offset into the input +/// string. +#[derive(thiserror::Error, Debug)] +pub enum CvtError { + #[error(transparent)] + Convert(#[from] Error), + #[error("{source} at offset {offset}")] + IllegalSequence { + #[source] + source: Error, + offset: usize, + }, +} + +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(thiserror::Error, Debug)] +pub enum IConvError { + #[error(transparent)] + Error(#[from] io::Error), + #[error("{source} at offset {offset}")] + WithOffset { + #[source] + source: io::Error, + offset: usize, + }, +} + +#[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(), &['🤔', ' ', 'ț']); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/date.rs b/walletapp/vendor/glib-0.18.5-btc09/src/date.rs new file mode 100644 index 0000000..60a90ef --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/date.rs @@ -0,0 +1,443 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{cmp, fmt, hash}; + +use crate::{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_: u32) -> 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); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/date_time.rs b/walletapp/vendor/glib-0.18.5-btc09/src/date_time.rs new file mode 100644 index 0000000..912c915 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/date_time.rs @@ -0,0 +1,15 @@ +// 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()); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/enums.rs b/walletapp/vendor/glib-0.18.5-btc09/src/enums.rs new file mode 100644 index 0000000..2c59236 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/enums.rs @@ -0,0 +1,966 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{cmp, ffi::CStr, fmt, ptr}; + +use crate::{ + translate::*, + value::{FromValue, ValueTypeChecker}, + HasParamSpec, ParamSpecEnum, ParamSpecFlags, StaticType, Type, 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)) + } +} + +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")] +#[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 + /// 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()) + } +} + +unsafe impl<'a, 'b> FromValue<'a> for &'b 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) + } +} + +pub struct EnumTypeChecker(); +unsafe impl 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)) + } +} + +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")] +#[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 + /// 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 {} + +// 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<'a> FlagsBuilder<'a> { + 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, 'b> FromValue<'a> for Vec<&'b 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 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 {} + +#[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()); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/error.rs b/walletapp/vendor/glib-0.18.5-btc09/src/error.rs new file mode 100644 index 0000000..255aa2e --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/error.rs @@ -0,0 +1,325 @@ +// 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::{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( +// Plain strings + ($msg:expr) => {{ + $crate::BoolError::new( + $msg, + file!(), + $crate::function_name!(), + line!(), + ) + }}; + +// Format strings + ($($msg:tt)*) => {{ + $crate::BoolError::new( + format!($($msg)*), + file!(), + $crate::function_name!(), + line!(), + ) + }}; +); + +#[macro_export] +macro_rules! result_from_gboolean( +// Plain strings + ($ffi_bool:expr, $msg:expr) => {{ + $crate::BoolError::from_glib( + $ffi_bool, + $msg, + file!(), + $crate::function_name!(), + line!(), + ) + }}; + +// Format strings + ($ffi_bool:expr, $($msg:tt)*) => {{ + $crate::BoolError::from_glib( + $ffi_bool, + format!($($msg)*), + 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 { 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); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/exit_code.rs b/walletapp/vendor/glib-0.18.5-btc09/src/exit_code.rs new file mode 100644 index 0000000..4a275c9 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/exit_code.rs @@ -0,0 +1,33 @@ +// 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) + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/future_with_timeout.rs b/walletapp/vendor/glib-0.18.5-btc09/src/future_with_timeout.rs new file mode 100644 index 0000000..92cf50f --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/future_with_timeout.rs @@ -0,0 +1,103 @@ +// 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(); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/binding.rs b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/binding.rs new file mode 100644 index 0000000..af6bcaf --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/binding.rs @@ -0,0 +1,59 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files (https://github.com/gtk-rs/gir-files) +// DO NOT EDIT + +use crate::{translate::*, BindingFlags}; +use std::fmt; + +crate::wrapper! { + #[doc(alias = "GBinding")] + pub struct Binding(Object); + + match fn { + type_ => || gobject_ffi::g_binding_get_type(), + } +} + +impl Binding { + #[doc(alias = "g_binding_get_flags")] + #[doc(alias = "get_flags")] + pub fn flags(&self) -> BindingFlags { + unsafe { from_glib(gobject_ffi::g_binding_get_flags(self.to_glib_none().0)) } + } + + #[doc(alias = "g_binding_get_source_property")] + #[doc(alias = "get_source_property")] + pub fn source_property(&self) -> crate::GString { + unsafe { + from_glib_none(gobject_ffi::g_binding_get_source_property( + self.to_glib_none().0, + )) + } + } + + #[doc(alias = "g_binding_get_target_property")] + #[doc(alias = "get_target_property")] + pub fn target_property(&self) -> crate::GString { + unsafe { + from_glib_none(gobject_ffi::g_binding_get_target_property( + self.to_glib_none().0, + )) + } + } + + #[doc(alias = "g_binding_unbind")] + pub fn unbind(&self) { + unsafe { + gobject_ffi::g_binding_unbind(self.to_glib_none().0); + } + } +} + +unsafe impl Send for Binding {} +unsafe impl Sync for Binding {} + +impl fmt::Display for Binding { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("Binding") + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/binding_group.rs b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/binding_group.rs new file mode 100644 index 0000000..72137e5 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/binding_group.rs @@ -0,0 +1,94 @@ +// 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::{ + prelude::*, + signal::{connect_raw, SignalHandlerId}, + translate::*, + Object, +}; +use std::{boxed::Box as Box_, fmt, mem::transmute}; + +crate::wrapper! { + #[doc(alias = "GBindingGroup")] + pub struct BindingGroup(Object); + + match fn { + type_ => || gobject_ffi::g_binding_group_get_type(), + } +} + +impl BindingGroup { + #[doc(alias = "g_binding_group_new")] + pub fn new() -> BindingGroup { + unsafe { from_glib_full(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(gobject_ffi::g_binding_group_dup_source( + self.to_glib_none().0, + )) + } + } + + #[doc(alias = "g_binding_group_set_source")] + pub fn set_source(&self, source: Option<&impl IsA>) { + unsafe { + 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(transmute::<_, 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 {} + +impl fmt::Display for BindingGroup { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("BindingGroup") + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/flags.rs b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/flags.rs new file mode 100644 index 0000000..22ea9c1 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/flags.rs @@ -0,0 +1,152 @@ +// 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, prelude::*, translate::*}; +use std::fmt; + +bitflags! { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + #[doc(alias = "GBindingFlags")] + pub struct BindingFlags: u32 { + #[doc(alias = "G_BINDING_DEFAULT")] + const DEFAULT = gobject_ffi::G_BINDING_DEFAULT as _; + #[doc(alias = "G_BINDING_BIDIRECTIONAL")] + const BIDIRECTIONAL = gobject_ffi::G_BINDING_BIDIRECTIONAL as _; + #[doc(alias = "G_BINDING_SYNC_CREATE")] + const SYNC_CREATE = gobject_ffi::G_BINDING_SYNC_CREATE as _; + #[doc(alias = "G_BINDING_INVERT_BOOLEAN")] + const INVERT_BOOLEAN = gobject_ffi::G_BINDING_INVERT_BOOLEAN as _; + } +} + +impl fmt::Display for BindingFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(self, f) + } +} + +#[doc(hidden)] +impl IntoGlib for BindingFlags { + type GlibType = gobject_ffi::GBindingFlags; + + #[inline] + fn into_glib(self) -> gobject_ffi::GBindingFlags { + self.bits() + } +} + +#[doc(hidden)] +impl FromGlib for BindingFlags { + #[inline] + unsafe fn from_glib(value: 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(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 = gobject_ffi::G_SIGNAL_RUN_FIRST as _; + #[doc(alias = "G_SIGNAL_RUN_LAST")] + const RUN_LAST = gobject_ffi::G_SIGNAL_RUN_LAST as _; + #[doc(alias = "G_SIGNAL_RUN_CLEANUP")] + const RUN_CLEANUP = gobject_ffi::G_SIGNAL_RUN_CLEANUP as _; + #[doc(alias = "G_SIGNAL_NO_RECURSE")] + const NO_RECURSE = gobject_ffi::G_SIGNAL_NO_RECURSE as _; + #[doc(alias = "G_SIGNAL_DETAILED")] + const DETAILED = gobject_ffi::G_SIGNAL_DETAILED as _; + #[doc(alias = "G_SIGNAL_ACTION")] + const ACTION = gobject_ffi::G_SIGNAL_ACTION as _; + #[doc(alias = "G_SIGNAL_NO_HOOKS")] + const NO_HOOKS = gobject_ffi::G_SIGNAL_NO_HOOKS as _; + #[doc(alias = "G_SIGNAL_MUST_COLLECT")] + const MUST_COLLECT = gobject_ffi::G_SIGNAL_MUST_COLLECT as _; + #[doc(alias = "G_SIGNAL_DEPRECATED")] + const DEPRECATED = gobject_ffi::G_SIGNAL_DEPRECATED as _; + #[doc(alias = "G_SIGNAL_ACCUMULATOR_FIRST_RUN")] + const ACCUMULATOR_FIRST_RUN = gobject_ffi::G_SIGNAL_ACCUMULATOR_FIRST_RUN as _; + } +} + +impl fmt::Display for SignalFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(self, f) + } +} + +#[doc(hidden)] +impl IntoGlib for SignalFlags { + type GlibType = gobject_ffi::GSignalFlags; + + #[inline] + fn into_glib(self) -> gobject_ffi::GSignalFlags { + self.bits() + } +} + +#[doc(hidden)] +impl FromGlib for SignalFlags { + #[inline] + unsafe fn from_glib(value: gobject_ffi::GSignalFlags) -> Self { + Self::from_bits_truncate(value) + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/mod.rs b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/mod.rs new file mode 100644 index 0000000..dbd122a --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/mod.rs @@ -0,0 +1,24 @@ +// 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; diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/signal_group.rs b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/signal_group.rs new file mode 100644 index 0000000..1a8a370 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/auto/signal_group.rs @@ -0,0 +1,73 @@ +// 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::{prelude::*, translate::*, Object}; +use std::fmt; + +crate::wrapper! { + #[doc(alias = "GSignalGroup")] + pub struct SignalGroup(Object); + + match fn { + type_ => || 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(gobject_ffi::g_signal_group_new(target_type.into_glib())) } + } + + #[doc(alias = "g_signal_group_block")] + pub fn block(&self) { + unsafe { + 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(gobject_ffi::g_signal_group_dup_target( + self.to_glib_none().0, + )) + } + } + + #[doc(alias = "g_signal_group_set_target")] + pub fn set_target(&self, target: Option<&impl IsA>) { + unsafe { + 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 { + 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 {} + +impl fmt::Display for SignalGroup { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("SignalGroup") + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/gobject/binding.rs b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/binding.rs new file mode 100644 index 0000000..01c0b8f --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/binding.rs @@ -0,0 +1,307 @@ +// 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; + + use once_cell::sync::Lazy; + + 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: Lazy> = Lazy::new(|| { + vec![ + crate::ParamSpecString::builder("name") + .explicit_notify() + .build(), + crate::ParamSpecBoolean::builder("enabled") + .explicit_notify() + .build(), + ] + }); + PROPERTIES.as_ref() + } + + 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"); + } + } + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/gobject/binding_group.rs b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/binding_group.rs new file mode 100644 index 0000000..78cba7d --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/binding_group.rs @@ -0,0 +1,507 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{fmt, ptr}; + +use crate::{ + 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<'a> fmt::Debug for BindingGroupBuilder<'a> { + 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_propery_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-termianted from the C side + source_property.name().as_ptr() + } else { + // This is a Rust &str and needs to be NUL-terminated first + let source_propery_name = std::ffi::CString::new(self.source_property).unwrap(); + let source_property_name_ptr = source_propery_name.as_ptr() as *const u8; + _source_propery_name_cstr = Some(source_propery_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; + + use once_cell::sync::Lazy; + + 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: Lazy> = Lazy::new(|| { + vec![ + crate::ParamSpecString::builder("name") + .explicit_notify() + .build(), + crate::ParamSpecBoolean::builder("enabled") + .explicit_notify() + .build(), + ] + }); + PROPERTIES.as_ref() + } + + 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"); + } + } + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/gobject/flags.rs b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/flags.rs new file mode 100644 index 0000000..a2f4c95 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/flags.rs @@ -0,0 +1,59 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use crate::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) + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/gobject/mod.rs b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/mod.rs new file mode 100644 index 0000000..274451c --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/mod.rs @@ -0,0 +1,22 @@ +// 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::*; diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/gobject/signal_group.rs b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/signal_group.rs new file mode 100644 index 0000000..f9fb063 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/gobject/signal_group.rs @@ -0,0 +1,248 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::mem::transmute; + +use crate::{ + signal::{connect_raw, SignalHandlerId}, + translate::*, + IsA, Object, ObjectType, 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::<_, 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::<_, 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}; + + use super::*; + use crate as glib; + use crate::{ObjectExt, StaticType}; + + 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] { + use once_cell::sync::Lazy; + static SIGNALS: Lazy> = Lazy::new(|| { + vec![ + Signal::builder("sig-with-args") + .param_types([u32::static_type(), String::static_type()]) + .build(), + Signal::builder("sig-with-ret") + .return_type::() + .build(), + ] + }); + SIGNALS.as_ref() + } + } + } + + 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); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/gstring.rs b/walletapp/vendor/glib-0.18.5-btc09/src/gstring.rs new file mode 100644 index 0000000..1d1bc95 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/gstring.rs @@ -0,0 +1,2547 @@ +// 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::{prelude::*, translate::*, value::FromValue, 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(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(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(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(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(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(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(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(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`](CStr::from_ptr#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::to_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(thiserror::Error, Debug)] +pub enum GStrError { + #[error(transparent)] + InvalidUtf8(#[from] std::str::Utf8Error), + #[error(transparent)] + InteriorNul(#[from] GStrInteriorNulError), + #[error("data provided is not nul terminated")] + NoTrailingNul, +} + +// rustdoc-stripper-ignore-next +/// Error type indicating that a buffer had unexpected nul-bytes. +#[derive(thiserror::Error, Copy, Clone, PartialEq, Eq, Debug)] +#[error("data provided contains an interior nul-byte at byte pos {0}")] +pub struct GStrInteriorNulError(usize); + +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> 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`]. +/// +/// Unlike [`&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`]. + #[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`]. + #[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!`] 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(thiserror::Error, Clone, PartialEq, Eq, Debug)] +#[error("data provided is not nul terminated")] +pub struct GStringNoTrailingNulError(T); + +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(thiserror::Error, Clone, PartialEq, Eq, Debug)] +#[error("{1}")] +pub struct GStringInteriorNulError(T, GStrInteriorNulError); + +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(thiserror::Error, Clone, PartialEq, Eq, Debug)] +#[error("{1}")] +pub struct GStringUtf8Error(T, std::str::Utf8Error); + +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(thiserror::Error, Debug)] +pub enum GStringFromError { + #[error(transparent)] + NoTrailingNul(#[from] GStringNoTrailingNulError), + #[error(transparent)] + InteriorNul(#[from] GStringInteriorNulError), + #[error(transparent)] + InvalidUtf8(#[from] GStringUtf8Error), + #[error("unable to convert")] + Unspecified(T), +} + +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<'a> From for Cow<'a, 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> 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::()); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/gstring_builder.rs b/walletapp/vendor/glib-0.18.5-btc09/src/gstring_builder.rs new file mode 100644 index 0000000..e08618d --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/gstring_builder.rs @@ -0,0 +1,367 @@ +// 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::{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`]. + #[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"); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/key_file.rs b/walletapp/vendor/glib-0.18.5-btc09/src/key_file.rs new file mode 100644 index 0000000..54c9eb1 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/key_file.rs @@ -0,0 +1,282 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{mem, path, ptr}; + +use crate::{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)) + } + } + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/lib.rs b/walletapp/vendor/glib-0.18.5-btc09/src/lib.rs new file mode 100644 index 0000000..af61bcb --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/lib.rs @@ -0,0 +1,231 @@ +// 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(renamed_and_removed_lints)] +#![doc = include_str!("../README.md")] + +pub use bitflags; +pub use ffi; +#[doc(hidden)] +pub use glib_macros::cstr_bytes; +pub use glib_macros::{ + clone, closure, closure_local, derived_properties, flags, object_interface, object_subclass, + Boxed, Downgrade, Enum, ErrorDomain, Properties, SharedBoxed, ValueDelegate, Variant, +}; +pub use gobject_ffi; +pub use once_cell; + +pub use self::{ + byte_array::ByteArray, + bytes::Bytes, + closure::{Closure, RustClosure}, + enums::{EnumClass, EnumValue, FlagsBuilder, FlagsClass, FlagsValue, UserDirectory}, + error::{BoolError, Error}, + object::{ + BorrowedObject, Cast, CastNone, Class, InitiallyUnowned, Interface, IsA, Object, ObjectExt, + ObjectType, SendWeakRef, WeakRef, + }, + signal::{ + signal_handler_block, signal_handler_disconnect, signal_handler_unblock, + signal_stop_emission_by_name, Propagation, SignalHandlerId, + }, + types::{ILong, Pointer, StaticType, StaticTypeExt, Type, ULong}, + value::{BoxedValue, SendValue, ToSendValue, ToValue, Value}, + variant::{ + FixedSizeVariantArray, FixedSizeVariantType, FromVariant, StaticVariantType, ToVariant, + 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::{ + ptr_slice::IntoPtrSlice, strv::IntoStrV, List, PtrSlice, SList, Slice, StrV, +}; + +pub use self::auto::{functions::*, *}; +#[allow(clippy::too_many_arguments)] +#[allow(clippy::type_complexity)] +#[allow(unused_imports)] +#[allow(non_upper_case_globals)] +mod auto; + +pub use self::gobject::*; +mod gobject; + +mod byte_array; +mod bytes; +mod control_flow; +pub use self::control_flow::ControlFlow; +pub mod char; +pub use self::char::*; +mod checksum; +pub mod closure; +mod convert; +pub use self::convert::*; +mod enums; +mod manual_functions; +pub use self::manual_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; +mod main_context_channel; +pub use self::{ + main_context::MainContextAcquireGuard, + main_context_channel::{Receiver, Sender, SyncSender}, +}; +mod date; +mod date_time; +mod time_span; +mod time_zone; +pub use self::time_span::*; +pub mod value; +pub mod variant; +mod variant_dict; +mod variant_iter; +mod variant_type; +pub use self::date::Date; +mod value_array; +pub use self::value_array::ValueArray; +mod param_spec; +pub use self::param_spec::*; +mod property; +pub use self::property::*; +mod quark; +pub use self::quark::Quark; +#[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::*; diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/log.rs b/walletapp/vendor/glib-0.18.5-btc09/src/log.rs new file mode 100644 index 0000000..276d736 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/log.rs @@ -0,0 +1,1069 @@ +// 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}, +}; + +use once_cell::sync::Lazy; + +use crate::{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; + +static PRINT_HANDLER: Lazy>>> = Lazy::new(|| 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) }; +} + +static PRINTERR_HANDLER: Lazy>>> = Lazy::new(|| 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; + +static DEFAULT_HANDLER: Lazy>>> = Lazy::new(|| 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 retreived 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 + /// Retreives 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: once_cell::sync::OnceCell> = + once_cell::sync::OnceCell::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!`] 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!`] 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!`] 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!`] 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!`] 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!`] 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, + )) + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/main_context.rs b/walletapp/vendor/glib-0.18.5-btc09/src/main_context.rs new file mode 100644 index 0000000..3500099 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/main_context.rs @@ -0,0 +1,279 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::mem; + +use 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(&self, func: F) -> Result + where + F: FnOnce() -> R, + { + 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<'a> Drop for MainContextAcquireGuard<'a> { + #[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<'a> ThreadDefaultContext<'a> { + fn new(ctx: &MainContext) -> ThreadDefaultContext { + unsafe { + ffi::g_main_context_push_thread_default(ctx.to_glib_none().0); + } + ThreadDefaultContext(ctx) + } +} + +impl<'a> Drop for ThreadDefaultContext<'a> { + #[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(); + thread::spawn(move || { + c.invoke(move || l_clone.quit()); + }); + + l.run(); + } + + fn is_same_context(a: &MainContext, b: &MainContext) -> bool { + ptr::eq(a.to_glib_none().0, b.to_glib_none().0) + } + + #[test] + fn test_with_thread_default() { + let a = MainContext::new(); + let b = MainContext::new(); + + assert!(!is_same_context(&a, &b)); + + a.with_thread_default(|| { + let t = MainContext::thread_default().unwrap(); + assert!(is_same_context(&a, &t)); + + b.with_thread_default(|| { + let t = MainContext::thread_default().unwrap(); + assert!(is_same_context(&b, &t)); + }) + .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(); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/main_context_channel.rs b/walletapp/vendor/glib-0.18.5-btc09/src/main_context_channel.rs new file mode 100644 index 0000000..a3da242 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/main_context_channel.rs @@ -0,0 +1,896 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{ + collections::VecDeque, + fmt, mem, ptr, + sync::{mpsc, Arc, Condvar, Mutex}, +}; + +use crate::{ + thread_guard::ThreadGuard, translate::*, ControlFlow, MainContext, Priority, Source, SourceId, +}; + +enum ChannelSourceState { + NotAttached, + Attached(*mut ffi::GSource), + Destroyed, +} + +unsafe impl Send for ChannelSourceState {} +unsafe impl Sync for ChannelSourceState {} + +struct ChannelInner { + queue: VecDeque, + source: ChannelSourceState, + num_senders: usize, +} + +impl ChannelInner { + fn receiver_disconnected(&self) -> bool { + match self.source { + ChannelSourceState::Destroyed => true, + // Receiver exists but is already destroyed + ChannelSourceState::Attached(source) + if unsafe { ffi::g_source_is_destroyed(source) } != ffi::GFALSE => + { + true + } + // Not attached yet so the Receiver still exists + ChannelSourceState::NotAttached => false, + // Receiver still running + ChannelSourceState::Attached(_) => false, + } + } + + #[doc(alias = "g_source_set_ready_time")] + fn set_ready_time(&mut self, ready_time: i64) { + if let ChannelSourceState::Attached(source) = self.source { + unsafe { + ffi::g_source_set_ready_time(source, ready_time); + } + } + } +} + +struct ChannelBound { + bound: usize, + cond: Condvar, +} + +struct Channel(Arc<(Mutex>, Option)>); + +impl Clone for Channel { + fn clone(&self) -> Channel { + Channel(self.0.clone()) + } +} + +impl Channel { + fn new(bound: Option) -> Channel { + Channel(Arc::new(( + Mutex::new(ChannelInner { + queue: VecDeque::new(), + source: ChannelSourceState::NotAttached, + num_senders: 0, + }), + bound.map(|bound| ChannelBound { + bound, + cond: Condvar::new(), + }), + ))) + } + + fn send(&self, t: T) -> Result<(), mpsc::SendError> { + let mut inner = (self.0).0.lock().unwrap(); + + // If we have a bounded channel then we need to wait here until enough free space is + // available or the receiver disappears + // + // A special case here is a bound of 0: the queue must be empty for accepting + // new data and then we will again wait later for the data to be actually taken + // out + if let Some(ChannelBound { bound, ref cond }) = (self.0).1 { + while inner.queue.len() >= bound + && !inner.queue.is_empty() + && !inner.receiver_disconnected() + { + inner = cond.wait(inner).unwrap(); + } + } + + // Error out directly if the receiver is disconnected + if inner.receiver_disconnected() { + return Err(mpsc::SendError(t)); + } + + // Store the item on our queue + inner.queue.push_back(t); + + // and then wake up the GSource + inner.set_ready_time(0); + + // If we have a bound of 0 we need to wait until the receiver actually + // handled the data + if let Some(ChannelBound { bound: 0, ref cond }) = (self.0).1 { + while !inner.queue.is_empty() && !inner.receiver_disconnected() { + inner = cond.wait(inner).unwrap(); + } + + // If the receiver was destroyed in the meantime take out the item and report an error + if inner.receiver_disconnected() { + // If the item is not in the queue anymore then the receiver just handled it before + // getting disconnected and all is good + if let Some(t) = inner.queue.pop_front() { + return Err(mpsc::SendError(t)); + } + } + } + + Ok(()) + } + + fn try_send(&self, t: T) -> Result<(), mpsc::TrySendError> { + let mut inner = (self.0).0.lock().unwrap(); + + let ChannelBound { bound, ref cond } = (self.0) + .1 + .as_ref() + .expect("called try_send() on an unbounded channel"); + + // Check if the queue is full and handle the special case of a 0 bound + if inner.queue.len() >= *bound && !inner.queue.is_empty() { + return Err(mpsc::TrySendError::Full(t)); + } + + // Error out directly if the receiver is disconnected + if inner.receiver_disconnected() { + return Err(mpsc::TrySendError::Disconnected(t)); + } + + // Store the item on our queue + inner.queue.push_back(t); + + // and then wake up the GSource + inner.set_ready_time(0); + + // If we have a bound of 0 we need to wait until the receiver actually + // handled the data + if *bound == 0 { + while !inner.queue.is_empty() && !inner.receiver_disconnected() { + inner = cond.wait(inner).unwrap(); + } + + // If the receiver was destroyed in the meantime take out the item and report an error + if inner.receiver_disconnected() { + // If the item is not in the queue anymore then the receiver just handled it before + // getting disconnected and all is good + if let Some(t) = inner.queue.pop_front() { + return Err(mpsc::TrySendError::Disconnected(t)); + } + } + } + + Ok(()) + } + + // SAFETY: Must be called from the main context the channel was attached to. + unsafe fn try_recv(&self) -> Result { + let mut inner = (self.0).0.lock().unwrap(); + + // Pop item if we have any + if let Some(item) = inner.queue.pop_front() { + // Wake up a sender that is currently waiting, if any + if let Some(ChannelBound { ref cond, .. }) = (self.0).1 { + cond.notify_one(); + } + return Ok(item); + } + + // If there are no senders left we are disconnected or otherwise empty. That's the case if + // the only remaining strong reference is the one of the receiver + if inner.num_senders == 0 { + Err(mpsc::TryRecvError::Disconnected) + } else { + Err(mpsc::TryRecvError::Empty) + } + } +} + +#[repr(C)] +struct ChannelSource ControlFlow + 'static> { + source: ffi::GSource, + source_funcs: Box, + channel: Channel, + callback: ThreadGuard, +} + +unsafe extern "C" fn dispatch ControlFlow + 'static>( + source: *mut ffi::GSource, + callback: ffi::GSourceFunc, + _user_data: ffi::gpointer, +) -> ffi::gboolean { + let source = &mut *(source as *mut ChannelSource); + debug_assert!(callback.is_none()); + + // Set ready-time to -1 so that we won't get called again before a new item is added + // to the channel queue. + ffi::g_source_set_ready_time(&mut source.source, -1); + + // Get a reference to the callback. This will panic if we're called from a different + // thread than where the source was attached to the main context. + let callback = source.callback.get_mut(); + + // Now iterate over all items that we currently have in the channel until it is + // empty again. If all senders are disconnected at some point we remove the GSource + // from the main context it was attached to as it will never ever be called again. + loop { + match source.channel.try_recv() { + Err(mpsc::TryRecvError::Empty) => break, + Err(mpsc::TryRecvError::Disconnected) => return ffi::G_SOURCE_REMOVE, + Ok(item) => { + if callback(item).is_break() { + return ffi::G_SOURCE_REMOVE; + } + } + } + } + + ffi::G_SOURCE_CONTINUE +} + +#[cfg(feature = "v2_64")] +unsafe extern "C" fn dispose ControlFlow + 'static>(source: *mut ffi::GSource) { + let source = &mut *(source as *mut ChannelSource); + + // Set the source inside the channel to None so that all senders know that there + // is no receiver left and wake up the condition variable if any + let mut inner = (source.channel.0).0.lock().unwrap(); + inner.source = ChannelSourceState::Destroyed; + if let Some(ChannelBound { ref cond, .. }) = (source.channel.0).1 { + cond.notify_all(); + } +} + +unsafe extern "C" fn finalize ControlFlow + 'static>(source: *mut ffi::GSource) { + let source = &mut *(source as *mut ChannelSource); + + // Drop all memory we own by taking it out of the Options + + #[cfg(not(feature = "v2_64"))] + { + // FIXME: This is the same as would otherwise be done in the dispose() function but + // unfortunately it doesn't exist in older version of GLib. Doing it only here can + // cause a channel sender to get a reference to the source with reference count 0 + // if it happens just before the mutex is taken below. + // + // This is exactly the pattern why g_source_set_dispose_function() was added. + // + // Set the source inside the channel to None so that all senders know that there + // is no receiver left and wake up the condition variable if any + let mut inner = (source.channel.0).0.lock().unwrap(); + inner.source = ChannelSourceState::Destroyed; + if let Some(ChannelBound { ref cond, .. }) = (source.channel.0).1 { + cond.notify_all(); + } + } + ptr::drop_in_place(&mut source.channel); + ptr::drop_in_place(&mut source.source_funcs); + + // Take the callback out of the source. This will panic if the value is dropped + // from a different thread than where the callback was created 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 caller to `attach()` gets the `Source` from the returned + // `SourceId` and sends it to another thread or otherwise retrieves it from the main context, + // but better safe than sorry. + if source.callback.is_owner() { + ptr::drop_in_place(&mut source.callback); + } else { + let callback = ptr::read(&source.callback); + let context = + ffi::g_source_get_context(source as *mut ChannelSource as *mut ffi::GSource); + if !context.is_null() { + let context = MainContext::from_glib_none(context); + context.invoke(move || { + drop(callback); + }); + } + } +} + +// rustdoc-stripper-ignore-next +/// A `Sender` that can be used to send items to the corresponding main context receiver. +/// +/// This `Sender` behaves the same as `std::sync::mpsc::Sender`. +/// +/// See [`MainContext::channel()`] for how to create such a `Sender`. +/// +/// [`MainContext::channel()`]: struct.MainContext.html#method.channel +pub struct Sender(Channel); + +// It's safe to send the Sender to other threads for attaching it as +// long as the items to be sent can also be sent between threads. +unsafe impl Send for Sender {} + +impl fmt::Debug for Sender { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Sender").finish() + } +} + +impl Clone for Sender { + fn clone(&self) -> Sender { + Self::new(&self.0) + } +} + +impl Sender { + fn new(channel: &Channel) -> Self { + let mut inner = (channel.0).0.lock().unwrap(); + inner.num_senders += 1; + Self(channel.clone()) + } + + // rustdoc-stripper-ignore-next + /// Sends a value to the channel. + pub fn send(&self, t: T) -> Result<(), mpsc::SendError> { + self.0.send(t) + } +} + +impl Drop for Sender { + fn drop(&mut self) { + // Decrease the number of senders and wake up the channel if this + // was the last sender that was dropped. + let mut inner = ((self.0).0).0.lock().unwrap(); + inner.num_senders -= 1; + if inner.num_senders == 0 { + inner.set_ready_time(0); + } + } +} + +// rustdoc-stripper-ignore-next +/// A `SyncSender` that can be used to send items to the corresponding main context receiver. +/// +/// This `SyncSender` behaves the same as `std::sync::mpsc::SyncSender`. +/// +/// See [`MainContext::sync_channel()`] for how to create such a `SyncSender`. +/// +/// [`MainContext::sync_channel()`]: struct.MainContext.html#method.sync_channel +pub struct SyncSender(Channel); + +// It's safe to send the SyncSender to other threads for attaching it as +// long as the items to be sent can also be sent between threads. +unsafe impl Send for SyncSender {} + +impl fmt::Debug for SyncSender { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("SyncSender").finish() + } +} + +impl Clone for SyncSender { + fn clone(&self) -> SyncSender { + Self::new(&self.0) + } +} + +impl SyncSender { + fn new(channel: &Channel) -> Self { + let mut inner = (channel.0).0.lock().unwrap(); + inner.num_senders += 1; + Self(channel.clone()) + } + + // rustdoc-stripper-ignore-next + /// Sends a value to the channel and blocks if the channel is full. + pub fn send(&self, t: T) -> Result<(), mpsc::SendError> { + self.0.send(t) + } + + // rustdoc-stripper-ignore-next + /// Sends a value to the channel. + pub fn try_send(&self, t: T) -> Result<(), mpsc::TrySendError> { + self.0.try_send(t) + } +} + +impl Drop for SyncSender { + fn drop(&mut self) { + // Decrease the number of senders and wake up the channel if this + // was the last sender that was dropped. + let mut inner = ((self.0).0).0.lock().unwrap(); + inner.num_senders -= 1; + if inner.num_senders == 0 { + inner.set_ready_time(0); + } + } +} + +// rustdoc-stripper-ignore-next +/// A `Receiver` that can be attached to a main context to receive items from its corresponding +/// `Sender` or `SyncSender`. +/// +/// See [`MainContext::channel()`] or [`MainContext::sync_channel()`] for how to create +/// such a `Receiver`. +/// +/// [`MainContext::channel()`]: struct.MainContext.html#method.channel +/// [`MainContext::sync_channel()`]: struct.MainContext.html#method.sync_channel +pub struct Receiver(Option>, Priority); + +impl fmt::Debug for Receiver { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Receiver").finish() + } +} + +// It's safe to send the Receiver to other threads for attaching it as +// long as the items to be sent can also be sent between threads. +unsafe impl Send for Receiver {} + +impl Drop for Receiver { + fn drop(&mut self) { + // If the receiver was never attached to a main context we need to let all the senders know + if let Some(channel) = self.0.take() { + let mut inner = (channel.0).0.lock().unwrap(); + inner.source = ChannelSourceState::Destroyed; + if let Some(ChannelBound { ref cond, .. }) = (channel.0).1 { + cond.notify_all(); + } + } + } +} + +impl Receiver { + // rustdoc-stripper-ignore-next + /// Attaches the receiver to the given `context` and calls `func` whenever an item is + /// available on the channel. + /// + /// Passing `None` for the context will attach it to the thread default main context. + /// + /// # Panics + /// + /// This function panics if called from a thread that is not the owner of the provided + /// `context`, or, if `None` is provided, of the thread default main context. + pub fn attach ControlFlow + 'static>( + mut self, + context: Option<&MainContext>, + func: F, + ) -> SourceId { + unsafe { + let channel = self.0.take().expect("Receiver without channel"); + + let source_funcs = Box::new(ffi::GSourceFuncs { + check: None, + prepare: None, + dispatch: Some(dispatch::), + finalize: Some(finalize::), + closure_callback: None, + closure_marshal: None, + }); + + let source = ffi::g_source_new( + mut_override(&*source_funcs), + mem::size_of::>() as u32, + ) as *mut ChannelSource; + + #[cfg(feature = "v2_64")] + { + ffi::g_source_set_dispose_function( + source as *mut ffi::GSource, + Some(dispose::), + ); + } + + // Set up the GSource + { + let source = &mut *source; + let mut inner = (channel.0).0.lock().unwrap(); + + ffi::g_source_set_priority(mut_override(&source.source), self.1.into_glib()); + + // We're immediately ready if the queue is not empty or if no sender is left at this point + ffi::g_source_set_ready_time( + mut_override(&source.source), + if !inner.queue.is_empty() || inner.num_senders == 0 { + 0 + } else { + -1 + }, + ); + inner.source = ChannelSourceState::Attached(&mut source.source); + } + + // Store all our data inside our part of the GSource + { + let source = &mut *source; + ptr::write(ptr::addr_of_mut!(source.channel), channel); + ptr::write(ptr::addr_of_mut!(source.callback), ThreadGuard::new(func)); + ptr::write(ptr::addr_of_mut!(source.source_funcs), source_funcs); + } + + let source = Source::from_glib_full(mut_override(&(*source).source)); + let context = match context { + Some(context) => context.clone(), + None => MainContext::ref_thread_default(), + }; + + let _acquire = context + .acquire() + .expect("main context already acquired by another thread"); + source.attach(Some(&context)) + } + } +} + +impl MainContext { + // rustdoc-stripper-ignore-next + /// Creates a channel for a main context. + /// + /// The `Receiver` has to be attached to a main context at a later time, together with a + /// closure that will be called for every item sent to a `Sender`. + /// + /// The `Sender` can be cloned and both the `Sender` and `Receiver` can be sent to different + /// threads as long as the item type implements the `Send` trait. + /// + /// When the last `Sender` is dropped the channel is removed from the main context. If the + /// `Receiver` is dropped and not attached to a main context all sending to the `Sender` + /// will fail. + /// + /// The returned `Sender` behaves the same as `std::sync::mpsc::Sender`. + #[deprecated = "Use an async channel, from async-channel for example, on the main context using spawn_future_local() instead"] + pub fn channel(priority: Priority) -> (Sender, Receiver) { + let channel = Channel::new(None); + let receiver = Receiver(Some(channel.clone()), priority); + let sender = Sender::new(&channel); + + (sender, receiver) + } + + // rustdoc-stripper-ignore-next + /// Creates a synchronous channel for a main context with a given bound on the capacity of the + /// channel. + /// + /// The `Receiver` has to be attached to a main context at a later time, together with a + /// closure that will be called for every item sent to a `SyncSender`. + /// + /// The `SyncSender` can be cloned and both the `SyncSender` and `Receiver` can be sent to different + /// threads as long as the item type implements the `Send` trait. + /// + /// When the last `SyncSender` is dropped the channel is removed from the main context. If the + /// `Receiver` is dropped and not attached to a main context all sending to the `SyncSender` + /// will fail. + /// + /// The returned `SyncSender` behaves the same as `std::sync::mpsc::SyncSender`. + #[deprecated = "Use an async channel, from async-channel for example, on the main context using spawn_future_local() instead"] + pub fn sync_channel(priority: Priority, bound: usize) -> (SyncSender, Receiver) { + let channel = Channel::new(Some(bound)); + let receiver = Receiver(Some(channel.clone()), priority); + let sender = SyncSender::new(&channel); + + (sender, receiver) + } +} + +#[cfg(test)] +#[allow(deprecated)] +mod tests { + use std::{ + cell::RefCell, + rc::Rc, + sync::atomic::{AtomicBool, Ordering}, + thread, time, + }; + + use super::*; + use crate::MainLoop; + + #[test] + fn test_channel() { + let c = MainContext::new(); + let l = MainLoop::new(Some(&c), false); + + let _guard = c.acquire().unwrap(); + + let (sender, receiver) = MainContext::channel(Priority::default()); + + let sum = Rc::new(RefCell::new(0)); + let sum_clone = sum.clone(); + let l_clone = l.clone(); + receiver.attach(Some(&c), move |item| { + *sum_clone.borrow_mut() += item; + if *sum_clone.borrow() == 6 { + l_clone.quit(); + ControlFlow::Break + } else { + ControlFlow::Continue + } + }); + + sender.send(1).unwrap(); + sender.send(2).unwrap(); + sender.send(3).unwrap(); + + l.run(); + + assert_eq!(*sum.borrow(), 6); + } + + #[test] + fn test_drop_sender() { + let c = MainContext::new(); + let l = MainLoop::new(Some(&c), false); + + let _guard = c.acquire().unwrap(); + + let (sender, receiver) = MainContext::channel::(Priority::default()); + + struct Helper(MainLoop); + impl Drop for Helper { + fn drop(&mut self) { + self.0.quit(); + } + } + + let helper = Helper(l.clone()); + receiver.attach(Some(&c), move |_| { + let _helper = &helper; + ControlFlow::Continue + }); + + drop(sender); + + l.run(); + } + + #[test] + fn test_drop_receiver() { + let (sender, receiver) = MainContext::channel::(Priority::default()); + + drop(receiver); + assert_eq!(sender.send(1), Err(mpsc::SendError(1))); + } + + #[test] + fn test_remove_receiver() { + let c = MainContext::new(); + + let _guard = c.acquire().unwrap(); + + let (sender, receiver) = MainContext::channel::(Priority::default()); + + let source_id = receiver.attach(Some(&c), move |_| ControlFlow::Continue); + + let source = c.find_source_by_id(&source_id).unwrap(); + source.destroy(); + + assert_eq!(sender.send(1), Err(mpsc::SendError(1))); + } + + #[test] + fn test_remove_receiver_and_drop_source() { + let c = MainContext::new(); + + let _guard = c.acquire().unwrap(); + + let (sender, receiver) = MainContext::channel::(Priority::default()); + + struct Helper(Arc); + impl Drop for Helper { + fn drop(&mut self) { + self.0.store(true, Ordering::Relaxed); + } + } + + let dropped = Arc::new(AtomicBool::new(false)); + let helper = Helper(dropped.clone()); + let source_id = receiver.attach(Some(&c), move |_| { + let _helper = &helper; + ControlFlow::Continue + }); + + let source = c.find_source_by_id(&source_id).unwrap(); + source.destroy(); + + // This should drop the closure + drop(source); + + assert!(dropped.load(Ordering::Relaxed)); + assert_eq!(sender.send(1), Err(mpsc::SendError(1))); + } + + #[test] + fn test_sync_channel() { + let c = MainContext::new(); + let l = MainLoop::new(Some(&c), false); + + let _guard = c.acquire().unwrap(); + + let (sender, receiver) = MainContext::sync_channel(Priority::default(), 2); + + let sum = Rc::new(RefCell::new(0)); + let sum_clone = sum.clone(); + let l_clone = l.clone(); + receiver.attach(Some(&c), move |item| { + *sum_clone.borrow_mut() += item; + if *sum_clone.borrow() == 6 { + l_clone.quit(); + ControlFlow::Break + } else { + ControlFlow::Continue + } + }); + + let (wait_sender, wait_receiver) = mpsc::channel(); + + let thread = thread::spawn(move || { + // The first two must succeed + sender.try_send(1).unwrap(); + sender.try_send(2).unwrap(); + + // This fill up the channel + assert!(sender.try_send(3).is_err()); + wait_sender.send(()).unwrap(); + + // This will block + sender.send(3).unwrap(); + }); + + // Wait until the channel is full, and then another + // 50ms to make sure the sender is blocked now and + // can wake up properly once an item was consumed + assert!(wait_receiver.recv().is_ok()); + thread::sleep(time::Duration::from_millis(50)); + l.run(); + + thread.join().unwrap(); + + assert_eq!(*sum.borrow(), 6); + } + + #[test] + fn test_sync_channel_drop_wakeup() { + let c = MainContext::new(); + let l = MainLoop::new(Some(&c), false); + + let _guard = c.acquire().unwrap(); + + let (sender, receiver) = MainContext::sync_channel(Priority::default(), 3); + + let sum = Rc::new(RefCell::new(0)); + let sum_clone = sum.clone(); + let l_clone = l.clone(); + receiver.attach(Some(&c), move |item| { + *sum_clone.borrow_mut() += item; + if *sum_clone.borrow() == 6 { + l_clone.quit(); + ControlFlow::Break + } else { + ControlFlow::Continue + } + }); + + let (wait_sender, wait_receiver) = mpsc::channel(); + + let thread = thread::spawn(move || { + // The first three must succeed + sender.try_send(1).unwrap(); + sender.try_send(2).unwrap(); + sender.try_send(3).unwrap(); + + wait_sender.send(()).unwrap(); + for i in 4.. { + // This will block at some point until the + // receiver is removed from the main context + if sender.send(i).is_err() { + break; + } + } + }); + + // Wait until the channel is full, and then another + // 50ms to make sure the sender is blocked now and + // can wake up properly once an item was consumed + assert!(wait_receiver.recv().is_ok()); + thread::sleep(time::Duration::from_millis(50)); + l.run(); + + thread.join().unwrap(); + + assert_eq!(*sum.borrow(), 6); + } + + #[test] + fn test_sync_channel_drop_receiver_wakeup() { + let c = MainContext::new(); + + let _guard = c.acquire().unwrap(); + + let (sender, receiver) = MainContext::sync_channel(Priority::default(), 2); + + let (wait_sender, wait_receiver) = mpsc::channel(); + + let thread = thread::spawn(move || { + // The first two must succeed + sender.try_send(1).unwrap(); + sender.try_send(2).unwrap(); + wait_sender.send(()).unwrap(); + + // This will block and then error out because the receiver is destroyed + assert!(sender.send(3).is_err()); + }); + + // Wait until the channel is full, and then another + // 50ms to make sure the sender is blocked now and + // can wake up properly once an item was consumed + assert!(wait_receiver.recv().is_ok()); + thread::sleep(time::Duration::from_millis(50)); + drop(receiver); + thread.join().unwrap(); + } + + #[test] + fn test_sync_channel_rendezvous() { + let c = MainContext::new(); + let l = MainLoop::new(Some(&c), false); + + let _guard = c.acquire().unwrap(); + + let (sender, receiver) = MainContext::sync_channel(Priority::default(), 0); + + let (wait_sender, wait_receiver) = mpsc::channel(); + + let thread = thread::spawn(move || { + wait_sender.send(()).unwrap(); + sender.send(1).unwrap(); + wait_sender.send(()).unwrap(); + sender.send(2).unwrap(); + wait_sender.send(()).unwrap(); + sender.send(3).unwrap(); + wait_sender.send(()).unwrap(); + }); + + // Wait until the thread is started, then wait another 50ms and + // during that time it must not have proceeded yet to send the + // second item because we did not yet receive the first item. + assert!(wait_receiver.recv().is_ok()); + assert_eq!( + wait_receiver.recv_timeout(time::Duration::from_millis(50)), + Err(mpsc::RecvTimeoutError::Timeout) + ); + + let sum = Rc::new(RefCell::new(0)); + let sum_clone = sum.clone(); + let l_clone = l.clone(); + receiver.attach(Some(&c), move |item| { + // We consumed one item so there should be one item on + // the other receiver now. + assert!(wait_receiver.recv().is_ok()); + *sum_clone.borrow_mut() += item; + if *sum_clone.borrow() == 6 { + // But as we didn't consume the next one yet, there must be no + // other item available yet + assert_eq!( + wait_receiver.recv_timeout(time::Duration::from_millis(50)), + Err(mpsc::RecvTimeoutError::Disconnected) + ); + l_clone.quit(); + ControlFlow::Break + } else { + // But as we didn't consume the next one yet, there must be no + // other item available yet + assert_eq!( + wait_receiver.recv_timeout(time::Duration::from_millis(50)), + Err(mpsc::RecvTimeoutError::Timeout) + ); + ControlFlow::Continue + } + }); + l.run(); + + thread.join().unwrap(); + + assert_eq!(*sum.borrow(), 6); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/main_context_futures.rs b/walletapp/vendor/glib-0.18.5-btc09/src/main_context_futures.rs new file mode 100644 index 0000000..04d3e92 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/main_context_futures.rs @@ -0,0 +1,810 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{ + any::Any, cell::Cell, 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::{ + 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); + } + } + } + + // 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() + } +} + +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(thiserror::Error, Debug)] +enum JoinErrorInner { + #[error("task cancelled")] + Cancelled, + #[error("task panicked")] + Panic(Box), +} + +impl From for JoinError { + #[inline] + fn from(e: JoinErrorInner) -> Self { + Self(e) + } +} + +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(()) + }), + ); + + thread::spawn(move || { + l.run(); + }); + + o_sender.send(()).unwrap(); + + receiver.recv().unwrap(); + } + + #[test] + fn test_spawn_local() { + let c = MainContext::new(); + let l = crate::MainLoop::new(Some(&c), false); + + c.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); + + std::thread::spawn({ + let l_clone = l.clone(); + move || { + c.spawn_from_within(move || async move { + l_clone.quit(); + }); + } + }); + + l.run(); + } + + #[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" + ); + }); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/manual_functions.rs b/walletapp/vendor/glib-0.18.5-btc09/src/manual_functions.rs new file mode 100644 index 0000000..7d81ba9 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/manual_functions.rs @@ -0,0 +1,288 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +#[cfg(not(windows))] +use std::boxed::Box as Box_; +#[cfg(not(windows))] +use std::mem; +#[cfg(not(windows))] +#[cfg(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::{translate::*, 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) + } +} + +#[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) +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/object.rs b/walletapp/vendor/glib-0.18.5-btc09/src/object.rs new file mode 100644 index 0000000..bb799ba --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/object.rs @@ -0,0 +1,4542 @@ +// 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, + prelude::*, + quark::Quark, + subclass::{prelude::*, signal::SignalQuery, SignalId}, + thread_guard::thread_id, + translate::*, + value::FromValue, + Closure, IntoGStr, 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 + + crate::value::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<'a>(ptr: *const *const Self::GlibType) -> &'a 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 +/// Inveitably this trait will discard informations 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])* + #[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),+>)? { + #[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),+>)? { + #[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),+>)? { + #[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),+>)? { + #[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),+>)? { + #[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<'a>(ptr: *const *const Self::GlibType) -> &'a Self { + &*(ptr 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::object::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::types::StaticType for $name $(<$($generic),+>)? { + #[inline] + fn static_type() -> $crate::types::Type { + #[allow(unused_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 { + debug_assert_eq!(std::mem::size_of::(), std::mem::size_of::<$crate::ffi::gpointer>()); + let value = &*(value as *const $crate::Value as *const $crate::gobject_ffi::GValue); + debug_assert!(!value.data[0].v_pointer.is_null()); + debug_assert_ne!((*(value.data[0].v_pointer as *const $crate::gobject_ffi::GObject)).ref_count, 0); + <$name $(<$($generic),+>)? as $crate::object::ObjectType>::from_glib_ptr_borrow(&value.data[0].v_pointer as *const $crate::ffi::gpointer as *const *const $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::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::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::object::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::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::Cast>::upcast(v) + } + } + + #[doc(hidden)] + unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::object::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)*] + ); + }; + + (@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::Cast>::upcast(v) + } + } + + #[doc(hidden)] + unsafe impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::object::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_ffi::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_ffi::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_}'")); + let pspecs = klass.list_properties(); + + for (idx, (name, value)) in properties.iter_mut().enumerate() { + let pspec = pspecs + .iter() + .find(|p| p.name() == *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 + /// Set property `name` to the given value `value`. + #[inline] + 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 + /// 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`](crate::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`](crate::subclass::signal::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 pspecs = self.list_properties(); + + let params = property_values + .iter() + .map(|&(name, value)| { + let pspec = pspecs.iter().find(|p| p.name() == 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::>(); + + 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 pspecs = self.list_properties(); + + let params = property_values + .iter() + .map(|(name, value)| { + let pspec = pspecs + .iter() + .find(|p| p.name() == *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::>(); + + 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::<_, 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<'a, T: ObjectType> Watchable for BorrowedObject<'a, 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})", + ) + ); + } + } +} + +impl ObjectClass { + // 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. + 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 object class. + /// + /// 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 object class. + #[doc(alias = "g_object_class_find_property")] + pub 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")] + pub 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) + } + } +} + +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] + 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 { + 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<'a, 'f, 't> fmt::Debug for BindingBuilder<'a, 'f, 't> { + 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> + where + U: IsA, + { + 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> + where + U: IsA, + { + if !self.type_().is_a(U::static_type()) { + return None; + } + + unsafe { + let klass = self as *mut _ as *mut Class; + Some(&mut *klass) + } + } + + // 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<'a, T: IsClass> ops::Deref for ClassRef<'a, T> { + type Target = Class; + + #[inline] + fn deref(&self) -> &Class { + unsafe { self.0.as_ref() } + } +} + +impl<'a, T: IsClass> Drop for ClassRef<'a, T> { + #[inline] + fn drop(&mut self) { + if self.1 { + unsafe { + gobject_ffi::g_type_class_unref(self.0.as_ptr() as *mut _); + } + } + } +} + +unsafe impl<'a, T: IsClass> Send for ClassRef<'a, T> {} +unsafe impl<'a, T: IsClass> Sync for ClassRef<'a, T> {} + +// This should require Self: IsA, but that seems to cause a cycle error +pub unsafe trait ParentClassIs: IsClass { + type Parent: IsClass; +} + +// 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<'a, T: IsInterface> Drop for InterfaceRef<'a, T> { + #[inline] + fn drop(&mut self) { + if self.1 { + unsafe { + gobject_ffi::g_type_default_interface_unref(self.0.as_ptr() as *mut _); + } + } + } +} + +impl<'a, T: IsInterface> ops::Deref for InterfaceRef<'a, T> { + type Target = Interface; + + #[inline] + fn deref(&self) -> &Interface { + unsafe { self.0.as_ref() } + } +} + +unsafe impl<'a, T: IsInterface> Send for InterfaceRef<'a, T> {} +unsafe impl<'a, T: IsInterface> Sync for InterfaceRef<'a, T> {} + +// 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<'a, T: Send + Sync> Send for BorrowedObject<'a, T> {} +unsafe impl<'a, T: Send + Sync> Sync for BorrowedObject<'a, 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<'a, T> ops::Deref for BorrowedObject<'a, T> { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + unsafe { &*(&self.ptr as *const _ as *const T) } + } +} + +impl<'a, T> AsRef for BorrowedObject<'a, T> { + #[inline] + fn as_ref(&self) -> &T { + unsafe { &*(&self.ptr as *const _ as *const T) } + } +} + +impl<'a, T: PartialEq> PartialEq for BorrowedObject<'a, T> { + #[inline] + fn eq(&self, other: &T) -> bool { + ::eq(self, other) + } +} + +impl<'a, T: PartialOrd> PartialOrd for BorrowedObject<'a, T> { + #[inline] + fn partial_cmp(&self, other: &T) -> Option { + ::partial_cmp(self, other) + } +} + +impl<'a, T: crate::clone::Downgrade + ObjectType> crate::clone::Downgrade + for BorrowedObject<'a, 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)); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/param_spec.rs b/walletapp/vendor/glib-0.18.5-btc09/src/param_spec.rs new file mode 100644 index 0000000..890b0b0 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/param_spec.rs @@ -0,0 +1,2316 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{ + char::CharTryFromError, + convert::TryFrom, + ffi::CStr, + num::{NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU32, NonZeroU64, NonZeroU8}, + path::{Path, PathBuf}, +}; + +use crate::{ + 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 +{ +} + +#[link(name = "gobject-2.0")] +extern "C" { + pub static g_param_spec_types: *const ffi::GType; +} + +macro_rules! define_param_spec { + ($rust_type:ident, $ffi_type:path, $rust_type_offset:expr) => { + // Can't use get_type here as this is not a boxed type but another fundamental type + wrapper! { + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct $rust_type(Shared<$ffi_type>); + + match fn { + ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec) as *mut $ffi_type, + unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), + } + } + + impl StaticType for $rust_type { + #[inline] + fn static_type() -> Type { + unsafe { + from_glib(*g_param_spec_types.add($rust_type_offset)) + } + } + } + + #[doc(hidden)] + impl crate::value::ValueType for $rust_type { + type Type = $rust_type; + } + + #[doc(hidden)] + 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, $rust_type_offset:expr, $ffi_fun:ident, $alias:literal) => { + define_param_spec!($rust_type, $ffi_type, $rust_type_offset); + 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 { + #[allow(clippy::new_ret_no_self)] + #[doc(alias = $alias)] + #[deprecated = "Use builder() instead"] + pub fn new<'a>( + name: &str, + nick: impl Into>, + blurb: impl Into>, + minimum: $value_type, + maximum: $value_type, + default_value: $value_type, + flags: ParamFlags, + ) -> ParamSpec { + assert_param_name(name); + unsafe { + Self::new_unchecked(name, nick, blurb, minimum, maximum, default_value, flags) + } + } + + 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, $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 { + 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, $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, $builder_type $($required_tt)?); + } +} +macro_rules! define_builder_numeric { + ($rust_type:ident, $builder_type:ident, $n_ty:ty) => { + define_builder!( + $rust_type, + $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", + ); +} +define_param_spec_numeric!( + ParamSpecChar, + gobject_ffi::GParamSpecChar, + i8, + 0, + g_param_spec_char, + "g_param_spec_char" +); + +define_builder_numeric!(ParamSpecChar, ParamSpecCharBuilder, i8); + +define_param_spec_numeric!( + ParamSpecUChar, + gobject_ffi::GParamSpecUChar, + u8, + 1, + g_param_spec_uchar, + "g_param_spec_uchar" +); + +define_builder_numeric!(ParamSpecUChar, ParamSpecUCharBuilder, u8); + +define_param_spec!(ParamSpecBoolean, gobject_ffi::GParamSpecBoolean, 2); + +define_param_spec_default!( + ParamSpecBoolean, + gobject_ffi::GParamSpecBoolean, + bool, + |x| from_glib(x) +); + +impl ParamSpecBoolean { + #[allow(clippy::new_ret_no_self)] + #[doc(alias = "g_param_spec_boolean")] + #[deprecated = "Use builder() instead"] + pub fn new<'a>( + name: &str, + nick: impl Into>, + blurb: impl Into>, + default_value: bool, + flags: ParamFlags, + ) -> ParamSpec { + assert_param_name(name); + unsafe { Self::new_unchecked(name, nick, blurb, default_value, flags) } + } + + 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, + ParamSpecBooleanBuilder { + default_value: bool = false, + } +); + +define_param_spec_numeric!( + ParamSpecInt, + gobject_ffi::GParamSpecInt, + i32, + 3, + g_param_spec_int, + "g_param_spec_int" +); + +define_builder_numeric!(ParamSpecInt, ParamSpecIntBuilder, i32); + +define_param_spec_numeric!( + ParamSpecUInt, + gobject_ffi::GParamSpecUInt, + u32, + 4, + g_param_spec_uint, + "g_param_spec_uint" +); + +define_builder_numeric!(ParamSpecUInt, ParamSpecUIntBuilder, u32); + +define_param_spec_numeric!( + ParamSpecLong, + gobject_ffi::GParamSpecLong, + libc::c_long, + 5, + g_param_spec_long, + "g_param_spec_long" +); + +define_builder_numeric!(ParamSpecLong, ParamSpecLongBuilder, libc::c_long); + +define_param_spec_numeric!( + ParamSpecULong, + gobject_ffi::GParamSpecULong, + libc::c_ulong, + 6, + g_param_spec_ulong, + "g_param_spec_ulong" +); + +define_builder_numeric!(ParamSpecULong, ParamSpecULongBuilder, libc::c_ulong); + +define_param_spec_numeric!( + ParamSpecInt64, + gobject_ffi::GParamSpecInt64, + i64, + 7, + g_param_spec_int64, + "g_param_spec_int64" +); + +define_builder_numeric!(ParamSpecInt64, ParamSpecInt64Builder, i64); + +define_param_spec_numeric!( + ParamSpecUInt64, + gobject_ffi::GParamSpecUInt64, + u64, + 8, + g_param_spec_uint64, + "g_param_spec_uint64" +); + +define_builder_numeric!(ParamSpecUInt64, ParamSpecUInt64Builder, u64); + +define_param_spec!(ParamSpecUnichar, gobject_ffi::GParamSpecUnichar, 9); +define_param_spec_default!(ParamSpecUnichar, gobject_ffi::GParamSpecUnichar, Result, TryFrom::try_from); + +impl ParamSpecUnichar { + #[allow(clippy::new_ret_no_self)] + #[doc(alias = "g_param_spec_unichar")] + #[deprecated = "Use builder() instead"] + pub fn new<'a>( + name: &str, + nick: impl Into>, + blurb: impl Into>, + default_value: char, + flags: ParamFlags, + ) -> ParamSpec { + assert_param_name(name); + unsafe { Self::new_unchecked(name, nick, blurb, default_value, flags) } + } + + 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, + ParamSpecUnicharBuilder { + default_value: char, + } + requires (default_value: char,) +); + +define_param_spec!(ParamSpecEnum, gobject_ffi::GParamSpecEnum, 10); + +impl ParamSpecEnum { + #[allow(clippy::new_ret_no_self)] + #[doc(alias = "g_param_spec_enum")] + #[deprecated = "Use builder() instead"] + pub fn new<'a>( + name: &str, + nick: impl Into>, + blurb: impl Into>, + enum_type: crate::Type, + default_value: i32, + flags: ParamFlags, + ) -> ParamSpec { + assert_param_name(name); + assert!(enum_type.is_a(Type::ENUM)); + unsafe { Self::new_unchecked(name, nick, blurb, enum_type, default_value, flags) } + } + + 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 + } + } + + pub fn builder_with_default + IntoGlib>( + name: &str, + default_value: T, + ) -> ParamSpecEnumBuilder { + ParamSpecEnumBuilder::new(name, default_value) + } + + 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 + } +} + +define_param_spec!(ParamSpecFlags, gobject_ffi::GParamSpecFlags, 11); + +impl ParamSpecFlags { + #[allow(clippy::new_ret_no_self)] + #[doc(alias = "g_param_spec_flags")] + #[deprecated = "Use builder() instead"] + pub fn new<'a>( + name: &str, + nick: impl Into>, + blurb: impl Into>, + flags_type: crate::Type, + default_value: u32, + flags: ParamFlags, + ) -> ParamSpec { + assert_param_name(name); + assert!(flags_type.is_a(Type::FLAGS)); + unsafe { Self::new_unchecked(name, nick, blurb, flags_type, default_value, flags) } + } + + 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 + } + } + + 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 + } +} + +define_param_spec_numeric!( + ParamSpecFloat, + gobject_ffi::GParamSpecFloat, + f32, + 12, + g_param_spec_float, + "g_param_spec_float" +); + +define_builder_numeric!(ParamSpecFloat, ParamSpecFloatBuilder, f32); + +define_param_spec_numeric!( + ParamSpecDouble, + gobject_ffi::GParamSpecDouble, + f64, + 13, + g_param_spec_double, + "g_param_spec_double" +); + +define_builder_numeric!(ParamSpecDouble, ParamSpecDoubleBuilder, f64); + +define_param_spec!(ParamSpecString, gobject_ffi::GParamSpecString, 14); + +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 { + #[allow(clippy::new_ret_no_self)] + #[doc(alias = "g_param_spec_string")] + #[deprecated = "Use builder() instead"] + pub fn new<'a>( + name: &str, + nick: impl Into>, + blurb: impl Into>, + default_value: Option<&str>, + flags: ParamFlags, + ) -> ParamSpec { + assert_param_name(name); + unsafe { Self::new_unchecked(name, nick, blurb, default_value, flags) } + } + + 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(), + )) + } + } + + 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 + } +} + +define_param_spec!(ParamSpecParam, gobject_ffi::GParamSpecParam, 15); + +impl ParamSpecParam { + #[allow(clippy::new_ret_no_self)] + #[doc(alias = "g_param_spec_param")] + #[deprecated = "Use builder() instead"] + pub fn new<'a>( + name: &str, + nick: impl Into>, + blurb: impl Into>, + param_type: crate::Type, + flags: ParamFlags, + ) -> ParamSpec { + assert_param_name(name); + unsafe { Self::new_unchecked(name, nick, blurb, param_type, flags) } + } + + 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, + ParamSpecParamBuilder { + param_type: crate::Type, + } + requires (param_type: crate::Type,) +); + +define_param_spec!(ParamSpecBoxed, gobject_ffi::GParamSpecBoxed, 16); + +impl ParamSpecBoxed { + #[allow(clippy::new_ret_no_self)] + #[doc(alias = "g_param_spec_boxed")] + #[deprecated = "Use builder() instead"] + pub fn new<'a>( + name: &str, + nick: impl Into>, + blurb: impl Into>, + boxed_type: crate::Type, + flags: ParamFlags, + ) -> ParamSpec { + assert_param_name(name); + assert!(boxed_type.is_a(Type::BOXED)); + unsafe { Self::new_unchecked(name, nick, blurb, boxed_type, flags) } + } + + 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(), + )) + } + } + + 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 + } +} + +define_param_spec!(ParamSpecPointer, gobject_ffi::GParamSpecPointer, 17); + +impl ParamSpecPointer { + #[allow(clippy::new_ret_no_self)] + #[doc(alias = "g_param_spec_pointer")] + #[deprecated = "Use builder() instead"] + pub fn new<'a>( + name: &str, + nick: impl Into>, + blurb: impl Into>, + flags: ParamFlags, + ) -> ParamSpec { + assert_param_name(name); + unsafe { Self::new_unchecked(name, nick, blurb, flags) } + } + + 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, ParamSpecPointerBuilder {}); + +define_param_spec!(ParamSpecValueArray, gobject_ffi::GParamSpecValueArray, 18); + +impl ParamSpecValueArray { + #[allow(clippy::new_ret_no_self)] + #[doc(alias = "g_param_spec_value_array")] + #[deprecated = "Use builder() instead"] + pub fn new<'a>( + name: &str, + nick: impl Into>, + blurb: impl Into>, + element_spec: Option>, + flags: ParamFlags, + ) -> ParamSpec { + assert_param_name(name); + unsafe { Self::new_unchecked(name, nick, blurb, element_spec, flags) } + } + + 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 + } + } + + 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 + } +} + +define_param_spec!(ParamSpecObject, gobject_ffi::GParamSpecObject, 19); + +impl ParamSpecObject { + #[allow(clippy::new_ret_no_self)] + #[doc(alias = "g_param_spec_object")] + #[deprecated = "Use builder() instead"] + pub fn new<'a>( + name: &str, + nick: impl Into>, + blurb: impl Into>, + object_type: crate::Type, + flags: ParamFlags, + ) -> ParamSpec { + assert_param_name(name); + assert!(object_type.is_a(Type::OBJECT)); + + unsafe { Self::new_unchecked(name, nick, blurb, object_type, flags) } + } + + 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(), + )) + } + } + + 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 + } +} + +define_param_spec!(ParamSpecOverride, gobject_ffi::GParamSpecOverride, 20); + +impl ParamSpecOverride { + #[allow(clippy::new_ret_no_self)] + #[doc(alias = "g_param_spec_override")] + #[deprecated = "Use builder() instead"] + pub fn new(name: &str, overridden: impl AsRef) -> ParamSpec { + assert_param_name(name); + unsafe { Self::new_unchecked(name, overridden) } + } + + 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 + /// Similar to [`ParamSpecOverride::new`] but specific for an interface. + /// + /// # 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 + /// Similar to [`ParamSpecOverride::new`] but specific for a class. + /// + /// # 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) + } + } + + 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) } + } +} + +define_param_spec!(ParamSpecGType, gobject_ffi::GParamSpecGType, 21); + +impl ParamSpecGType { + #[allow(clippy::new_ret_no_self)] + #[doc(alias = "g_param_spec_gtype")] + #[deprecated = "Use builder() instead"] + pub fn new<'a>( + name: &str, + nick: impl Into>, + blurb: impl Into>, + is_a_type: crate::Type, + flags: ParamFlags, + ) -> ParamSpec { + assert_param_name(name); + unsafe { Self::new_unchecked(name, nick, blurb, is_a_type, flags) } + } + + 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, + ParamSpecGTypeBuilder { + is_a_type: crate::Type = crate::Type::UNIT, + } +); + +define_param_spec!(ParamSpecVariant, gobject_ffi::GParamSpecVariant, 22); + +define_param_spec_default!( + ParamSpecVariant, + gobject_ffi::GParamSpecVariant, + Option, + |x: *mut ffi::GVariant| from_glib_none(x) +); + +impl ParamSpecVariant { + #[allow(clippy::new_ret_no_self)] + #[doc(alias = "g_param_spec_variant")] + #[deprecated = "Use builder() instead"] + pub fn new<'a>( + name: &str, + nick: impl Into>, + blurb: impl Into>, + type_: &crate::VariantTy, + default_value: Option<&crate::Variant>, + flags: ParamFlags, + ) -> ParamSpec { + assert_param_name(name); + unsafe { Self::new_unchecked(name, nick, blurb, type_, default_value, flags) } + } + + 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_)) + } + } + } + + 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 = + fn(&'static str, ty: &'static crate::VariantTy) -> ParamSpecVariantBuilder<'static>; + + fn param_spec_builder() -> Self::BuilderFn { + Self::ParamSpec::builder + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[allow(deprecated)] + fn test_param_spec_string() { + let pspec = + ParamSpecString::new("name", None, None, Some("default"), ParamFlags::READWRITE); + + 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 + ); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/prelude.rs b/walletapp/vendor/glib-0.18.5-btc09/src/prelude.rs new file mode 100644 index 0000000..596442b --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/prelude.rs @@ -0,0 +1,9 @@ +// 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::{ + param_spec::ParamSpecBuilderExt, Cast, CastNone, IsA, ObjectExt, ObjectType, ParamSpecType, + StaticType, StaticTypeExt, StaticVariantType, ToSendValue, ToValue, ToVariant, +}; diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/property.rs b/walletapp/vendor/glib-0.18.5-btc09/src/property.rs new file mode 100644 index 0000000..e6db701 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/property.rs @@ -0,0 +1,303 @@ +// 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::HasParamSpec; +use crate::IsA; +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 once_cell::sync::OnceCell { + type Value = T::Value; +} +impl Property for once_cell::unsync::OnceCell { + 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 trasparently +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 `Props` 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 `Props` 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 `Props` 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 once_cell::sync::OnceCell { + type Value = T; + fn get R>(&self, f: F) -> R { + f(self.get().unwrap()) + } +} +impl PropertyGet for once_cell::unsync::OnceCell { + type Value = T; + fn get R>(&self, f: F) -> R { + f(self.get().unwrap()) + } +} +impl PropertySet for once_cell::sync::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 once_cell::unsync::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 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); diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/quark.rs b/walletapp/vendor/glib-0.18.5-btc09/src/quark.rs new file mode 100644 index 0000000..37dbae9 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/quark.rs @@ -0,0 +1,103 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{fmt, num::NonZeroU32}; + +use crate::{translate::*, GStr, IntoGStr}; + +#[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) -> Quark { + unsafe { s.run_with_gstr(|s| from_glib(ffi::g_quark_from_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"); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/shared.rs b/walletapp/vendor/glib-0.18.5-btc09/src/shared.rs new file mode 100644 index 0000000..f0d0046 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/shared.rs @@ -0,0 +1,588 @@ +// 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])* + #[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<'a>(ptr: *const *const $ffi_name) -> &'a Self { + &*(ptr as *const Self) + } + } + + impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? std::clone::Clone for $name $(<$($generic),+>)? { + #[inline] + fn clone(&self) -> Self { + Self { + inner: std::clone::Clone::clone(&self.inner), + } + } + } + + #[doc(hidden)] + impl $(<$($generic $(: $bound $(+ $bound2)*)?),+>)? $crate::shared::SharedMemoryManager<$ffi_name> for $name $(<$($generic),+>)? { + #[inline] + unsafe fn ref_($ref_arg: *mut $ffi_name) { + $ref_expr; + } + + #[inline] + #[allow(clippy::no_effect)] + unsafe fn unref($unref_arg: *mut $ffi_name) { + $unref_expr; + } + } + + #[doc(hidden)] + impl $(<$($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::types::StaticType for $name $(<$($generic),+>)? { + #[inline] + fn static_type() -> $crate::types::Type { + #[allow(unused_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 { + debug_assert_eq!(std::mem::size_of::(), std::mem::size_of::<$crate::ffi::gpointer>()); + let value = &*(value as *const $crate::Value as *const $crate::gobject_ffi::GValue); + debug_assert!(!value.data[0].v_pointer.is_null()); + <$name $(<$($generic),+>)?>::from_glib_ptr_borrow(&value.data[0].v_pointer as *const $crate::ffi::gpointer as *const *const $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::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::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 { + /// # Safety + /// + /// Callers are responsible for ensuring that a matching call to `unref` + /// is made at an appropriate time. + unsafe fn ref_(ptr: *mut T); + + /// # Safety + /// + /// Callers are responsible for ensuring that a matching call to `ref` was + /// made before this is called, and that the pointer is not used after the + /// `unref` call. + unsafe fn unref(ptr: *mut T); +} + +/// Encapsulates memory management logic for shared types. +#[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, + }) + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/signal.rs b/walletapp/vendor/glib-0.18.5-btc09/src/signal.rs new file mode 100644 index 0000000..75d986e --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/signal.rs @@ -0,0 +1,226 @@ +// 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 ffi::gpointer; +use gobject_ffi::{self, GCallback}; +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: 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. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Propagation { + // Stop other handlers from being invoked for the event. + Stop, + // Propagate the event further. + 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::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() + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/source.rs b/walletapp/vendor/glib-0.18.5-btc09/src/source.rs new file mode 100644 index 0000000..04704f8 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/source.rs @@ -0,0 +1,1197 @@ +// 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 ffi::{self, gboolean, gpointer}; +#[cfg(all(not(unix), docsrs))] +use libc::c_int as RawFd; + +#[cfg(any(unix, docsrs))] +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 identificator +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[doc(alias = "GPid")] +pub struct Pid(pub ffi::GPid); + +unsafe impl Send for Pid {} +unsafe impl Sync for Pid {} + +#[doc(hidden)] +impl IntoGlib for Pid { + type GlibType = ffi::GPid; + + #[inline] + fn into_glib(self) -> ffi::GPid { + self.0 + } +} + +#[doc(hidden)] +impl FromGlib for Pid { + #[inline] + unsafe fn from_glib(val: ffi::GPid) -> Self { + Self(val) + } +} + +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(any(unix, docsrs))] +#[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(any(unix, docsrs))] +#[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(any(unix, docsrs))] +#[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(any(unix, docsrs))] +#[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(any(unix, docsrs))] +#[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(any(unix, docsrs))] +#[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(any(unix, docsrs))] +#[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(any(unix, docsrs))] +#[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(any(unix, docsrs))] +#[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(any(unix, docsrs))] +#[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(any(unix, docsrs))] +#[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(any(unix, docsrs))] +#[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::), + )) + } +} + +// 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::< + _, + unsafe extern "C" fn(ffi::gpointer) -> ffi::gboolean, + >(trampoline_child_watch:: as *const ())), + into_raw_child_watch(func), + Some(destroy_closure_child_watch::), + ); + ffi::g_source_set_priority(source, priority.into_glib()); + + if let Some(name) = name { + ffi::g_source_set_name(source, name.to_glib_none().0); + } + + from_glib_full(source) + } +} + +#[cfg(any(unix, docsrs))] +#[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(any(unix, docsrs))] +#[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::< + _, + 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, + )) + } + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/source_futures.rs b/walletapp/vendor/glib-0.18.5-btc09/src/source_futures.rs new file mode 100644 index 0000000..f483301 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/source_futures.rs @@ -0,0 +1,482 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{marker::Unpin, 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(any(unix, docsrs))] +#[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(any(unix, docsrs))] +#[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(any(unix, docsrs))] +#[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(any(unix, docsrs))] +#[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::default(); + + let res = c.block_on(timeout_future(Duration::from_millis(20)).then(|()| { + let (sender, receiver) = oneshot::channel(); + + thread::spawn(move || { + sender.send(1).unwrap(); + }); + + receiver.then(|i| futures_util::future::ready(i.unwrap())) + })); + + assert_eq!(res, 1); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/subclass/basic.rs b/walletapp/vendor/glib-0.18.5-btc09/src/subclass/basic.rs new file mode 100644 index 0000000..7fee280 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/subclass/basic.rs @@ -0,0 +1,72 @@ +// 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) } + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/subclass/boxed.rs b/walletapp/vendor/glib-0.18.5-btc09/src/subclass/boxed.rs new file mode 100644 index 0000000..2381362 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/subclass/boxed.rs @@ -0,0 +1,109 @@ +// 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::{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 +/// 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 = 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() + ); + + 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()); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/subclass/interface.rs b/walletapp/vendor/glib-0.18.5-btc09/src/subclass/interface.rs new file mode 100644 index 0000000..b87bfae --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/subclass/interface.rs @@ -0,0 +1,217 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{marker, mem}; + +use super::{InitializingType, Signal}; +use crate::{prelude::*, translate::*, Object, ParamSpec, Type}; + +// 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().into_glib()] + } +} + +// Generates all the PrerequisiteList impls for prerequisite_lists of arbitrary sizes based on a list of type +// parameters like A B C. It would generate the impl then for (A, B) and (A, B, C). +macro_rules! prerequisite_list_trait( + ($name1:ident, $name2: ident, $($name:ident),*) => ( + prerequisite_list_trait!(__impl $name1, $name2; $($name),*); + ); + (__impl $($name:ident),+; $name1:ident, $($name2:ident),*) => ( + prerequisite_list_trait_impl!($($name),+); + prerequisite_list_trait!(__impl $($name),+ , $name1; $($name2),*); + ); + (__impl $($name:ident),+; $name1:ident) => ( + prerequisite_list_trait_impl!($($name),+); + prerequisite_list_trait_impl!($($name),+, $name1); + ); +); + +// Generates the impl block for PrerequisiteList on prerequisite_lists or arbitrary sizes based on its +// arguments. Takes a list of type parameters as parameters, e.g. A B C +// and then implements the trait on (A, B, C). +macro_rules! prerequisite_list_trait_impl( + ($($name:ident),+) => ( + impl<$($name: crate::ObjectType),+> PrerequisiteList for ( $($name),+ ) { + fn types() -> Vec { + vec![$($name::static_type().into_glib()),+] + } + } + ); +); + +prerequisite_list_trait!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S); + +/// Type methods required for an [`ObjectInterface`] implementation. +/// +/// This is usually generated by the [`#[object_interface]`](crate::object_interface) attribute macro. +pub unsafe trait ObjectInterfaceType { + /// Returns the `glib::Type` ID of the interface. + /// + /// This will register the type with the type system on the first call. + #[doc(alias = "get_type")] + fn type_() -> Type; +} + +/// The central trait for defining a `GObject` interface. +/// +/// Links together the type name, and the interface struct for type registration and allows hooking +/// into various steps of the type registration and initialization. +/// +/// This must only be implemented on `#[repr(C)]` structs and have `gobject_ffi::GTypeInterface` as +/// the first field. +/// +/// See [`register_interface`] for registering an implementation of this trait +/// with the type system. +/// +/// [`register_interface`]: fn.register_interface.html +pub unsafe trait ObjectInterface: ObjectInterfaceType + Sized + 'static { + /// `GObject` type name. + /// + /// This must be unique in the whole process. + const NAME: &'static str; + + /// Prerequisites for this interface. + /// + /// Any implementer of the interface must be a subclass of the prerequisites or implement them + /// in case of interfaces. + type Prerequisites: PrerequisiteList; + + /// Additional type initialization. + /// + /// This is called right after the type was registered and allows + /// interfaces to do additional type-specific initialization. + /// + /// Optional + fn type_init(_type_: &mut InitializingType) {} + + /// Interface initialization. + /// + /// This is called after `type_init` and before the first implementor + /// of the interface is created. Interfaces can use this to do interface- + /// specific initialization, e.g. for installing signals on the interface, + /// and for setting default implementations of interface functions. + /// + /// Optional + fn interface_init(&mut self) {} + + /// Properties installed for this interface. + /// + /// All implementors of the interface must provide these properties. + fn properties() -> &'static [ParamSpec] { + &[] + } + + /// Signals installed for this interface. + fn signals() -> &'static [Signal] { + &[] + } +} + +pub trait ObjectInterfaceExt: ObjectInterface { + /// Get interface from an instance. + /// + /// This will panic if `obj` does not implement the interface. + #[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); + + let pspecs = ::properties(); + for pspec in pspecs { + gobject_ffi::g_object_interface_install_property( + iface as *mut T as *mut _, + pspec.to_glib_none().0, + ); + } + + let type_ = T::type_(); + let signals = ::signals(); + for signal in signals { + signal.register(type_); + } + + iface.interface_init(); +} + +/// Register a `glib::Type` ID for `T`. +/// +/// This must be called only once and will panic on a second call. +/// +/// The [`object_interface!`] macro will create a `type_()` function around this, which will +/// ensure that it's only ever called once. +/// +/// [`object_interface!`]: ../../macro.object_interface.html +pub fn register_interface() -> Type { + unsafe { + use std::ffi::CString; + + let type_name = CString::new(T::NAME).unwrap(); + assert_eq!( + gobject_ffi::g_type_from_name(type_name.as_ptr()), + gobject_ffi::G_TYPE_INVALID + ); + + let type_ = gobject_ffi::g_type_register_static_simple( + Type::INTERFACE.into_glib(), + type_name.as_ptr(), + mem::size_of::() as u32, + Some(interface_init::), + 0, + None, + 0, + ); + + let prerequisites = T::Prerequisites::types(); + for prerequisite in prerequisites { + gobject_ffi::g_type_interface_add_prerequisite(type_, prerequisite); + } + + let type_ = Type::from_glib(type_); + assert!(type_.is_valid()); + + T::type_init(&mut InitializingType::(type_, marker::PhantomData)); + + type_ + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/subclass/mod.rs b/walletapp/vendor/glib-0.18.5-btc09/src/subclass/mod.rs new file mode 100644 index 0000000..8fd16ad --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/subclass/mod.rs @@ -0,0 +1,267 @@ +// 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 once_cell::sync::Lazy; +//! static PROPERTIES: Lazy> = Lazy::new(|| { +//! vec![ +//! glib::ParamSpecString::builder("name") +//! .build(), +//! glib::ParamSpecEnum::builder::("animal") +//! .build(), +//! glib::ParamSpecFlags::builder::("flags") +//! .build(), +//! glib::ParamSpecVariant::builder("variant", glib::VariantTy::ANY) +//! .build(), +//! ] +//! }); +//! +//! PROPERTIES.as_ref() +//! } +//! +//! // Called whenever a property is set on this instance. The id +//! // is the same as the index of the property in the PROPERTIES array. +//! fn set_property(&self, _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 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 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}, + types::{ + ClassStruct, InstanceStruct, InstanceStructExt, IsImplementable, IsSubclassable, + IsSubclassableExt, ObjectSubclass, ObjectSubclassExt, ObjectSubclassIsExt, + ObjectSubclassType, + }, + }; +} + +pub use self::{ + boxed::register_boxed_type, + interface::register_interface, + signal::{ + Signal, SignalClassHandlerToken, SignalId, SignalInvocationHint, SignalQuery, SignalType, + }, + types::{register_type, InitializingObject, InitializingType, TypeData}, +}; diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/subclass/object.rs b/walletapp/vendor/glib-0.18.5-btc09/src/subclass/object.rs new file mode 100644 index 0000000..ef84967 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/subclass/object.rs @@ -0,0 +1,717 @@ +// 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 super::{prelude::*, Signal}; +use crate::{prelude::*, translate::*, Cast, 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 `Props` 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`] 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`] 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 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 {} + + #[derive(Default)] + pub struct SimpleObject { + name: RefCell>, + construct_name: RefCell>, + constructed: RefCell, + } + + #[glib::object_subclass] + impl ObjectSubclass for SimpleObject { + const NAME: &'static str = "SimpleObject"; + type Type = super::SimpleObject; + type Interfaces = (super::Dummy,); + } + + impl ObjectImpl for SimpleObject { + fn properties() -> &'static [ParamSpec] { + use once_cell::sync::Lazy; + static PROPERTIES: Lazy> = Lazy::new(|| { + 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(), + ] + }); + + PROPERTIES.as_ref() + } + + fn signals() -> &'static [super::Signal] { + use once_cell::sync::Lazy; + static SIGNALS: Lazy> = Lazy::new(|| { + 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(), + ] + }); + + SIGNALS.as_ref() + } + + 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` + } + _ => 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(), + _ => 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, + } + + #[glib::object_interface] + unsafe impl ObjectInterface for DummyInterface { + const NAME: &'static str = "Dummy"; + } + } + + wrapper! { + pub struct ChildObject(ObjectSubclass); + } + + wrapper! { + pub struct SimpleObject(ObjectSubclass); + } + + wrapper! { + pub struct Dummy(ObjectInterface); + } + + unsafe impl IsImplementable for Dummy {} + + #[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(), 4); + 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"); + } + + #[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] + #[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 accross FFI boundaries + // are UB. See https://github.com/gtk-rs/glib/issues/518 + + #[test] + fn test_signal_return_expected_object_type() { + let obj = Object::with_type(SimpleObject::static_type()); + + 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())); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/subclass/object_impl_ref.rs b/walletapp/vendor/glib-0.18.5-btc09/src/subclass/object_impl_ref.rs new file mode 100644 index 0000000..6a75346 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/subclass/object_impl_ref.rs @@ -0,0 +1,163 @@ +// 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() + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/subclass/shared.rs b/walletapp/vendor/glib-0.18.5-btc09/src/subclass/shared.rs new file mode 100644 index 0000000..acd459c --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/subclass/shared.rs @@ -0,0 +1,295 @@ +// 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::{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 + /// 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 = 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() + ); + + 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); + } + + #[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); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/subclass/signal.rs b/walletapp/vendor/glib-0.18.5-btc09/src/subclass/signal.rs new file mode 100644 index 0000000..2ea40cb --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/subclass/signal.rs @@ -0,0 +1,715 @@ +// 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::{ + prelude::*, translate::*, utils::is_canonical_pspec_name, Closure, IntoGStr, 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() + } +} + +impl std::fmt::Display for SignalType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let type_: Type = (*self).into(); + f.debug_struct("SignalType") + .field("name", &type_.name()) + .field("static_scope", &self.static_scope()) + .finish() + } +} + +#[doc(hidden)] +impl FromGlib for SignalType { + #[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), + }; + } + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/subclass/types.rs b/walletapp/vendor/glib-0.18.5-btc09/src/subclass/types.rs new file mode 100644 index 0000000..7e1cdd5 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/subclass/types.rs @@ -0,0 +1,1127 @@ +// 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::SignalId; +use crate::{ + object::{IsClass, IsInterface, ObjectSubclassIs, ParentClassIs}, + prelude::*, + translate::*, + Closure, Object, Type, 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 for implementable interfaces. +pub unsafe trait IsImplementable: IsInterface +where + ::GlibClassType: Copy, +{ + // 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<(ffi::GType, gobject_ffi::GInterfaceInfo)>; + + // 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<(ffi::GType, gobject_ffi::GInterfaceInfo)> { + vec![] + } + + #[inline] + fn instance_init(_instance: &mut InitializingObject) {} +} + +impl> InterfaceList for (A,) +where + ::GlibClassType: Copy, +{ + fn iface_infos() -> Vec<(ffi::GType, gobject_ffi::GInterfaceInfo)> { + vec![( + A::static_type().into_glib(), + gobject_ffi::GInterfaceInfo { + interface_init: Some(interface_init::), + interface_finalize: None, + interface_data: ptr::null_mut(), + }, + )] + } + + #[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<(ffi::GType, gobject_ffi::GInterfaceInfo)> { + vec![ + $( + ( + $name::static_type().into_glib(), + gobject_ffi::GInterfaceInfo { + interface_init: Some(interface_init::), + interface_finalize: None, + interface_data: ptr::null_mut(), + }, + ) + ),+ + ] + } + + #[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. +// FIXME: Once trait bounds other than `Sized` on const fn parameters are stable +// the content of `TypeData` can be made private, and we can add a `const fn new` +// for initialization by the `object_subclass_internal!` macro. +pub struct TypeData { + #[doc(hidden)] + pub type_: Type, + #[doc(hidden)] + pub parent_class: ffi::gpointer, + #[doc(hidden)] + pub parent_ifaces: Option>, + #[doc(hidden)] + pub class_data: Option>>, + #[doc(hidden)] + pub private_offset: isize, + #[doc(hidden)] + pub private_imp_offset: isize, +} + +unsafe impl Send for TypeData {} +unsafe impl Sync for TypeData {} + +impl TypeData { + // 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 + } +} + +// 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; +} + +pub const INIT_TYPE_DATA: TypeData = TypeData { + 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 +/// 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 + /// 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 instance struct that should be + /// used in most cases. + /// + /// [`basic::ClassStruct`]: ../basic/struct.ClassStruct.html + // TODO: Should default to basic::ClassStruct once associated + // type defaults are stabilized https://github.com/rust-lang/rust/issues/29661 + type Class: ClassStruct; + + // 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 = 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() + ); + + 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, &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) +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/thread_guard.rs b/walletapp/vendor/glib-0.18.5-btc09/src/thread_guard.rs new file mode 100644 index 0000000..f3b4c61 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/thread_guard.rs @@ -0,0 +1,114 @@ +// 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 {} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/thread_pool.rs b/walletapp/vendor/glib-0.18.5-btc09/src/thread_pool.rs new file mode 100644 index 0000000..c309708 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/thread_pool.rs @@ -0,0 +1,254 @@ +// 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::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()); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/time_span.rs b/walletapp/vendor/glib-0.18.5-btc09/src/time_span.rs new file mode 100644 index 0000000..082c63a --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/time_span.rs @@ -0,0 +1,99 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use crate::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 + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/time_zone.rs b/walletapp/vendor/glib-0.18.5-btc09/src/time_zone.rs new file mode 100644 index 0000000..ee0f10d --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/time_zone.rs @@ -0,0 +1,15 @@ +// 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 = + ffi::g_time_zone_adjust_time(self.to_glib_none().0, type_.into_glib(), &mut time); + (res, time) + } + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/translate.rs b/walletapp/vendor/glib-0.18.5-btc09/src/translate.rs new file mode 100644 index 0000000..11cfec0 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/translate.rs @@ -0,0 +1,2969 @@ +// 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::{Eq, Ordering, PartialEq}, + collections::HashMap, + error::Error, + ffi::{CStr, CString, OsStr, OsString}, + fmt, + marker::PhantomData, + mem, + path::{Path, PathBuf}, + ptr, +}; + +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<'a, T: ?Sized + GlibPtrDefault> GlibPtrDefault for &'a 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; +} + +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!(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::{convert::TryFrom, num::TryFromIntError}; + + #[derive(Debug, PartialEq, Eq)] + struct U32(u32); + + impl TryFromGlib for U32 { + type Error = TryFromIntError; + unsafe fn try_from_glib(val: libc::c_long) -> Result { + Ok(U32(u32::try_from(val)?)) + } + } + + assert_eq!(unsafe { U32::try_from_glib(0) }, Ok(U32(0))); + assert_eq!(unsafe { U32::try_from_glib(42) }, Ok(U32(42))); + assert!(unsafe { U32::try_from_glib(-1) }.is_err()); + assert!(unsafe { U32::try_from_glib(-42) }.is_err()); + } + + #[test] + fn none_or_invalid_value() { + use std::{convert::TryFrom, 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()); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/types.rs b/walletapp/vendor/glib-0.18.5-btc09/src/types.rs new file mode 100644 index 0000000..4cfa291 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/types.rs @@ -0,0 +1,678 @@ +// 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::{translate::*, IntoGStr, Slice}; + +// 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()) + } + } + + // 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<'a, T: ?Sized + StaticType> StaticType for &'a T { + #[inline] + fn static_type() -> Type { + T::static_type() + } +} + +impl<'a, T: ?Sized + StaticType> StaticType for &'a 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<'a> StaticType for [&'a 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)); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/unichar.rs b/walletapp/vendor/glib-0.18.5-btc09/src/unichar.rs new file mode 100644 index 0000000..435744e --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/unichar.rs @@ -0,0 +1,243 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::mem::MaybeUninit; + +use crate::{ + 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 {} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/unicollate.rs b/walletapp/vendor/glib-0.18.5-btc09/src/unicollate.rs new file mode 100644 index 0000000..0f94554 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/unicollate.rs @@ -0,0 +1,88 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use crate::translate::*; + +// 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(String); + +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 key = + unsafe { from_glib_full(ffi::g_utf8_collate_key(s.as_ref().to_glib_none().0, -1)) }; + 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(String); + +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 key = unsafe { + from_glib_full(ffi::g_utf8_collate_key_for_filename( + s.as_ref().to_glib_none().0, + -1, + )) + }; + Self(key) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn collate() { + let mut unsorted = vec![ + String::from("bcd"), + String::from("cde"), + String::from("abc"), + ]; + + let sorted = vec![ + String::from("abc"), + String::from("bcd"), + String::from("cde"), + ]; + + unsorted.sort_by(|s1, s2| CollationKey::from(&s1).cmp(&CollationKey::from(&s2))); + + assert_eq!(unsorted, sorted); + } + + #[test] + fn collate_filenames() { + let mut unsorted = vec![ + String::from("bcd.a"), + String::from("cde.b"), + String::from("abc.c"), + ]; + + let sorted = vec![ + String::from("abc.c"), + String::from("bcd.a"), + String::from("cde.b"), + ]; + + unsorted.sort_by(|s1, s2| { + FilenameCollationKey::from(&s1).cmp(&FilenameCollationKey::from(&s2)) + }); + + assert_eq!(unsorted, sorted); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/utils.rs b/walletapp/vendor/glib-0.18.5-btc09/src/utils.rs new file mode 100644 index 0000000..59e46be --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/utils.rs @@ -0,0 +1,278 @@ +// 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::{translate::*, GString, IntoGStr, IntoOptionalGStr}; + +// 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}; + + //Mutex to prevent run environment tests parallel + static LOCK: once_cell::sync::Lazy> = once_cell::sync::Lazy::new(|| Mutex::new(())); + + const VAR_NAME: &str = "function_environment_test"; + + fn check_getenv(val: &str) { + let _data = LOCK.lock().unwrap(); + + env::set_var(VAR_NAME, val); + assert_eq!(env::var_os(VAR_NAME), Some(val.into())); + assert_eq!(crate::getenv(VAR_NAME), Some(val.into())); + + let environ = crate::environ(); + assert_eq!(crate::environ_getenv(&environ, VAR_NAME), Some(val.into())); + } + + fn check_setenv(val: &str) { + let _data = LOCK.lock().unwrap(); + + crate::setenv(VAR_NAME, val, true).unwrap(); + assert_eq!(env::var_os(VAR_NAME), Some(val.into())); + } + + #[test] + fn getenv() { + check_getenv("Test"); + check_getenv("Тест"); // "Test" in Russian + } + + #[test] + fn setenv() { + check_setenv("Test"); + check_setenv("Тест"); // "Test" in Russian + } + + #[test] + fn test_filename_from_uri() { + use 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 + ); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/value.rs b/walletapp/vendor/glib-0.18.5-btc09/src/value.rs new file mode 100644 index 0000000..8886db1 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/value.rs @@ -0,0 +1,1665 @@ +// 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::{ + gstring::GString, + prelude::*, + translate::*, + types::{Pointee, Pointer, Type}, +}; + +// 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 identifer 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 + /// 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) + } + } + + #[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) + } + } + + 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<'a> ToValue for &'a 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<'a> ToValue for &'a 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 + ?Sized>(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<'a> ToValue for [&'a str] { + fn to_value(&self) -> Value { + unsafe { + let mut value = Value::for_value_type::>(); + let ptr: *mut *mut c_char = self.to_glib_full(); + gobject_ffi::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void); + value + } + } + + fn value_type(&self) -> Type { + >::static_type() + } +} + +impl<'a> ToValue for &'a [&'a str] { + fn to_value(&self) -> Value { + unsafe { + let mut value = Value::for_value_type::>(); + let ptr: *mut *mut c_char = self.to_glib_full(); + gobject_ffi::g_value_take_boxed(value.to_glib_none_mut().0, ptr as *const c_void); + value + } + } + + fn value_type(&self) -> Type { + >::static_type() + } +} + +impl 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""#); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/value_array.rs b/walletapp/vendor/glib-0.18.5-btc09/src/value_array.rs new file mode 100644 index 0000000..081985a --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/value_array.rs @@ -0,0 +1,251 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{cmp::Ordering, ops, slice}; + +use crate::{ + prelude::*, + translate::*, + value::{ + FromValue, GenericValueTypeOrNoneChecker, ToValueOptional, ValueType, ValueTypeOptional, + }, + HasParamSpec, 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 { + #[doc(alias = "g_value_array_new")] + pub fn new(n_prealloced: u32) -> ValueArray { + unsafe { from_glib_full(gobject_ffi::g_value_array_new(n_prealloced)) } + } + + #[doc(alias = "g_value_array_append")] + pub fn append(&mut self, value: &Value) { + let value = value.to_glib_none(); + unsafe { + gobject_ffi::g_value_array_append(self.to_glib_none_mut().0, value.0); + } + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + #[inline] + pub fn len(&self) -> usize { + self.inner.n_values as usize + } + + #[doc(alias = "get_nth")] + #[doc(alias = "g_value_array_get_nth")] + pub fn nth(&self, index_: u32) -> Option { + unsafe { + from_glib_none(gobject_ffi::g_value_array_get_nth( + mut_override(self.to_glib_none().0), + index_, + )) + } + } + + #[doc(alias = "g_value_array_insert")] + pub fn insert(&mut self, index_: u32, value: &Value) { + let value = value.to_glib_none(); + unsafe { + gobject_ffi::g_value_array_insert(self.to_glib_none_mut().0, index_, value.0); + } + } + + #[doc(alias = "g_value_array_prepend")] + pub fn prepend(&mut self, value: &Value) { + let value = value.to_glib_none(); + unsafe { + gobject_ffi::g_value_array_prepend(self.to_glib_none_mut().0, value.0); + } + } + + #[doc(alias = "g_value_array_remove")] + pub fn remove(&mut self, index_: u32) { + unsafe { + gobject_ffi::g_value_array_remove(self.to_glib_none_mut().0, index_); + } + } + + #[doc(alias = "g_value_array_sort_with_data")] + pub fn sort_with_data Ordering>(&mut self, compare_func: F) { + unsafe extern "C" fn compare_func_trampoline( + a: ffi::gconstpointer, + b: ffi::gconstpointer, + func: ffi::gpointer, + ) -> i32 { + let func = func as *mut &mut (dyn FnMut(&Value, &Value) -> Ordering); + + let a = &*(a as *const Value); + let b = &*(b as *const Value); + + (*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, + ); + } + } +} + +impl ops::Deref for ValueArray { + type Target = [Value]; + + #[inline] + fn deref(&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, + ) + } + } +} + +impl ops::DerefMut for ValueArray { + #[inline] + fn deref_mut(&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, + ) + } + } +} + +// 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 ValueTypeOptional for ValueArray {} + +#[doc(hidden)] +unsafe impl<'a> FromValue<'a> for ValueArray { + type Checker = 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> FromValue<'a> for &'a ValueArray { + type Checker = 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 *const 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 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 + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/variant.rs b/walletapp/vendor/glib-0.18.5-btc09/src/variant.rs new file mode 100644 index 0000000..7793e80 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/variant.rs @@ -0,0 +1,2520 @@ +// 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, FromVariant, ToVariant}; +//! use std::collections::HashMap; +//! +//! // Using the `ToVariant` trait. +//! let num = 10.to_variant(); +//! +//! // `is` tests the type of the value. +//! assert!(num.is::()); +//! +//! // `get` tries to extract the value. +//! assert_eq!(num.get::(), Some(10)); +//! assert_eq!(num.get::(), None); +//! +//! // `get_str` tries to borrow a string slice. +//! let hello = "Hello!".to_variant(); +//! assert_eq!(hello.str(), Some("Hello!")); +//! assert_eq!(num.str(), None); +//! +//! // `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::{Eq, Ordering, PartialEq, PartialOrd}, + collections::{BTreeMap, HashMap}, + fmt, + hash::{BuildHasher, Hash, Hasher}, + mem, ptr, slice, str, +}; + +use crate::{ + 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<'a, T: ?Sized + ToVariant> ToVariant for &'a T { + fn to_variant(&self) -> Variant { + ::to_variant(self) + } +} + +impl<'a, T: ?Sized + Into + Clone> From<&'a T> for Variant { + #[inline] + fn from(v: &'a T) -> Self { + v.clone().into() + } +} + +impl<'a, T: ?Sized + StaticVariantType> StaticVariantType for &'a T { + fn static_variant_type() -> Cow<'static, VariantTy> { + ::static_variant_type() + } +} + +macro_rules! impl_numeric { + ($name:ty, $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 = match entry.child_value(0).get() { + Some(key) => key, + None => return None, + }; + let val = match entry.child_value(1).get() { + Some(val) => val, + None => return None, + }; + + map.insert(key, val); + } + + Some(map) + } +} + +impl 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 = match entry.child_value(0).get() { + Some(key) => key, + None => return None, + }; + let val = match entry.child_value(1).get() { + Some(val) => val, + None => return None, + }; + + map.insert(key, val); + } + + Some(map) + } +} + +impl ToVariant for HashMap +where + K: StaticVariantType + ToVariant + Eq + Hash, + V: StaticVariantType + ToVariant, +{ + fn to_variant(&self) -> Variant { + 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, FromVariant, ToVariant}; +/// use glib::variant::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 = match variant.child_value(0).get() { + Some(key) => key, + None => return None, + }; + let value = match variant.child_value(1).get() { + Some(value) => value, + None => return None, + }; + + Some(Self { key, value }) + } +} + +impl ToVariant for DictEntry +where + K: StaticVariantType + ToVariant, + 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_value(); + while n > 0 { + let v = n.to_variant(); + assert_eq!(v.get(), Some(n)); + n /= 2; + } + } + }; + } + + macro_rules! signed { + ($name:ident, $ty:ident) => { + #[test] + fn $name() { + let mut n = $ty::max_value(); + while n > 0 { + let v = n.to_variant(); + assert_eq!(v.get(), Some(n)); + let v = (-n).to_variant(); + assert_eq!(v.get(), Some(-n)); + n /= 2; + } + } + }; + } + + unsigned!(test_u8, u8); + unsigned!(test_u16, u16); + unsigned!(test_u32, u32); + unsigned!(test_u64, u64); + signed!(test_i16, i16); + signed!(test_i32, i32); + signed!(test_i64, i64); + + #[test] + fn test_str() { + let s = "this is a test"; + let v = s.to_variant(); + assert_eq!(v.str(), Some(s)); + assert_eq!(42u32.to_variant().str(), None); + } + + #[test] + fn test_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()); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/variant_dict.rs b/walletapp/vendor/glib-0.18.5-btc09/src/variant_dict.rs new file mode 100644 index 0000000..a9dfd84 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/variant_dict.rs @@ -0,0 +1,293 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{borrow::Cow, default::Default}; + +use crate::{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 { + #[inline] + fn from(d: VariantDict) -> Self { + unsafe { d.end_unsafe() } + } +} + +impl FromVariant for VariantDict { + fn from_variant(variant: &Variant) -> Option { + if variant.type_() == VariantDict::static_variant_type() { + Some(Self::new(Some(variant))) + } else { + None + } + } +} + +impl From for VariantDict { + fn from(other: Variant) -> Self { + Self::new(Some(&other)) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn create_destroy() { + let _dict = VariantDict::new(None); + } + + #[test] + fn create_roundtrip() { + let dict = VariantDict::default(); + let var: Variant = dict.to_variant(); + let _dict2: VariantDict = var.into(); + } + + #[test] + fn create_populate_destroy() { + let dict = VariantDict::default(); + dict.insert_value("one", &(1u8.to_variant())); + assert_eq!(dict.lookup_value("one", None), Some(1u8.to_variant())); + } + + #[test] + fn create_populate_roundtrip() { + let dict = VariantDict::default(); + dict.insert_value("one", &(1u8.to_variant())); + let var: Variant = dict.to_variant(); + let dict = VariantDict::from_variant(&var).expect("Not a dict?"); + assert_eq!(dict.lookup_value("one", None), Some(1u8.to_variant())); + } + + #[test] + fn lookup() -> Result<(), Box> { + let dict = VariantDict::default(); + dict.insert_value("one", &(1u8.to_variant())); + assert_eq!(dict.lookup::("one")?.unwrap(), 1u8); + assert_eq!( + dict.lookup::("one").err().unwrap().actual, + u8::static_variant_type() + ); + assert!(dict.lookup::("two")?.is_none()); + Ok(()) + } + + #[test] + fn create_populate_remove() { + let dict = VariantDict::default(); + let empty_var = dict.to_variant(); + dict.insert("one", 1u64); + assert!(dict.remove("one")); + assert!(!dict.remove("one")); + let var2 = dict.to_variant(); + assert_eq!(empty_var, var2); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/variant_iter.rs b/walletapp/vendor/glib-0.18.5-btc09/src/variant_iter.rs new file mode 100644 index 0000000..e0997f6 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/variant_iter.rs @@ -0,0 +1,371 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +// This is similar to the GVariantIter provided by glib, but that would +// introduce a heap allocation and doesn't provide a way to determine how +// many items are left in the iterator. + +use std::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator}; + +use crate::{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<'a> ExactSizeIterator for VariantStrIter<'a> {} + +impl<'a> FusedIterator for VariantStrIter<'a> {} + +#[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")); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/variant_type.rs b/walletapp/vendor/glib-0.18.5-btc09/src/variant_type.rs new file mode 100644 index 0000000..ebd53c2 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/variant_type.rs @@ -0,0 +1,1083 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{ + borrow::{Borrow, Cow, ToOwned}, + cmp::{Eq, PartialEq}, + fmt, + hash::{Hash, Hasher}, + iter, + marker::PhantomData, + ops::Deref, + ptr, slice, + str::FromStr, +}; + +use crate::{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<'a> iter::FusedIterator for VariantTyIterator<'a> {} + +#[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"]); + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/win32.rs b/walletapp/vendor/glib-0.18.5-btc09/src/win32.rs new file mode 100644 index 0000000..4e2984c --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/win32.rs @@ -0,0 +1,95 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::path::PathBuf; + +use crate::{translate::*, GString, StrV}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum OSType { + #[doc(alias = "G_WIN32_OS_ANY")] + Any, + #[doc(alias = "G_WIN32_OS_WORKSTATION")] + Workstation, + #[doc(alias = "G_WIN32_OS_SERVER")] + Server, +} + +#[doc(hidden)] +impl IntoGlib for OSType { + 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, + } + } +} + +#[doc(alias = "g_win32_check_windows_version")] +pub fn check_windows_version(major: i32, minor: i32, spver: i32, os_type: OSType) -> 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 command_line() -> StrV { + unsafe { FromGlibPtrContainer::from_glib_full(ffi::g_win32_get_command_line()) } +} + +#[doc(alias = "g_win32_error_message")] +pub fn error_message(error: i32) -> GString { + unsafe { from_glib_full(ffi::g_win32_error_message(error)) } +} + +#[doc(alias = "g_win32_getlocale")] +pub fn 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 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()), + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/src/wrapper.rs b/walletapp/vendor/glib-0.18.5-btc09/src/wrapper.rs new file mode 100644 index 0000000..1ad0610 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/src/wrapper.rs @@ -0,0 +1,445 @@ +// 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!( + @interface [$($attr)*] $visibility $name $(<$($generic $(: $bound $(+ $bound2)*)?),+>)?, *mut std::os::raw::c_void, std::os::raw::c_void, + @ffi_class $iface_name, + @type_ $crate::translate::IntoGlib::into_glib(<$iface_name as $crate::subclass::interface::ObjectInterfaceType>::type_()), + @requires [$( $($requires),+ )?] + ); + }; +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/tests/check_gir.rs b/walletapp/vendor/glib-0.18.5-btc09/tests/check_gir.rs new file mode 100644 index 0000000..2ccf5ff --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/tests/check_gir.rs @@ -0,0 +1,8 @@ +// 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); +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/tests/clone.rs b/walletapp/vendor/glib-0.18.5-btc09/tests/clone.rs new file mode 100644 index 0000000..ee6ccf2 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/tests/clone.rs @@ -0,0 +1,635 @@ +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 self.v as v, @weak state as hello => move |_| { + println!("v: {v}"); + hello.borrow_mut().started = true; + }); + closure(2); + } + } + + Foo { v: Rc::new(0) }.foo(); +} + +#[test] +fn renaming() { + let state = Rc::new(RefCell::new(State::new())); + assert!(!state.borrow().started); + + let closure = { + clone!(@weak state as hello => move || { + hello.borrow_mut().started = true; + }) + }; + + closure(); + assert!(state.borrow().started); +} + +#[test] +fn clone_closure() { + let state = Rc::new(RefCell::new(State::new())); + assert!(!state.borrow().started); + + let closure = { + clone!(@weak state => move || { + state.borrow_mut().started = true; + }) + }; + + closure(); + + assert!(state.borrow().started); + assert_eq!(state.borrow().count, 0); + + let closure = { + let state2 = Rc::new(RefCell::new(State::new())); + assert!(state.borrow().started); + + clone!(@weak state, @strong state2 => move || { + state.borrow_mut().count += 1; + state.borrow_mut().started = true; + state2.borrow_mut().started = true; + }) + }; + + closure(); + + assert_eq!(state.borrow().count, 1); + assert!(state.borrow().started); +} + +#[test] +fn clone_default_value() { + let closure = { + let state = Rc::new(RefCell::new(State::new())); + clone!(@weak state => @default-return 42, move |_| { + state.borrow_mut().started = true; + 10 + }) + }; + + assert_eq!(42, closure(50)); +} + +#[test] +fn clone_panic() { + let state = Arc::new(Mutex::new(State::new())); + state.lock().expect("Failed to lock state mutex").count = 20; + + let closure = { + let state2 = Arc::new(Mutex::new(State::new())); + clone!(@weak state2, @strong state => @default-return panic!(), move |_| { + state.lock().expect("Failed to lock state mutex").count = 21; + state2.lock().expect("Failed to lock state2 mutex").started = true; + 10 + }) + }; + + let result = panic::catch_unwind(|| { + closure(50); + }); + + assert!(result.is_err()); + + assert_eq!(state.lock().expect("Failed to lock state mutex").count, 20); +} + +#[test] +fn clone_import_rename() { + import_rename::test(); +} + +mod import_rename { + use glib::clone as clone_g; + + #[allow(unused_macros)] + macro_rules! clone { + ($($anything:tt)*) => { + |_, _| panic!("The clone! macro doesn't support renaming") + }; + } + + #[allow(unused_variables)] + pub fn test() { + let n = 2; + + let closure: Box = Box::new(clone_g!( + @strong n + => move |_, _| + println!("The clone! macro does support renaming") + )); + + closure(0, 0); + } +} + +#[test] +fn test_clone_macro_self_rename() { + #[derive(Debug)] + struct Foo { + v: u8, + } + + impl Foo { + #[allow(dead_code)] + fn foo(&self) { + let closure = clone!(@strong self as this => move |_x| { + println!("v: {this:?}"); + }); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@strong self as this => move || { + println!("v: {this:?}"); + }); + let closure = clone!(@strong self as this => move |_x| println!("v: {this:?}")); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@strong self as this => move || println!("v: {this:?}")); + + // Fields now! + let closure = clone!(@strong self.v as v => move |_x| { + println!("v: {v:?}"); + }); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@strong self.v as v => move || println!("v: {v:?}")); + + // With @default-panic + let closure = clone!(@strong self.v as v => @default-panic, move |_x| { + println!("v: {v:?}"); + }); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@strong self.v as v => @default-panic, move || println!("v: {v:?}")); + + // With @default-return + let closure = clone!(@strong self.v as _v => @default-return true, move |_x| { + false + }); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@strong self.v as _v => @default-return true, move || false); + } + } +} + +#[test] +fn test_clone_macro_rename() { + let v = Rc::new(1); + + let closure = clone!(@weak v as y => @default-panic, move |_x| { + println!("v: {y}"); + }); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@weak v as y => @default-panic, move || println!("v: {y}")); + + let closure = clone!(@strong v as y => @default-panic, move |_x| { + println!("v: {y}"); + }); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@strong v as y => @default-panic, move || println!("v: {y}")); + + let closure = clone!(@weak v as y => move |_x| { + println!("v: {y}"); + }); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@weak v as y => move || println!("v: {y}")); + + let closure = clone!(@strong v as y => move |_x| { + println!("v: {y}"); + }); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@strong v as y => move || println!("v: {y}")); + + let closure = clone!(@weak v as _y => @default-return true, move |_x| { + false + }); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@weak v as _y => @default-return true, move || false); + + let closure = clone!(@strong v as _y => @default-return true, move |_x| false); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@strong v as _y => @default-return true, move || false); +} + +#[test] +fn test_clone_macro_simple() { + let v = Rc::new(1); + + let closure = clone!(@weak v => @default-panic, move |_x| { + println!("v: {v}"); + }); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@weak v => @default-panic, move || println!("v: {v}")); + + let closure = clone!(@strong v => @default-panic, move |_x| { + println!("v: {v}"); + }); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@strong v => @default-panic, move || println!("v: {v}")); + + let closure = clone!(@weak v => move |_x| { + println!("v: {v}"); + }); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@weak v => move || println!("v: {v}")); + + let closure = clone!(@strong v => move |_x| { + println!("v: {v}"); + }); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@strong v => move || println!("v: {v}")); + + let closure = clone!(@weak v => @default-return true, move |_x| { + false + }); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@weak v => @default-return true, move || false); + + let closure = clone!(@strong v => @default-return true, move |_x| false); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@strong v => @default-return true, move || false); +} + +#[test] +fn test_clone_macro_double_simple() { + let v = Rc::new(1); + let w = Rc::new(2); + + let closure = clone!(@weak v, @weak w => @default-panic, move |_x| { + println!("v: {v}, w: {w}"); + }); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@weak v, @weak w => @default-panic, move || println!("v: {v}, w: {w}")); + + let closure = clone!(@strong v, @strong w => @default-panic, move |_x| { + println!("v: {v}, w: {w}"); + }); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@strong v, @strong w => @default-panic, 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 => @default-return true, move |_x| { + false + }); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@weak v, @weak w => @default-return true, move || false); + + let closure = clone!(@strong v, @strong w => @default-return true, move |_x| false); + closure(0i8); // to prevent compiler error for unknown `x` type. + let _ = clone!(@strong v, @strong w => @default-return true, move || false); +} + +#[test] +fn test_clone_macro_double_rename() { + let v = Rc::new(1); + let w = Rc::new(2); + let done = Rc::new(RefCell::new(0)); + + let closure = clone!(@weak v as x, @weak w => @default-panic, move |z| { + z + *x + *w + }); + assert_eq!(closure(1i8), 4i8); + let closure = clone!(@weak v as x, @weak w => @default-panic, move || 1); + assert_eq!(closure(), 1); + + let closure = clone!(@weak v, @weak w as x => @default-panic, move |z| { + z + *v + *x + }); + assert_eq!(closure(10i8), 13i8); + let closure = clone!(@weak v, @weak w as x => @default-panic, move || 2 + *x); + assert_eq!(closure(), 4); + + let closure = clone!(@strong v as x, @strong w => @default-panic, move |z| { + z + *x + *w + }); + assert_eq!(closure(3i8), 6i8); + let closure = clone!(@strong v as x, @strong w => @default-panic, move || 4 + *w); + assert_eq!(closure(), 6); + + let closure = clone!(@strong v, @strong w as x => @default-panic, move |z| { + z + *v + *x + }); + assert_eq!(closure(0i8), 3i8); + let closure = clone!(@strong v, @strong w as x => @default-panic, move || 5); + assert_eq!(closure(), 5); + + let t_done = done.clone(); + let closure = clone!(@weak v as x, @weak w => move |z| { + *t_done.borrow_mut() = z + *x + *w; + }); + closure(4i8); + assert_eq!(*done.borrow(), 7); + let t_done = done.clone(); + let closure = clone!(@weak v as x, @weak w => move || *t_done.borrow_mut() = *x + *w); + closure(); + assert_eq!(*done.borrow(), 3); + + let t_done = done.clone(); + let closure = clone!(@weak v, @weak w as x => move |z| { + *t_done.borrow_mut() = z + *v + *x; + }); + closure(8i8); + assert_eq!(*done.borrow(), 11i8); + let t_done = done.clone(); + let closure = clone!(@weak v, @weak w as x => move || *t_done.borrow_mut() = *v * *x); + closure(); + assert_eq!(*done.borrow(), 2); + + let t_done = done.clone(); + let closure = clone!(@strong v as x, @strong w => move |z| { + *t_done.borrow_mut() = z + *x + *w; + }); + closure(9i8); + assert_eq!(*done.borrow(), 12i8); + let t_done = done.clone(); + let closure = clone!(@strong v as x, @strong w => move || *t_done.borrow_mut() = *x - *w); + closure(); + assert_eq!(*done.borrow(), -1); + + let t_done = done.clone(); + let closure = clone!(@strong v, @strong w as x => move |z| { + *t_done.borrow_mut() = *v + *x * z; + }); + closure(2i8); + assert_eq!(*done.borrow(), 5); + let t_done = done.clone(); + let closure = clone!(@strong v, @strong w as x => move || *t_done.borrow_mut() = *x - *v); + closure(); + assert_eq!(*done.borrow(), 1); + + let closure = clone!(@weak v as _x, @weak w => @default-return true, move |_| { + false + }); + assert!(!closure(0u8)); + let closure = clone!(@weak v as _x, @weak w => @default-return true, move || false); + assert!(!closure()); + + let closure = clone!(@weak v, @weak w as _x => @default-return true, move |_| { + false + }); + assert!(!closure("a")); + let closure = clone!(@weak v, @weak w as _x => @default-return true, move || false); + assert!(!closure()); + + let closure = clone!(@strong v as _x, @strong w => @default-return true, move |_| { + false + }); + assert!(!closure('a')); + let closure = clone!(@strong v as _x, @strong w => @default-return true, move || false); + assert!(!closure()); + + let closure = clone!(@strong v, @strong w as _x => @default-return true, move |_| { + false + }); + assert!(!closure(12.)); + let closure = clone!(@strong v, @strong w as _x => @default-return true, move || false); + assert!(!closure()); +} + +#[test] +fn test_clone_macro_typed_args() { + macro_rules! test_closure { + ($kind:tt, panic) => {{ + // We need Arc and Mutex to use them below in the thread. + let check = Arc::new(Mutex::new(0)); + let v = Arc::new(Mutex::new(1)); + let w = Arc::new(Mutex::new(1)); + + let closure = clone!(@$kind v as x, @$kind w, @weak check => @default-panic, move |arg: i8| { + *x.lock().unwrap() += arg; + *w.lock().unwrap() += arg; + *check.lock().unwrap() += 1; + }); + closure(1); + assert_eq!(2, *v.lock().unwrap()); + assert_eq!(2, *w.lock().unwrap()); + assert_eq!(1, *check.lock().unwrap()); + + let closure2 = clone!(@$kind v, @$kind w as x, @weak check => @default-panic, move |arg: i8| { + *v.lock().unwrap() += arg; + *x.lock().unwrap() += arg; + *check.lock().unwrap() += 1; + }); + closure2(1); + assert_eq!(3, *v.lock().unwrap()); + assert_eq!(3, *w.lock().unwrap()); + assert_eq!(2, *check.lock().unwrap()); + + #[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 v as x, @$kind w, @weak check => move |arg: i8| { + *x.borrow_mut() += arg; + *w.borrow_mut() += arg; + *check.borrow_mut() += 1; + }); + closure(1); + assert_eq!(2, *v.borrow()); + assert_eq!(2, *w.borrow()); + assert_eq!(1, *check.borrow()); + + let closure2 = clone!(@$kind v, @$kind w as x, @weak check => move |arg: i8| { + *v.borrow_mut() += arg; + *x.borrow_mut() += arg; + *check.borrow_mut() += 1; + }); + closure2(1); + assert_eq!(3, *v.borrow()); + assert_eq!(3, *w.borrow()); + assert_eq!(2, *check.borrow()); + + #[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 w as x, @weak check => move |arg: i8, arg2| { + *v.borrow_mut() = arg; + *x.borrow_mut() = arg2; + *check.borrow_mut() += 1; + }); + closure(0, 9); + assert_eq!(0, *v.borrow()); + assert_eq!(9, *w.borrow()); + assert_eq!(1, *check.borrow()); + + std::mem::drop(v); + std::mem::drop(w); + assert_eq!(1, *check.borrow()); +} + +#[test] +#[allow(clippy::bool_assert_comparison)] +#[allow(clippy::nonminimal_bool)] +fn test_clone_macro_default_return() { + macro_rules! test_default { + ($ret:expr, $($closure_body:tt)*) => {{ + let v = Rc::new(1); + let tmp = clone!(@weak v => @default-return $ret, move || $($closure_body)*); + assert_eq!(tmp(), $($closure_body)*, "shouldn't use default-return value!"); + ::std::mem::drop(v); + assert_eq!(tmp(), $ret, "should use default-return value!"); + }} + } + + #[derive(PartialEq, Debug)] + struct Foo(i32); + + test_default!(Foo(0), Foo(1)); + + #[derive(PartialEq, Debug)] + struct Bar { + x: i32, + } + + test_default!(Bar { x: 0 }, Bar { x: 1 }); + + #[derive(PartialEq, Debug)] + enum Enum { + A, + B(i32), + C { x: i32 }, + } + test_default!(Enum::A, Enum::B(0)); + test_default!(Enum::B(0), Enum::A); + test_default!(Enum::C { x: 0 }, Enum::A); + test_default!( + { + let x = 12; + x + 2 + }, + 19 + ); + // This one is simply to check that we wait for the comma for the default-return value. + test_default!(Enum::A == Enum::B(0) || false, true); +} + +#[test] +fn test_clone_macro_body() { + let v = Arc::new(Mutex::new(0)); + + let closure = clone!(@weak v => move || { + std::thread::spawn(move || { + let mut lock = v.lock().expect("failed to lock"); + for _ in 1..=10 { + *lock += 1; + } + }).join().expect("thread::spawn failed"); + }); + closure(); + assert_eq!(10, *v.lock().expect("failed to lock")); +} + +#[test] +fn test_clone_macro_async_kinds() { + let v = Rc::new(RefCell::new(1)); + + // This one is still a rust unstable feature. + // let _closure = clone!(@weak v => async move || 0); + let closure = clone!(@weak v => move || async move { *v.borrow_mut() += 1; }); + block_on(closure()); + assert_eq!(*v.borrow(), 2); + block_on(clone!(@weak v => async move { *v.borrow_mut() += 1; })); + assert_eq!(*v.borrow(), 3); +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/tests/derive.rs b/walletapp/vendor/glib-0.18.5-btc09/tests/derive.rs new file mode 100644 index 0000000..80a7a89 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/tests/derive.rs @@ -0,0 +1,33 @@ +use 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), + } +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/tests/log.rs b/walletapp/vendor/glib-0.18.5-btc09/tests/log.rs new file mode 100644 index 0000000..194cba8 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/tests/log.rs @@ -0,0 +1,106 @@ +use 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); +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/tests/print.rs b/walletapp/vendor/glib-0.18.5-btc09/tests/print.rs new file mode 100644 index 0000000..0cbcee2 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/tests/print.rs @@ -0,0 +1,49 @@ +use 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); +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/tests/structured_log.rs b/walletapp/vendor/glib-0.18.5-btc09/tests/structured_log.rs new file mode 100644 index 0000000..0ffd5bf --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/tests/structured_log.rs @@ -0,0 +1,152 @@ +#![allow(clippy::unnecessary_to_owned)] +#![allow(clippy::unnecessary_cast)] + +#[test] +fn structured_log() { + use std::sync::{Arc, Mutex}; + + use glib::*; + + let log = Arc::new(Mutex::new(Vec::new())); + { + let log = log.clone(); + // can only be called once per test file + 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)); + LogWriterOutput::Handled + }); + } + log_structured!( + "test", + LogLevel::Message, + { + "MY_META" => "abc"; + "MESSAGE" => "normal with meta"; + "MY_META2" => "def"; + } + ); + + 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(); + } + ); + 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 = 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()); + 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"), + ] + ) + ); +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest.rs b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest.rs new file mode 100644 index 0000000..509933c --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest.rs @@ -0,0 +1,13 @@ +#[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", + ); +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/01-auto-send-sync.rs b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/01-auto-send-sync.rs new file mode 100644 index 0000000..a628864 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/01-auto-send-sync.rs @@ -0,0 +1,33 @@ +mod 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); +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/02-no-auto-send-sync.rs b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/02-no-auto-send-sync.rs new file mode 100644 index 0000000..19e9779 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/02-no-auto-send-sync.rs @@ -0,0 +1,34 @@ +mod 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); +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/02-no-auto-send-sync.stderr b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/02-no-auto-send-sync.stderr new file mode 100644 index 0000000..9dfe0ca --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/02-no-auto-send-sync.stderr @@ -0,0 +1,26 @@ +error[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 `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` diff --git a/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/03-object-no-auto-send-sync.rs b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/03-object-no-auto-send-sync.rs new file mode 100644 index 0000000..901fb8d --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/03-object-no-auto-send-sync.rs @@ -0,0 +1,6 @@ +fn main() { + fn check(_obj: &T) {} + + let obj = glib::Object::new::(); + check(&obj); +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/03-object-no-auto-send-sync.stderr b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/03-object-no-auto-send-sync.stderr new file mode 100644 index 0000000..4fc7bdc --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/03-object-no-auto-send-sync.stderr @@ -0,0 +1,41 @@ +error[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` diff --git a/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/04-auto-send-sync-with-send-sync-parent.rs b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/04-auto-send-sync-with-send-sync-parent.rs new file mode 100644 index 0000000..f3c38ae --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/04-auto-send-sync-with-send-sync-parent.rs @@ -0,0 +1,69 @@ +mod 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); +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.rs b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.rs new file mode 100644 index 0000000..836f225 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.rs @@ -0,0 +1,67 @@ +mod 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); +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.stderr b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.stderr new file mode 100644 index 0000000..b64598f --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.stderr @@ -0,0 +1,32 @@ +error[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 `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` diff --git a/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.rs b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.rs new file mode 100644 index 0000000..e8e9338 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.rs @@ -0,0 +1,51 @@ +glib::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); +} diff --git a/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.stderr b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.stderr new file mode 100644 index 0000000..38fa770 --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.stderr @@ -0,0 +1,53 @@ +error[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` diff --git a/walletapp/vendor/glib-0.18.5-btc09/tests/value.rs b/walletapp/vendor/glib-0.18.5-btc09/tests/value.rs new file mode 100644 index 0000000..53a9eac --- /dev/null +++ b/walletapp/vendor/glib-0.18.5-btc09/tests/value.rs @@ -0,0 +1,67 @@ +use std::ops::Deref; + +use glib::*; + +// 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() + ); +} From b8df5d56005ce197e7c8f5d7cc628740a8379d72 Mon Sep 17 00:00:00 2001 From: Kurt Landman Date: Sat, 18 Jul 2026 15:38:33 +0800 Subject: [PATCH 2/2] Run glib security contract in mirror CI --- .gitlab-ci.yml | 1 + tools/ci/test_ci_workflow_contract.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9167c7c..eda1f74 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -90,6 +90,7 @@ python-contracts: tools.release.test_package_macos tools.release.test_direct_distribution tools.release.test_package_windows_store + tools.release.test_rust_dependency_security tools.site.test_index_contract tools.site.test_store_readiness_contract tools.deploy.test_nine_inbox_contract diff --git a/tools/ci/test_ci_workflow_contract.py b/tools/ci/test_ci_workflow_contract.py index b7df739..cb2dbc6 100644 --- a/tools/ci/test_ci_workflow_contract.py +++ b/tools/ci/test_ci_workflow_contract.py @@ -55,6 +55,7 @@ def test_project_contracts_cover_public_surfaces(self): "python -m unittest discover -s bot/tests -p 'test_*.py'", "python -m unittest \\", "tools.release.test_package_macos", + "tools.release.test_rust_dependency_security", "tools.site.test_index_contract", "tools.deploy.test_nine_inbox_contract", "tools.deploy.test_open_miner_contract", @@ -82,6 +83,7 @@ def test_gitlab_mirror_runs_core_contracts_and_security_scanners(self): "node tools/desktop/verify-wallet-edition.mjs btc09-wallet-core", "node --test tools/mobile/*.test.mjs", "python -m unittest discover -s bot/tests -p 'test_*.py'", + "tools.release.test_rust_dependency_security", ): with self.subTest(token=token): self.assertIn(token, self.gitlab)