From 8cd2695670021a38bc81a499b00fb3459f42e516 Mon Sep 17 00:00:00 2001 From: Alex Cinovoj <135995822+Alexi5000@users.noreply.github.com> Date: Sat, 17 Oct 2026 23:26:27 -0400 Subject: [PATCH 1/7] fix(ci): use pnpm 9 compatible with Node 20 (#1) Co-authored-by: zocomputer --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca510a1..eb6d763 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v4 with: - version: latest + version: 9 - name: Setup Node.js uses: actions/setup-node@v4 From e5706a603f51279748012e88622ae0bb70f5f423 Mon Sep 17 00:00:00 2001 From: Alex Cinovoj <135995822+Alexi5000@users.noreply.github.com> Date: Sat, 17 Oct 2026 23:33:15 -0400 Subject: [PATCH 2/7] ci: allow manual quality verification (#2) Co-authored-by: zocomputer --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eb6d763..1c8c0fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,7 @@ name: CI on: + workflow_dispatch: push: branches: [main] pull_request: From 7cb12049cf81e2ddcf7c1c17fef0aedec8c3d831 Mon Sep 17 00:00:00 2001 From: Alex Cinovoj <135995822+Alexi5000@users.noreply.github.com> Date: Sat, 17 Oct 2026 23:49:37 -0400 Subject: [PATCH 3/7] fix: refresh vulnerable JavaScript and Rust dependencies (#3) * fix: refresh security dependencies and prefer native secret scanner * fix: declare recursive callbacks safely for current React lint rules --------- Co-authored-by: zocomputer --- components/terminal-panel.tsx | 2 +- context/gateway-context.tsx | 11 +- context/local-context.tsx | 28 +- next-env.d.ts | 1 + package.json | 64 +- pnpm-lock.yaml | 2885 +++++++++++++++++---------------- scripts/secrets-scan.sh | 4 + src-tauri/Cargo.lock | 2669 +++++++++++------------------- 8 files changed, 2509 insertions(+), 3155 deletions(-) diff --git a/components/terminal-panel.tsx b/components/terminal-panel.tsx index 7193ff8..5ab2bca 100644 --- a/components/terminal-panel.tsx +++ b/components/terminal-panel.tsx @@ -323,7 +323,7 @@ function TerminalPane({ ) const createTerminal = useCallback( - async (initialCommand?: string) => { + async function createTerminal(initialCommand?: string) { if (!isDesktop) return if (session.terminalId != null) { try { diff --git a/context/gateway-context.tsx b/context/gateway-context.tsx index 907fff8..488b324 100644 --- a/context/gateway-context.tsx +++ b/context/gateway-context.tsx @@ -34,11 +34,7 @@ import { // ─── Connection state machine ──────────────────────────────────────────────── export type ConnectionStatus = - | 'disconnected' - | 'connecting' - | 'authenticating' - | 'connected' - | 'error' + 'disconnected' | 'connecting' | 'authenticating' | 'connected' | 'error' interface PendingRequest { resolve: (payload: unknown) => void @@ -114,7 +110,7 @@ export function GatewayProvider({ children }: { children: React.ReactNode }) { // Core connect logic const doConnect = useCallback( - (url: string, credential: string) => { + function doConnect(url: string, credential: string) { cleanup() intentionalDisconnectRef.current = false setError(null) @@ -249,8 +245,7 @@ export function GatewayProvider({ children }: { children: React.ReactNode }) { setSnapshot(snap) const authInfo = payload.auth as - | { deviceToken?: string; role?: string; scopes?: string[] } - | undefined + { deviceToken?: string; role?: string; scopes?: string[] } | undefined const scopes = authInfo?.scopes ?? (Array.isArray(payload.scopes) ? (payload.scopes as string[]) : []) ?? diff --git a/context/local-context.tsx b/context/local-context.tsx index 1cd8138..17cc0b3 100644 --- a/context/local-context.tsx +++ b/context/local-context.tsx @@ -171,20 +171,6 @@ export function LocalProvider({ children }: { children: ReactNode }) { const webDirHandleRef = useRef(null) - useEffect(() => { - const hasTauriFS = isTauri() && !isIOSTauri() - setDesktop(hasTauriFS) - setLocalMode(true) - - if (hasTauriFS) { - const recent = getRecentFolders() - if (recent.length > 0) { - setRootPathState(recent[0]) - loadTreeTauri(recent[0]) - } - } - }, []) // eslint-disable-line react-hooks/exhaustive-deps - // ── Tauri tree loader ── const loadTreeTauri = useCallback(async (root: string) => { const tree = await tauriInvoke('local_read_tree', { root }) @@ -215,6 +201,20 @@ export function LocalProvider({ children }: { children: ReactNode }) { } }, []) + useEffect(() => { + const hasTauriFS = isTauri() && !isIOSTauri() + setDesktop(hasTauriFS) + setLocalMode(true) + + if (hasTauriFS) { + const recent = getRecentFolders() + if (recent.length > 0) { + setRootPathState(recent[0]) + loadTreeTauri(recent[0]) + } + } + }, []) // eslint-disable-line react-hooks/exhaustive-deps + // ── Web tree loader ── const loadTreeWeb = useCallback(async (handle: FileSystemDirectoryHandle) => { const tree = await webReadTree(handle) diff --git a/next-env.d.ts b/next-env.d.ts index 9edff1c..ce4e94a 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,6 +1,7 @@ /// /// import "./.next/types/routes.d.ts"; +import "./.next/types/root-params.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/package.json b/package.json index 6b0fbf9..e405c40 100644 --- a/package.json +++ b/package.json @@ -48,49 +48,50 @@ "@iconify/react": "^6.0.2", "@monaco-editor/loader": "^1.7.0", "@monaco-editor/react": "^4.7.0", - "@tailwindcss/postcss": "^4.2.1", - "@tauri-apps/api": "^2.10.1", - "@tauri-apps/plugin-clipboard-manager": "^2.3.2", - "@tauri-apps/plugin-dialog": "^2.6.0", - "@tauri-apps/plugin-http": "^2.5.7", - "@tauri-apps/plugin-shell": "^2.3.5", - "@tauri-apps/plugin-window-state": "^2.4.1", + "@tailwindcss/postcss": "^4.3.3", + "@tauri-apps/api": "^2.12.4", + "@tauri-apps/plugin-clipboard-manager": "^2.5.0", + "@tauri-apps/plugin-dialog": "^2.8.3", + "@tauri-apps/plugin-http": "^2.8.3", + "@tauri-apps/plugin-shell": "^2.5.0", + "@tauri-apps/plugin-window-state": "^2.5.0", "@types/dompurify": "^3.2.0", - "@types/node": "^25.3.3", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", + "@types/node": "^25.9.9", + "@types/react": "^19.3.0", + "@types/react-dom": "^19.3.0", "@xterm/addon-fit": "^0.11.0", "@xterm/addon-web-links": "^0.12.0", "@xterm/xterm": "^6.0.0", "create-markdown": "^0.4.0", - "dompurify": "^3.3.1", - "framer-motion": "^12.34.4", - "next": "^16.1.6", - "postcss": "^8.5.6", + "dompurify": "^3.4.17", + "framer-motion": "^12.43.0", + "next": "^16.4.2", + "postcss": "^8.5.30", "qrcode.react": "^4.2.0", - "react": "^19.2.4", - "react-dom": "^19.2.4", - "tailwindcss": "^4.2.1", + "react": "^19.3.1", + "react-dom": "^19.3.1", + "tailwindcss": "^4.3.3", "tw-animate-css": "^1.4.0", "typescript": "^5.9.3" }, "devDependencies": { "@eslint/js": "^10.0.1", - "@tauri-apps/cli": "^2.10.0", + "@tauri-apps/cli": "^2.12.3", "@testing-library/jest-dom": "^6.9.1", - "@testing-library/react": "^16.3.2", - "@vitest/coverage-v8": "^4.0.18", - "eslint": "^10.0.2", - "eslint-config-prettier": "^10.1.8", - "eslint-plugin-react-hooks": "^7.0.1", + "@testing-library/react": "^16.3.3", + "@vitest/coverage-v8": "^4.1.12", "cross-env": "^7.0.3", + "eslint": "^10.13.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-react-hooks": "^7.1.1", "husky": "^9.1.7", "jsdom": "^28.1.0", - "lint-staged": "^16.3.2", + "lint-staged": "^16.4.0", "monaco-editor": "^0.55.1", - "prettier": "^3.8.1", - "typescript-eslint": "^8.56.1", - "vitest": "^4.0.18" + "prettier": "^3.9.10", + "typescript-eslint": "^8.71.2", + "vite": "^7.3.5", + "vitest": "^4.1.12" }, "description": "AI-native code editor powered by OpenClaw. Browser + desktop (Tauri).", "license": "Apache-2.0", @@ -107,5 +108,12 @@ "tauri", "monaco", "nextjs" - ] + ], + "pnpm": { + "overrides": { + "dompurify": "^3.4.17", + "vite": "^7.3.5", + "esbuild": "^0.28.1" + } + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 29fd868..38c7d1b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,52 +4,57 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + dompurify: ^3.4.17 + vite: ^7.3.5 + esbuild: ^0.28.1 + importers: .: dependencies: '@iconify/react': specifier: ^6.0.2 - version: 6.0.2(react@19.2.4) + version: 6.0.2(react@19.3.1) '@monaco-editor/loader': specifier: ^1.7.0 version: 1.7.0 '@monaco-editor/react': specifier: ^4.7.0 - version: 4.7.0(monaco-editor@0.55.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 4.7.0(monaco-editor@0.55.1)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) '@tailwindcss/postcss': - specifier: ^4.2.1 - version: 4.2.1 + specifier: ^4.3.3 + version: 4.3.3 '@tauri-apps/api': - specifier: ^2.10.1 - version: 2.10.1 + specifier: ^2.12.4 + version: 2.12.4 '@tauri-apps/plugin-clipboard-manager': - specifier: ^2.3.2 - version: 2.3.2 + specifier: ^2.5.0 + version: 2.5.0 '@tauri-apps/plugin-dialog': - specifier: ^2.6.0 - version: 2.6.0 + specifier: ^2.8.3 + version: 2.8.3 '@tauri-apps/plugin-http': - specifier: ^2.5.7 - version: 2.5.7 + specifier: ^2.8.3 + version: 2.8.3 '@tauri-apps/plugin-shell': - specifier: ^2.3.5 - version: 2.3.5 + specifier: ^2.5.0 + version: 2.5.0 '@tauri-apps/plugin-window-state': - specifier: ^2.4.1 - version: 2.4.1 + specifier: ^2.5.0 + version: 2.5.0 '@types/dompurify': specifier: ^3.2.0 version: 3.2.0 '@types/node': - specifier: ^25.3.3 - version: 25.3.3 + specifier: ^25.9.9 + version: 25.9.9 '@types/react': - specifier: ^19.2.14 - version: 19.2.14 + specifier: ^19.3.0 + version: 19.3.0 '@types/react-dom': - specifier: ^19.2.3 - version: 19.2.3(@types/react@19.2.14) + specifier: ^19.3.0 + version: 19.3.0(@types/react@19.3.0) '@xterm/addon-fit': specifier: ^0.11.0 version: 0.11.0 @@ -61,31 +66,31 @@ importers: version: 6.0.0 create-markdown: specifier: ^0.4.0 - version: 0.4.0(react@19.2.4) + version: 0.4.0(react@19.3.1) dompurify: - specifier: ^3.3.1 - version: 3.3.1 + specifier: ^3.4.17 + version: 3.4.17 framer-motion: - specifier: ^12.34.4 - version: 12.34.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^12.43.0 + version: 12.43.0(react-dom@19.3.1(react@19.3.1))(react@19.3.1) next: - specifier: ^16.1.6 - version: 16.1.6(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^16.4.2 + version: 16.4.2(@babel/core@7.29.7)(@types/node@25.9.9)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) postcss: - specifier: ^8.5.6 - version: 8.5.6 + specifier: ^8.5.30 + version: 8.5.30 qrcode.react: specifier: ^4.2.0 - version: 4.2.0(react@19.2.4) + version: 4.2.0(react@19.3.1) react: - specifier: ^19.2.4 - version: 19.2.4 + specifier: ^19.3.1 + version: 19.3.1 react-dom: - specifier: ^19.2.4 - version: 19.2.4(react@19.2.4) + specifier: ^19.3.1 + version: 19.3.1(react@19.3.1) tailwindcss: - specifier: ^4.2.1 - version: 4.2.1 + specifier: ^4.3.3 + version: 4.3.3 tw-animate-css: specifier: ^1.4.0 version: 1.4.0 @@ -95,31 +100,31 @@ importers: devDependencies: '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.0.2(jiti@2.6.1)) + version: 10.0.1(eslint@10.13.0(jiti@2.7.0)) '@tauri-apps/cli': - specifier: ^2.10.0 - version: 2.10.0 + specifier: ^2.12.3 + version: 2.12.3 '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 '@testing-library/react': - specifier: ^16.3.2 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^16.3.3 + version: 16.3.3(@testing-library/dom@10.4.1)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1) '@vitest/coverage-v8': - specifier: ^4.0.18 - version: 4.0.18(vitest@4.0.18(@types/node@25.3.3)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(yaml@2.8.2)) + specifier: ^4.1.12 + version: 4.1.12(vitest@4.1.12) cross-env: specifier: ^7.0.3 version: 7.0.3 eslint: - specifier: ^10.0.2 - version: 10.0.2(jiti@2.6.1) + specifier: ^10.13.0 + version: 10.13.0(jiti@2.7.0) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@10.0.2(jiti@2.6.1)) + version: 10.1.8(eslint@10.13.0(jiti@2.7.0)) eslint-plugin-react-hooks: - specifier: ^7.0.1 - version: 7.0.1(eslint@10.0.2(jiti@2.6.1)) + specifier: ^7.1.1 + version: 7.1.1(eslint@10.13.0(jiti@2.7.0)) husky: specifier: ^9.1.7 version: 9.1.7 @@ -127,122 +132,135 @@ importers: specifier: ^28.1.0 version: 28.1.0 lint-staged: - specifier: ^16.3.2 - version: 16.3.2 + specifier: ^16.4.0 + version: 16.4.0 monaco-editor: specifier: ^0.55.1 version: 0.55.1 prettier: - specifier: ^3.8.1 - version: 3.8.1 + specifier: ^3.9.10 + version: 3.9.10 typescript-eslint: - specifier: ^8.56.1 - version: 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.71.2 + version: 8.71.2(eslint@10.13.0(jiti@2.7.0))(typescript@5.9.3) + vite: + specifier: ^7.3.5 + version: 7.3.7(@types/node@25.9.9)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.1) vitest: - specifier: ^4.0.18 - version: 4.0.18(@types/node@25.3.3)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(yaml@2.8.2) + specifier: ^4.1.12 + version: 4.1.12(@types/node@25.9.9)(@vitest/coverage-v8@4.1.12)(jsdom@28.1.0)(vite@7.3.7(@types/node@25.9.9)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.1)) packages: - '@acemir/cssom@0.9.31': - resolution: {integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==} + '@acemir/cssom@0.9.32': + resolution: {integrity: sha512-OijrAUu7rrJhSIoHNg6LMPS5e344nwUHA+1EFYYjrh64D+GmytUsfBQjci45TjT+rd5Spsp8B5xsZDT+TgyXXQ==} - '@adobe/css-tools@4.4.4': - resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} + '@adobe/css-tools@4.5.0': + resolution: {integrity: sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==} - '@alloc/quick-lru@5.2.0': - resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + '@alloc/quick-lru@5.3.0': + resolution: {integrity: sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA==} engines: {node: '>=10'} - '@asamuzakjp/css-color@5.0.1': - resolution: {integrity: sha512-2SZFvqMyvboVV1d15lMf7XiI3m7SDqXUuKaTymJYLN6dSGadqp+fVojqJlVoMlbZnlTmu3S0TLwLTJpvBMO1Aw==} + '@asamuzakjp/css-color@5.1.11': + resolution: {integrity: sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} '@asamuzakjp/dom-selector@6.8.1': resolution: {integrity: sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==} + '@asamuzakjp/generational-cache@1.0.1': + resolution: {integrity: sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + '@asamuzakjp/nwsapi@2.3.9': resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.29.0': - resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} engines: {node: '>=6.9.0'} - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + '@babel/generator@7.29.8': + resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} engines: {node: '>=6.9.0'} - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.28.6': - resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + '@babel/helpers@7.29.10': + resolution: {integrity: sha512-EMCx3AGZ3WfAl6ht7AyQoPm2Lh+BGYEMdc4Q6Hf7uSCDOZFuLq44qNwL+iaim8VlyYhRAo4X43+weadK8ZB4Yg==} engines: {node: '>=6.9.0'} - '@babel/parser@7.29.0': - resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + '@babel/parser@7.29.9': + resolution: {integrity: sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/runtime@7.28.6': - resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + '@babel/runtime@7.29.10': + resolution: {integrity: sha512-NpugTzbKgGrNe45Ui32cN8vCFFMxVtP/9rtfwv0nP5FRDAjvYBxJcLVpYA9mr1jxP6cnIT7x9LUzuDTbWYYNRA==} engines: {node: '>=6.9.0'} - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + '@babel/traverse@7.29.10': + resolution: {integrity: sha512-B3lYAs2nkKskbgQ1nfy8Ma9ao9Q1rntTAQHrzzyDuj+TSO+X3le6PfWwqDvodsb+OumE10eMFfuMCTQSQ5iuIQ==} engines: {node: '>=6.9.0'} - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} engines: {node: '>=6.9.0'} '@bcoe/v8-coverage@1.0.2': resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} - '@bramus/specificity@2.4.2': - resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} + '@bramus/specificity@2.4.3': + resolution: {integrity: sha512-0GEz8qJWokkUVYQYRukmkSHIFNoBH8QTreeHrAFbvz1XFYc3Y+puhMs8PQ5x8GNugiC2l5jvDBXKLbBIByeSBw==} hasBin: true + '@cacheable/memory@2.2.0': + resolution: {integrity: sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==} + + '@cacheable/utils@2.5.0': + resolution: {integrity: sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==} + '@create-markdown/core@0.2.0': resolution: {integrity: sha512-lCvQcIY+C+oyHbojZSxuEwgVjcrSgT0yU7VvRrx6g2dyC2kb/HHyakkcq15n6SjXUCgvhocxnXQURoROH/cKbA==} engines: {node: '>=20.0.0'} @@ -267,198 +285,203 @@ packages: '@create-markdown/core': '>=0.2.0' react: '>=18.0.0' - '@csstools/color-helpers@6.0.2': - resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} + '@csstools/color-helpers@6.1.2': + resolution: {integrity: sha512-grhRy3OKmniaAEKXMjua5z/EODX0MSqBGjunw8+j/3HQjOnahs2AGhvEOIYVUWcU6ScApbhLhVrQTX8XqrMrow==} engines: {node: '>=20.19.0'} - '@csstools/css-calc@3.1.1': - resolution: {integrity: sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==} + '@csstools/css-calc@3.4.3': + resolution: {integrity: sha512-iex20d8CHVkyvg6B7UKV7uHnI2Bqo9g+EFfT9E0y+GvTvhZ/DwONJ+9aKb1dlqm0ZiGsL5RXjp0fCoJYnkeDjA==} engines: {node: '>=20.19.0'} peerDependencies: - '@csstools/css-parser-algorithms': ^4.0.0 - '@csstools/css-tokenizer': ^4.0.0 + '@csstools/css-parser-algorithms': ^4.0.2 + '@csstools/css-tokenizer': ^4.0.2 - '@csstools/css-color-parser@4.0.2': - resolution: {integrity: sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==} + '@csstools/css-color-parser@4.2.6': + resolution: {integrity: sha512-iiPQ3iRWwnJkeEn6RIu6SJPr7hYrLz6XZ9s/QZl+2/LI5KQVjpl2fdmDSZKuD4xP6GMmMPgHFFXg6k1Wkz0Trg==} engines: {node: '>=20.19.0'} peerDependencies: - '@csstools/css-parser-algorithms': ^4.0.0 - '@csstools/css-tokenizer': ^4.0.0 + '@csstools/css-parser-algorithms': ^4.0.2 + '@csstools/css-tokenizer': ^4.0.2 - '@csstools/css-parser-algorithms@4.0.0': - resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + '@csstools/css-parser-algorithms@4.0.2': + resolution: {integrity: sha512-40cSKyMvK+tq4qz6Awrlye2WGuOKt3FwPgtGg6KTfbHOWNw+Rk1rzbAtZnZ6IBhsY491HLRnDXwoyBAijmmILA==} engines: {node: '>=20.19.0'} peerDependencies: - '@csstools/css-tokenizer': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.2 - '@csstools/css-syntax-patches-for-csstree@1.0.29': - resolution: {integrity: sha512-jx9GjkkP5YHuTmko2eWAvpPnb0mB4mGRr2U7XwVNwevm8nlpobZEVk+GNmiYMk2VuA75v+plfXWyroWKmICZXg==} + '@csstools/css-syntax-patches-for-csstree@1.1.15': + resolution: {integrity: sha512-J0u7HkVl2nzSlhsiTOp4AmwcUQ3D+mGEEKfBy/7To5/y7F2OHwyLrXfrhR0SMgr4p5Lo+eaMVSeai24zUcBIxA==} + peerDependencies: + css-tree: ^3.2.1 + peerDependenciesMeta: + css-tree: + optional: true - '@csstools/css-tokenizer@4.0.0': - resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + '@csstools/css-tokenizer@4.0.2': + resolution: {integrity: sha512-OoKoR0f76dCY666JlcbhmVTs2drYj1GUXZTYTcbUgJjh9Nv41aFfZ21bPQTERm5+L5cBDo466NltB2lplS5GBw==} engines: {node: '>=20.19.0'} - '@emnapi/runtime@1.8.1': - resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} - '@esbuild/aix-ppc64@0.27.3': - resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.27.3': - resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.27.3': - resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.27.3': - resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.27.3': - resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.27.3': - resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.27.3': - resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.3': - resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.27.3': - resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.27.3': - resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.27.3': - resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.27.3': - resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.27.3': - resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.27.3': - resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.27.3': - resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.27.3': - resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.27.3': - resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.27.3': - resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.3': - resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.27.3': - resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.3': - resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.27.3': - resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.27.3': - resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.27.3': - resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.27.3': - resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.27.3': - resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.9.1': - resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + '@eslint-community/eslint-utils@4.10.1': + resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 @@ -467,16 +490,16 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.23.2': - resolution: {integrity: sha512-YF+fE6LV4v5MGWRGj7G404/OZzGNepVF8fxk7jqmqo3lrza7a0uUcDnROGRBG1WFC1omYUS/Wp1f42i0M+3Q3A==} + '@eslint/config-array@0.23.5': + resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/config-helpers@0.5.2': - resolution: {integrity: sha512-a5MxrdDXEvqnIq+LisyCX6tQMPF/dSJpCfBgBauY+pNZ28yCtSsTvyTYrMhaI+LK26bVyCJfJkT0u8KIj2i1dQ==} + '@eslint/config-helpers@0.7.0': + resolution: {integrity: sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/core@1.1.0': - resolution: {integrity: sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==} + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@eslint/js@10.0.1': @@ -488,16 +511,16 @@ packages: eslint: optional: true - '@eslint/object-schema@3.0.2': - resolution: {integrity: sha512-HOy56KJt48Bx8KmJ+XGQNSUMT/6dZee/M54XyUyuvTvPXJmsERRvBchsUVx1UMe1WwIH49XLAczNC7V2INsuUw==} + '@eslint/object-schema@3.0.5': + resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/plugin-kit@0.6.0': - resolution: {integrity: sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ==} + '@eslint/plugin-kit@0.7.3': + resolution: {integrity: sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@exodus/bytes@1.15.0': - resolution: {integrity: sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==} + '@exodus/bytes@1.16.0': + resolution: {integrity: sha512-IcpW84uEn3N7ETtNZMlxKhfl6Pec8rUNGOTBtWbK1FKhJxIFAptZyVrvVRVBimAJxJCgc3PxepxkdWWG4DVzfA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: '@noble/hashes': ^1.8.0 || ^2.0.0 @@ -505,12 +528,16 @@ packages: '@noble/hashes': optional: true - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} engines: {node: '>=18.18.0'} - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': @@ -529,156 +556,149 @@ packages: '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} - '@img/colour@1.0.0': - resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} - '@img/sharp-darwin-arm64@0.34.5': - resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-darwin-arm64@0.35.5': + resolution: {integrity: sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.34.5': - resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-darwin-x64@0.35.5': + resolution: {integrity: sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.4': - resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + '@img/sharp-freebsd-wasm32@0.35.5': + resolution: {integrity: sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-libvips-darwin-arm64@1.3.4': + resolution: {integrity: sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.4': - resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + '@img/sharp-libvips-darwin-x64@1.3.4': + resolution: {integrity: sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.2.4': - resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + '@img/sharp-libvips-linux-arm64@1.3.4': + resolution: {integrity: sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==} cpu: [arm64] os: [linux] - libc: [glibc] - '@img/sharp-libvips-linux-arm@1.2.4': - resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + '@img/sharp-libvips-linux-arm@1.3.4': + resolution: {integrity: sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==} cpu: [arm] os: [linux] - libc: [glibc] - '@img/sharp-libvips-linux-ppc64@1.2.4': - resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + '@img/sharp-libvips-linux-ppc64@1.3.4': + resolution: {integrity: sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==} cpu: [ppc64] os: [linux] - libc: [glibc] - '@img/sharp-libvips-linux-riscv64@1.2.4': - resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + '@img/sharp-libvips-linux-riscv64@1.3.4': + resolution: {integrity: sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==} cpu: [riscv64] os: [linux] - libc: [glibc] - '@img/sharp-libvips-linux-s390x@1.2.4': - resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + '@img/sharp-libvips-linux-s390x@1.3.4': + resolution: {integrity: sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==} cpu: [s390x] os: [linux] - libc: [glibc] - '@img/sharp-libvips-linux-x64@1.2.4': - resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + '@img/sharp-libvips-linux-x64@1.3.4': + resolution: {integrity: sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==} cpu: [x64] os: [linux] - libc: [glibc] - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + '@img/sharp-libvips-linuxmusl-arm64@1.3.4': + resolution: {integrity: sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==} cpu: [arm64] os: [linux] - libc: [musl] - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + '@img/sharp-libvips-linuxmusl-x64@1.3.4': + resolution: {integrity: sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==} cpu: [x64] os: [linux] - libc: [musl] - '@img/sharp-linux-arm64@0.34.5': - resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-arm64@0.35.5': + resolution: {integrity: sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] - libc: [glibc] - '@img/sharp-linux-arm@0.34.5': - resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-arm@0.35.5': + resolution: {integrity: sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==} + engines: {node: '>=20.9.0'} cpu: [arm] os: [linux] - libc: [glibc] - '@img/sharp-linux-ppc64@0.34.5': - resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-ppc64@0.35.5': + resolution: {integrity: sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==} + engines: {node: '>=20.9.0'} cpu: [ppc64] os: [linux] - libc: [glibc] - '@img/sharp-linux-riscv64@0.34.5': - resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-riscv64@0.35.5': + resolution: {integrity: sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==} + engines: {node: '>=20.9.0'} cpu: [riscv64] os: [linux] - libc: [glibc] - '@img/sharp-linux-s390x@0.34.5': - resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-s390x@0.35.5': + resolution: {integrity: sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==} + engines: {node: '>=20.9.0'} cpu: [s390x] os: [linux] - libc: [glibc] - '@img/sharp-linux-x64@0.34.5': - resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-x64@0.35.5': + resolution: {integrity: sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] - libc: [glibc] - '@img/sharp-linuxmusl-arm64@0.34.5': - resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-arm64@0.35.5': + resolution: {integrity: sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] - libc: [musl] - '@img/sharp-linuxmusl-x64@0.34.5': - resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-x64@0.35.5': + resolution: {integrity: sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] - libc: [musl] - '@img/sharp-wasm32@0.34.5': - resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-wasm32@0.35.5': + resolution: {integrity: sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==} + engines: {node: '>=20.9.0'} + + '@img/sharp-webcontainers-wasm32@0.35.5': + resolution: {integrity: sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==} + engines: {node: '>=20.9.0'} cpu: [wasm32] - '@img/sharp-win32-arm64@0.34.5': - resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-arm64@0.35.5': + resolution: {integrity: sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.34.5': - resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-ia32@0.35.5': + resolution: {integrity: sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==} + engines: {node: ^20.9.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.34.5': - resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-x64@0.35.5': + resolution: {integrity: sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [win32] @@ -692,12 +712,21 @@ packages: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@keyv/bigmap@1.3.1': + resolution: {integrity: sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==} + engines: {node: '>= 18'} + peerDependencies: + keyv: ^5.6.0 + + '@keyv/serialize@1.1.1': + resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==} + '@monaco-editor/loader@1.7.0': resolution: {integrity: sha512-gIwR1HrJrrx+vfyOhYmCZ0/JcWqG5kbfG7+d3f/C1LXk2EvzAbHSg3MQ5lO2sMlo9izoAZ04shohfKLVT6crVA==} @@ -708,268 +737,253 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@next/env@16.1.6': - resolution: {integrity: sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==} + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} + engines: {node: ^22.20 || ^24.12 || >=25} + cpu: [x64] + os: [linux] + + '@next/env@16.4.2': + resolution: {integrity: sha512-nTUTFH7G5/J/fmpkjVLegOkqyKOP0CEsJcMsyO4UCYeN1su+YMW/MfaSErnJskL7XM+UDK6aTvslxsRCyya/sA==} - '@next/swc-darwin-arm64@16.1.6': - resolution: {integrity: sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==} + '@next/swc-darwin-arm64@16.4.2': + resolution: {integrity: sha512-ONkhFvZNFWlsEHOM/81AtxdyuJP2KRYKYR0JxPwvcu1AuPMMMgcL+wW2luldJvMtZwKtUxoSkCychW5wIeoYSw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@16.1.6': - resolution: {integrity: sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==} + '@next/swc-darwin-x64@16.4.2': + resolution: {integrity: sha512-luPCMbOsCoaF+kXJEUjmjmOZg1lC3BflhmUu+ZmW4tBu2vW/4AXak8JBFvePizGkxVmNiAw/r9ra+6UviCWtWQ==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@16.1.6': - resolution: {integrity: sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==} + '@next/swc-linux-arm64-gnu@16.4.2': + resolution: {integrity: sha512-xhwFTAncJyaCNy5KqKKuKaIIdCy1/1ZV1s5S1G0hhT7wGMkDTlfJ6aQbfRFnIG/s3/kDrxQ8aycVe+c5QnP8ow==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] - '@next/swc-linux-arm64-musl@16.1.6': - resolution: {integrity: sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==} + '@next/swc-linux-arm64-musl@16.4.2': + resolution: {integrity: sha512-T1PNmfbPcxr5ndtWUL/3wQtLXsz808lq6sc2GrNT5k2oquF7UyqZddHSuAewHVsWsGXe6nsl9HoN1YNriVjuSg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] - '@next/swc-linux-x64-gnu@16.1.6': - resolution: {integrity: sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==} + '@next/swc-linux-x64-gnu@16.4.2': + resolution: {integrity: sha512-N9cDUOCGtkJG5PNKDFZUF3xXndrJJcpLp121uAGjIGvO/U2p9tfdNOM9htj7+5f72l0m8rMw/cvYacUJBQoudg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] - '@next/swc-linux-x64-musl@16.1.6': - resolution: {integrity: sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==} + '@next/swc-linux-x64-musl@16.4.2': + resolution: {integrity: sha512-yY2uh1YhX6ufuYy2FCbw1dqblbhI57GLYAJfCkqD9auTv6pLrH67Uccjc3QMKBeCYAG6lkgu08ExmX1bbjejjQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] - '@next/swc-win32-arm64-msvc@16.1.6': - resolution: {integrity: sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==} + '@next/swc-win32-arm64-msvc@16.4.2': + resolution: {integrity: sha512-j/ArWRIHpMMB6wYLMhr2puTguBt70lNU/Cmjl9p6dTDE8DGknYJMP9PdwPk2dqpCNL/KIX9yfngDvIesxJPmsg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@16.1.6': - resolution: {integrity: sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==} + '@next/swc-win32-x64-msvc@16.4.2': + resolution: {integrity: sha512-AA4edyWHDko3NCSo0x6GomsdgFb0oR1J3MXU1b5xt6FRFg4AucrMPW3S0hCe/9onU0O1BbpGQBsqo1r0Gneu1g==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@rollup/rollup-android-arm-eabi@4.59.0': - resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} + '@rollup/rollup-android-arm-eabi@4.64.9': + resolution: {integrity: sha512-qJmhckvOleXp8R+BaXiVW/S34/3M7pvN17/QcG90A74BDaSvKv8ffY+GYG+a/xU0vEoITzdMSiM7o9HZSQWbfA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.59.0': - resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} + '@rollup/rollup-android-arm64@4.64.9': + resolution: {integrity: sha512-dqQgds39BNWGB2ughJ6n2LTQFXk8RAOwnXj6m387OHpygfD93QRS1ODIfpiWyAa9gsFB9l34pSqeLmA0Xk/VBw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.59.0': - resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} + '@rollup/rollup-darwin-arm64@4.64.9': + resolution: {integrity: sha512-scrMx4SGikOSbWknLmPD0v6OeJ1Wih3kyRLdNZnlVbBeKVWp1nRTVcpM0IxDJdc3u8UjesPHTmnX649u8cQpBw==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.59.0': - resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} + '@rollup/rollup-darwin-x64@4.64.9': + resolution: {integrity: sha512-fkwi2OQR+QWoViRFt08Bsca6G0e9pk/4z+JgmqHq6jSRTT0LtI27KRVK8bu++6L/CBtQ3OZePbqC3bcrwGzTqQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.59.0': - resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} + '@rollup/rollup-freebsd-arm64@4.64.9': + resolution: {integrity: sha512-8Apr0Khn0r2MUsDtcOMbp85fDdXsX/E+iLhO17WUjG24m3O8ChArqI0isI7CAdj9Ouq177PHtVtEUpMNE1C4Gw==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.59.0': - resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} + '@rollup/rollup-freebsd-x64@4.64.9': + resolution: {integrity: sha512-H+upy4DhBcBZlUsCAMyr8wR0Dg9kj8sGloVZdZ7va2heJM/5jnROxI47dtXseJjlD/VoQe6MrXhY3b5ikOq/Vw==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': - resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} + '@rollup/rollup-linux-arm-gnueabihf@4.64.9': + resolution: {integrity: sha512-b50NS9TbAEK/b16vBoKrkeNwy+HvGBXmtBbzX4wcodWOh9dQZvRTN9rUyElIXa36QnwXhU9PAVVkZpqRzSi2Tg==} cpu: [arm] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.59.0': - resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} + '@rollup/rollup-linux-arm-musleabihf@4.64.9': + resolution: {integrity: sha512-SdqcudB/FzjLESsRMgXhV+FXGtf6usxXwlMoRW7D/XS3f9CZ4T4wycRBu2h9bVl2AOaPpunoA8ftAM/MF4altQ==} cpu: [arm] os: [linux] - libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.59.0': - resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} + '@rollup/rollup-linux-arm64-gnu@4.64.9': + resolution: {integrity: sha512-dg19FFRoovN+KZ+gMHBAq4Do8PgQmBcxpuhux57OuiR0QLavfn8uPBY8CP+UO50bO+xf0tK0GlqI/jld++5E6g==} cpu: [arm64] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.59.0': - resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} + '@rollup/rollup-linux-arm64-musl@4.64.9': + resolution: {integrity: sha512-+jyv5ofGmpAvtrzLjSr/e4syskeikEp5L82bUzB76auwOgK1VNVwZV/F2g1Pes9bhTznbejOefAqPglHSKYmTA==} cpu: [arm64] os: [linux] - libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.59.0': - resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} + '@rollup/rollup-linux-loong64-gnu@4.64.9': + resolution: {integrity: sha512-MKFXxqmkzCbtNvx/vjiJdss44eRtVabhCtDWcCFD9NHGwP+YkqnM/slnEsv/3fsoq9ukTtudraAjGhptrUPCVg==} cpu: [loong64] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.59.0': - resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} + '@rollup/rollup-linux-loong64-musl@4.64.9': + resolution: {integrity: sha512-lhARcOT6n7Ni9hpQRq8LZjbuoW+G/GXaW4Jfhx2MbmjnCj9XxLMRTceJIMpiMLQVWm+qxe7oq1sYvlIGOAW34Q==} cpu: [loong64] os: [linux] - libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.59.0': - resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} + '@rollup/rollup-linux-ppc64-gnu@4.64.9': + resolution: {integrity: sha512-oORQzGxZ1oHghJwLdwc8Ni0SY9otILAeXsWdiImTF4F5HkWJUwh5s/269PF5tYILNC1z/3RwFsrgcHPguBcb0g==} cpu: [ppc64] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.59.0': - resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} + '@rollup/rollup-linux-ppc64-musl@4.64.9': + resolution: {integrity: sha512-J2JQHQt7oR1uutd2OSwbV2Qpb2LI5gggPolbkUwDe7vn/0dnduZ0w6EIbGnZUAw7uIKaMgfVylcH6V+Aov8kRA==} cpu: [ppc64] os: [linux] - libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.59.0': - resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} + '@rollup/rollup-linux-riscv64-gnu@4.64.9': + resolution: {integrity: sha512-bWaKLrfzeQ9mOzJJxXbPgw2RH6VAaTJrb/60Tqf7YSMxubG8780Hzm7Us+D6qVW8QRGJYl4VUvVXxnRB0o9zvQ==} cpu: [riscv64] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.59.0': - resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} + '@rollup/rollup-linux-riscv64-musl@4.64.9': + resolution: {integrity: sha512-TFJyaCB9NsvSyvVGQgTSRD9XgxsAq99ivDDkt9KAySlrNW5Obsd1kQpvoCvBCOLq+JlJTjmtroLH0wp8M8mEsA==} cpu: [riscv64] os: [linux] - libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.59.0': - resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} + '@rollup/rollup-linux-s390x-gnu@4.64.9': + resolution: {integrity: sha512-DvmOM5xz/wDnUJFVjqP32ahalxn7BDuvO25bpuFOrb50AIFCCcFPN4lWWUDD1c8Ddv9sMO9SXyqtOet8G8u9cQ==} cpu: [s390x] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.59.0': - resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} + '@rollup/rollup-linux-x64-gnu@4.64.9': + resolution: {integrity: sha512-aFzokHK3yE00mzAvKm/PY76OsOOTjvoTGE82Vp89iBDyD2wUBlV4ZsR2tWkRECTEFk6TC4Yc3zaEWjPqq1vstQ==} cpu: [x64] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.59.0': - resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} + '@rollup/rollup-linux-x64-musl@4.64.9': + resolution: {integrity: sha512-t/yMdeaaQUuNNpmT7taBmH2VvHzgT4YA/IaKVE3qVr4PYQemn/kmJkL4uG4UvTLcWXQd0MSoOa/3URYSWGmUEg==} cpu: [x64] os: [linux] - libc: [musl] - '@rollup/rollup-openbsd-x64@4.59.0': - resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} + '@rollup/rollup-openbsd-x64@4.64.9': + resolution: {integrity: sha512-4dnxKQ8GHARyjqAU87q5UWhywZTpIbR2VWhtACdC37GD1SGszmvb3TaBFVA4n+fnDHSKMut4ZJ63hVFwgnxVtg==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.59.0': - resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} + '@rollup/rollup-openharmony-arm64@4.64.9': + resolution: {integrity: sha512-1qdQj6IrNoR0xFvrCQHmhBXe9HMbBGNTFi+3n4jKMt2rTx4k0aeAdraZU4WDOMfL9tAwS8/TRSuquvNuPQ+Gpw==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.59.0': - resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} + '@rollup/rollup-win32-arm64-msvc@4.64.9': + resolution: {integrity: sha512-yc1GSEHIYhKGN5WSaJc+eMy8bZvzcvAmflEgFh8L3xcy8dYxGmfrudyBnBFde9f6JzOa1kFqocF8BHaWybjQoA==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.59.0': - resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} + '@rollup/rollup-win32-ia32-msvc@4.64.9': + resolution: {integrity: sha512-VzHGvosAkLIzrwqvSgJBPDmGFTF/yE8OtMT4H5z8pM1NA0NiPpvTYnUh+9xPd+d5oy/wqF317FmJ1I8Kk8pp0Q==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.59.0': - resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} + '@rollup/rollup-win32-x64-gnu@4.64.9': + resolution: {integrity: sha512-FB77txy1PiAcJgG72nOLA6R0S3PRZahs8Spx0z2yseDUkoMmJcrQghiebJ2JHZ74cCOVlX/MYd4dUbJtJJ8fow==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.59.0': - resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} + '@rollup/rollup-win32-x64-msvc@4.64.9': + resolution: {integrity: sha512-IoIgQLpK1DbOcQf1vX+i5oe5LXypsCVb1j/mU6BLAbOGmXH4E+j4kMfgZRwPYUohVBurNyVMgIKVM5dR6xA0kA==} cpu: [x64] os: [win32] '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@swc/helpers@0.5.15': - resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + '@swc/helpers@0.5.23': + resolution: {integrity: sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==} - '@tailwindcss/node@4.2.1': - resolution: {integrity: sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==} + '@tailwindcss/node@4.3.3': + resolution: {integrity: sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==} - '@tailwindcss/oxide-android-arm64@4.2.1': - resolution: {integrity: sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==} + '@tailwindcss/oxide-android-arm64@4.3.3': + resolution: {integrity: sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==} engines: {node: '>= 20'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.2.1': - resolution: {integrity: sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==} + '@tailwindcss/oxide-darwin-arm64@4.3.3': + resolution: {integrity: sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==} engines: {node: '>= 20'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.2.1': - resolution: {integrity: sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==} + '@tailwindcss/oxide-darwin-x64@4.3.3': + resolution: {integrity: sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==} engines: {node: '>= 20'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.2.1': - resolution: {integrity: sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==} + '@tailwindcss/oxide-freebsd-x64@4.3.3': + resolution: {integrity: sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==} engines: {node: '>= 20'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': - resolution: {integrity: sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': + resolution: {integrity: sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==} engines: {node: '>= 20'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': - resolution: {integrity: sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==} + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': + resolution: {integrity: sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] - libc: [glibc] - '@tailwindcss/oxide-linux-arm64-musl@4.2.1': - resolution: {integrity: sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==} + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': + resolution: {integrity: sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] - libc: [musl] - '@tailwindcss/oxide-linux-x64-gnu@4.2.1': - resolution: {integrity: sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==} + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': + resolution: {integrity: sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==} engines: {node: '>= 20'} cpu: [x64] os: [linux] - libc: [glibc] - '@tailwindcss/oxide-linux-x64-musl@4.2.1': - resolution: {integrity: sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==} + '@tailwindcss/oxide-linux-x64-musl@4.3.3': + resolution: {integrity: sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==} engines: {node: '>= 20'} cpu: [x64] os: [linux] - libc: [musl] - '@tailwindcss/oxide-wasm32-wasi@4.2.1': - resolution: {integrity: sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==} + '@tailwindcss/oxide-wasm32-wasi@4.3.3': + resolution: {integrity: sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -980,118 +994,113 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': - resolution: {integrity: sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==} + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': + resolution: {integrity: sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==} engines: {node: '>= 20'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.2.1': - resolution: {integrity: sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==} + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': + resolution: {integrity: sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==} engines: {node: '>= 20'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.2.1': - resolution: {integrity: sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==} + '@tailwindcss/oxide@4.3.3': + resolution: {integrity: sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==} engines: {node: '>= 20'} - '@tailwindcss/postcss@4.2.1': - resolution: {integrity: sha512-OEwGIBnXnj7zJeonOh6ZG9woofIjGrd2BORfvE5p9USYKDCZoQmfqLcfNiRWoJlRWLdNPn2IgVZuWAOM4iTYMw==} + '@tailwindcss/postcss@4.3.3': + resolution: {integrity: sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg==} - '@tauri-apps/api@2.10.1': - resolution: {integrity: sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==} + '@tauri-apps/api@2.12.4': + resolution: {integrity: sha512-pVmfis+4zT8H0Qhp3xPZx9Ju7kpzvA6rr/PSJPyuwfvucTQ8sVt61NYU9KMkK703UFlYadFmjKA4HhybOtN0gg==} - '@tauri-apps/cli-darwin-arm64@2.10.0': - resolution: {integrity: sha512-avqHD4HRjrMamE/7R/kzJPcAJnZs0IIS+1nkDP5b+TNBn3py7N2aIo9LIpy+VQq0AkN8G5dDpZtOOBkmWt/zjA==} + '@tauri-apps/cli-darwin-arm64@2.12.3': + resolution: {integrity: sha512-xmVNoJOOKzKLj7GLHXmXLimRby9M42aBIJa0sB80N7o24eKV5JiVmToKTRLVH9yhL05GZ/B6rSSOmbzNFJwBAA==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tauri-apps/cli-darwin-x64@2.10.0': - resolution: {integrity: sha512-keDmlvJRStzVFjZTd0xYkBONLtgBC9eMTpmXnBXzsHuawV2q9PvDo2x6D5mhuoMVrJ9QWjgaPKBBCFks4dK71Q==} + '@tauri-apps/cli-darwin-x64@2.12.3': + resolution: {integrity: sha512-URd+0usfmUQQyb5kNPiKt2OT8gp7oGU7QR+qOppB6e35mpVBFFVNhWc9oWb3p0u71fDJ09DpF4T6m9xYxoIB8g==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tauri-apps/cli-linux-arm-gnueabihf@2.10.0': - resolution: {integrity: sha512-e5u0VfLZsMAC9iHaOEANumgl6lfnJx0Dtjkd8IJpysZ8jp0tJ6wrIkto2OzQgzcYyRCKgX72aKE0PFgZputA8g==} + '@tauri-apps/cli-linux-arm-gnueabihf@2.12.3': + resolution: {integrity: sha512-0kwUVx2LbmOoTRlwF1oDww7th4/NSluv4ZBQ6KRZsFKg4g0TlTcIiJ0VehqkQYUeC9xIT1Mk6XtF52mI155VSQ==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tauri-apps/cli-linux-arm64-gnu@2.10.0': - resolution: {integrity: sha512-YrYYk2dfmBs5m+OIMCrb+JH/oo+4FtlpcrTCgiFYc7vcs6m3QDd1TTyWu0u01ewsCtK2kOdluhr/zKku+KP7HA==} + '@tauri-apps/cli-linux-arm64-gnu@2.12.3': + resolution: {integrity: sha512-gKSGDx6fx+HBLQmG6guChFdisbrCSdx9Yli+j5teOa64gm1CeM+C6NLru5Pj3ZkkEep05BmCFjxvX+cjqAycZQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] - '@tauri-apps/cli-linux-arm64-musl@2.10.0': - resolution: {integrity: sha512-GUoPdVJmrJRIXFfW3Rkt+eGK9ygOdyISACZfC/bCSfOnGt8kNdQIQr5WRH9QUaTVFIwxMlQyV3m+yXYP+xhSVA==} + '@tauri-apps/cli-linux-arm64-musl@2.12.3': + resolution: {integrity: sha512-Yr59qMy/gcvAfBuFdCGlAmGiLsYWMFDbsP4bAI6iNBzcJTGrYWZGeiQhGDo29MQwfF/NUBqyM2qljXu5tZ6wjQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] - '@tauri-apps/cli-linux-riscv64-gnu@2.10.0': - resolution: {integrity: sha512-JO7s3TlSxshwsoKNCDkyvsx5gw2QAs/Y2GbR5UE2d5kkU138ATKoPOtxn8G1fFT1aDW4LH0rYAAfBpGkDyJJnw==} + '@tauri-apps/cli-linux-riscv64-gnu@2.12.3': + resolution: {integrity: sha512-jKr0/REBMnLKC0OwPQZkyge0mKDaNZ0b/AbfGwVyCgFfwS730EVLfVDo3nt7MUu6jJaytRq08+xSj5qfy+U1+Q==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] - libc: [glibc] - '@tauri-apps/cli-linux-x64-gnu@2.10.0': - resolution: {integrity: sha512-Uvh4SUUp4A6DVRSMWjelww0GnZI3PlVy7VS+DRF5napKuIehVjGl9XD0uKoCoxwAQBLctvipyEK+pDXpJeoHng==} + '@tauri-apps/cli-linux-x64-gnu@2.12.3': + resolution: {integrity: sha512-gTkEqJAGCMROGanxHnzaJzQ+/rXl39HWVg0/hDODS1wDWBGqoceqGC6Qm1+mQbyT11xnsB8mKu/gyVID/YpFIw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] - '@tauri-apps/cli-linux-x64-musl@2.10.0': - resolution: {integrity: sha512-AP0KRK6bJuTpQ8kMNWvhIpKUkQJfcPFeba7QshOQZjJ8wOS6emwTN4K5g/d3AbCMo0RRdnZWwu67MlmtJyxC1Q==} + '@tauri-apps/cli-linux-x64-musl@2.12.3': + resolution: {integrity: sha512-T2dTxL1svRym71fZtaW4pZYXbthbfFsEJr1NeOUg/p7laWXZbUt/8DMSZf8recu9f7+1F/Lv00HtzsEu6vDO9w==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] - '@tauri-apps/cli-win32-arm64-msvc@2.10.0': - resolution: {integrity: sha512-97DXVU3dJystrq7W41IX+82JEorLNY+3+ECYxvXWqkq7DBN6FsA08x/EFGE8N/b0LTOui9X2dvpGGoeZKKV08g==} + '@tauri-apps/cli-win32-arm64-msvc@2.12.3': + resolution: {integrity: sha512-eoiQwpEZWbpsVHcM9BAzqqe4TCHszvr3rsM7pUQ4ofLK0lF1i1d/jX0Qo5DYMqcrUtwQuDdDuOCbcT0Izf1VwQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tauri-apps/cli-win32-ia32-msvc@2.10.0': - resolution: {integrity: sha512-EHyQ1iwrWy1CwMalEm9z2a6L5isQ121pe7FcA2xe4VWMJp+GHSDDGvbTv/OPdkt2Lyr7DAZBpZHM6nvlHXEc4A==} + '@tauri-apps/cli-win32-ia32-msvc@2.12.3': + resolution: {integrity: sha512-kE+KUg6Dbbkgvcw0m99wJVIToFQzJqpMBAXah74WqxaLzssNwSTUccrHp6+QVzMhjQP330tvekFmnQF+0NbE6Q==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@tauri-apps/cli-win32-x64-msvc@2.10.0': - resolution: {integrity: sha512-NTpyQxkpzGmU6ceWBTY2xRIEaS0ZLbVx1HE1zTA3TY/pV3+cPoPPOs+7YScr4IMzXMtOw7tLw5LEXo5oIG3qaQ==} + '@tauri-apps/cli-win32-x64-msvc@2.12.3': + resolution: {integrity: sha512-L7wndWAgX2mLW7alswpL3d1R0P9FN2WYBgHaQkAYEBxHHGkY4vFX9CjcRQ1LAxDAMIJxrY7/aDziFJeChS84NQ==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tauri-apps/cli@2.10.0': - resolution: {integrity: sha512-ZwT0T+7bw4+DPCSWzmviwq5XbXlM0cNoleDKOYPFYqcZqeKY31KlpoMW/MOON/tOFBPgi31a2v3w9gliqwL2+Q==} + '@tauri-apps/cli@2.12.3': + resolution: {integrity: sha512-f7/LsY74SVb1ChmOPw1ajOpxii0GSzDAgmWHRci8JUYuuai04rXsSbFobpmB0sP2DdlvMD/B5ZotEn8GOGMRUg==} engines: {node: '>= 10'} hasBin: true - '@tauri-apps/plugin-clipboard-manager@2.3.2': - resolution: {integrity: sha512-CUlb5Hqi2oZbcZf4VUyUH53XWPPdtpw43EUpCza5HWZJwxEoDowFzNUDt1tRUXA8Uq+XPn17Ysfptip33sG4eQ==} + '@tauri-apps/plugin-clipboard-manager@2.5.0': + resolution: {integrity: sha512-dibUy1nKURYDXRMvjNk4deAbTZ5jPQ8wCE4nolt5xniryWgXQ4sK2GkFXoXlHbRdPzfZptZj95BRLfalA7m/2Q==} - '@tauri-apps/plugin-dialog@2.6.0': - resolution: {integrity: sha512-q4Uq3eY87TdcYzXACiYSPhmpBA76shgmQswGkSVio4C82Sz2W4iehe9TnKYwbq7weHiL88Yw19XZm7v28+Micg==} + '@tauri-apps/plugin-dialog@2.8.3': + resolution: {integrity: sha512-Hd/yBfk2R5v2MFrz/0VArSXeh8xKLLXGunqSiTtcHKn1zNZwaKujuA0VSwUvNfwC4hDoF1PveS+gBDNe3nHspw==} - '@tauri-apps/plugin-http@2.5.7': - resolution: {integrity: sha512-+F2lEH/c9b0zSsOXKq+5hZNcd9F4IIKCK1T17RqMwpCmVnx2aoqY8yIBccCd25HTYUb3j6NPVbRax/m00hKG8A==} + '@tauri-apps/plugin-http@2.8.3': + resolution: {integrity: sha512-MrgCnnxSnzxkMX+Tk1XXB8rSI9hfhUHQmtbn0EpflEDcSx04K1BDfrv51tcK27SCuU/B1j8sNHL0UZur/1iqKA==} - '@tauri-apps/plugin-shell@2.3.5': - resolution: {integrity: sha512-jewtULhiQ7lI7+owCKAjc8tYLJr92U16bPOeAa472LHJdgaibLP83NcfAF2e+wkEcA53FxKQAZ7byDzs2eeizg==} + '@tauri-apps/plugin-shell@2.5.0': + resolution: {integrity: sha512-FZ6RtcikCxJ35do1kfqi94Fknmc7DAK4mJxDRfNBInX24TQMsMLddM5i4XLqE8VvJ+Lg6EriiDcLs7JIfuFkWw==} - '@tauri-apps/plugin-window-state@2.4.1': - resolution: {integrity: sha512-OuvdrzyY8Q5Dbzpj+GcrnV1iCeoZbcFdzMjanZMMcAEUNy/6PH5pxZPXpaZLOR7whlzXiuzx0L9EKZbH7zpdRw==} + '@tauri-apps/plugin-window-state@2.5.0': + resolution: {integrity: sha512-ySI/32fpC1ZTslIZ00/wf9HujyDnkG3OPL16uuLjG53y1hTgjIJ9G2VPuOL1IV8GVr3xeF6lnr6h2T73HuGXow==} '@testing-library/dom@10.4.1': resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} @@ -1101,8 +1110,8 @@ packages: resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} engines: {node: '>=14', npm: '>=6', yarn: '>=1'} - '@testing-library/react@16.3.2': - resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==} + '@testing-library/react@16.3.3': + resolution: {integrity: sha512-Uo193NgQbPMz6lrrhtRQQFcMC6Re/ELLFbbuVL30WDlZxlpZf9/lMHTAVxPRLw1q1iu9OJmR1c2BLiENRstdBg==} engines: {node: '>=18'} peerDependencies: '@testing-library/dom': ^10.0.0 @@ -1132,122 +1141,122 @@ packages: '@types/esrecurse@4.3.1': resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/node@25.3.3': - resolution: {integrity: sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==} + '@types/node@25.9.9': + resolution: {integrity: sha512-b4e2xxj/yMeT2hNlD6x7zNFiQK2Dlmkb9CQ6v3/1G2RezKN4YS2lcEv8lzGm1mhs4f2lM4yNAMI/zUDBZBBt7w==} - '@types/react-dom@19.2.3': - resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + '@types/react-dom@19.3.0': + resolution: {integrity: sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==} peerDependencies: - '@types/react': ^19.2.0 + '@types/react': ^19.3.0 - '@types/react@19.2.14': - resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + '@types/react@19.3.0': + resolution: {integrity: sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==} '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - '@typescript-eslint/eslint-plugin@8.56.1': - resolution: {integrity: sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==} + '@typescript-eslint/eslint-plugin@8.71.2': + resolution: {integrity: sha512-K72/pvT7qpm8q3k8G5u93NCSN1RcLxX5h7Gw0bQpbMXviBHeY6Nx1WEwmk9wP+eKTSQ8ecxvcgt/ZX/rB938xQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.56.1 + '@typescript-eslint/parser': ^8.71.2 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.56.1': - resolution: {integrity: sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==} + '@typescript-eslint/parser@8.71.2': + resolution: {integrity: sha512-aTtmZjp/x3gsGHkDs04/1I8kNogBJkpQaeGaN0PfiG43NzDEmW2n+OP5im9wfsvyX0yP1UZWBrAGtDBfH9jEVw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.56.1': - resolution: {integrity: sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==} + '@typescript-eslint/project-service@8.71.2': + resolution: {integrity: sha512-Pd68GsLVh5ZXlcEccFPdhSOvtHZ/2WU0XsA8zmXOS3F158lVlcTLhfQ6qvtL1RzbMie0Kp8xtbVwAg4nejKPHw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.56.1': - resolution: {integrity: sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==} + '@typescript-eslint/scope-manager@8.71.2': + resolution: {integrity: sha512-YF4wgg5iUX5Obywoac27B56FhozMNFhdJSbh11H5GBAwmBtfyRhmgTQqW9tRNNmHDvsZ2CX6UGzoz+YfYn2Leg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.56.1': - resolution: {integrity: sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==} + '@typescript-eslint/tsconfig-utils@8.71.2': + resolution: {integrity: sha512-jz49TAWokm/7yWD9/o837nYax9DyALxIPOImdImvVzo6canBCZYzin8zJyqNR5k1j9K1DE0bVvr0XYB+99uAdg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.56.1': - resolution: {integrity: sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==} + '@typescript-eslint/type-utils@8.71.2': + resolution: {integrity: sha512-cC8UaalCViJkb3rH/xLIvidEwoFRtMZMUqDjjJMGEKaTFwYRHYBcoczlEGHuvkHEO8svRDrgZ0yQgOArFmwang==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.56.1': - resolution: {integrity: sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==} + '@typescript-eslint/types@8.71.2': + resolution: {integrity: sha512-y5Ukl3oVp7e/VGxqIoEXoeb/Roj71PAJ4WG/N/RGj+eeDvKRLM15kGr9MijLbN0i03S52zxu31Z98E5gWChJKw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.56.1': - resolution: {integrity: sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==} + '@typescript-eslint/typescript-estree@8.71.2': + resolution: {integrity: sha512-DgNOEsl4pdYzwSL+N/Cl33tX1Hlw3FvId73LnKXfq7jnrF2viOEn7X+P7RBkkSWCVm92gnWd28GIC5vJuLREeA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.56.1': - resolution: {integrity: sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==} + '@typescript-eslint/utils@8.71.2': + resolution: {integrity: sha512-RyKa1G1M9rKHDhrk+HJtiF1MvLD5Ux2JW3TSkzw+02pRALdpJb+QzG1Y5em+LvCgzGwgg8H7mBRFKljNz7ImPw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.56.1': - resolution: {integrity: sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==} + '@typescript-eslint/visitor-keys@8.71.2': + resolution: {integrity: sha512-zozlN0UA32bSG2zkKAgQyRYSbEISVoyU6vvkKYo2aSny74D8Jh4e+POkJ6Lk0dlezZi5x7TtD+88Xb06IB8nhg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@vitest/coverage-v8@4.0.18': - resolution: {integrity: sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==} + '@vitest/coverage-v8@4.1.12': + resolution: {integrity: sha512-6S7/iVknKglLAxMFxQGNppBI0iqJS2NgM6FBxavitj7KaDq/vywOWGf6dGu7F2L1Qy0G6S3uTp7aGshHrzK8JA==} peerDependencies: - '@vitest/browser': 4.0.18 - vitest: 4.0.18 + '@vitest/browser': 4.1.12 + vitest: 4.1.12 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@4.0.18': - resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} + '@vitest/expect@4.1.12': + resolution: {integrity: sha512-vFlTt+YEu9WBpNjdGayNmlMVzrWPi1+sv853/7t2FU7hpO5gAFBKHzQmkCq5Xjpr+evegF2994LQT3hF3mRlqQ==} - '@vitest/mocker@4.0.18': - resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==} + '@vitest/mocker@4.1.12': + resolution: {integrity: sha512-fKShNpKZzupWZuY0z7egydvL0sqW4INEZBEExMBMAa6izlENEVHwoXgdaTCaBZ5fwlr4xf2o1wXC83n9RpO+NA==} peerDependencies: msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0-0 + vite: ^7.3.5 peerDependenciesMeta: msw: optional: true vite: optional: true - '@vitest/pretty-format@4.0.18': - resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} + '@vitest/pretty-format@4.1.12': + resolution: {integrity: sha512-XW9O8+Mxx4VpCtkYdMJLZQQwsVryP9wk7cPKDxtXFfwSak6yRh5+2fep/Y0XF/ElBvJHq8bcYdi6aeuai0opZA==} - '@vitest/runner@4.0.18': - resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==} + '@vitest/runner@4.1.12': + resolution: {integrity: sha512-NKlVKCr5QnCe8jijdMnmkpHHU+WTqiLFR6G0pHji9uRjXK9xJl1k1nTw6F3pOOj2PDcsDt2GKQMI7wIsaT491w==} - '@vitest/snapshot@4.0.18': - resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} + '@vitest/snapshot@4.1.12': + resolution: {integrity: sha512-ko1y1Qgb/slzQ9mr+b89Cuqud8WG1TKtsPD8r7ZUBdvVOGt85Af2HwCqHujrhwJq95hs/9RM7fcAPg57o1vlzw==} - '@vitest/spy@4.0.18': - resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==} + '@vitest/spy@4.1.12': + resolution: {integrity: sha512-RGq9x4JNGNTZHEJxvN0oSiJjeSCExm0n2gZKKJZHY9cX5AVA6M7VJILBT3ZJ/tJ/0J9uWT7fETV9/btoi//vSg==} - '@vitest/utils@4.0.18': - resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} + '@vitest/utils@4.1.12': + resolution: {integrity: sha512-Q3awXrwOfEV+qc3WmO5ONyE0yO7Q1gQ9/oyHxGLZ/pl7N3NO/ZztqQwKLuwMkV+CA1JYSIeO3gkHnRDIo4AVaA==} '@xterm/addon-fit@0.11.0': resolution: {integrity: sha512-jYcgT6xtVYhnhgxh3QgYDnnNMYTcf8ElbxxFzX0IZo+vabQqSPAjC3c1wJrKB5E19VwQei89QCiZZP86DCPF7g==} @@ -1263,8 +1272,8 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.16.0: - resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + acorn@8.19.0: + resolution: {integrity: sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==} engines: {node: '>=0.4.0'} hasBin: true @@ -1272,8 +1281,8 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - ajv@6.14.0: - resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} ansi-escapes@7.3.0: resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} @@ -1283,8 +1292,8 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-regex@6.2.2: - resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + ansi-regex@6.4.0: + resolution: {integrity: sha512-KzTVk2tCWAHtYrvvvaP8bJKJq2pVinhLcGEQdtLIYPbmNGNyYe8QwNaTUYQp2J7/vIsUKt5QCqAfUkYyG9DkOw==} engines: {node: '>=12'} ansi-styles@5.2.0: @@ -1306,39 +1315,38 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - ast-v8-to-istanbul@0.3.12: - resolution: {integrity: sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==} + ast-v8-to-istanbul@1.0.7: + resolution: {integrity: sha512-kFL68AG6ajd8fg248zwM9GQrUWEp79gsmjum34OEXjs4yHuUMZfYKwOLW9GMmB4oNvVrj+EAGxsP7ye2UR9UlA==} balanced-match@4.0.4: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} - baseline-browser-mapping@2.10.0: - resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==} + baseline-browser-mapping@2.11.29: + resolution: {integrity: sha512-YeesxhUmR4h5y5V8KF8iBCqJb8YFrBJ++XBTeGcWIaQOYXGN19JM0FoiOjAhwuDoln8owMgXcWBmgHtYSkky2w==} engines: {node: '>=6.0.0'} hasBin: true - bidi-js@1.0.3: - resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + bidi-js@1.1.0: + resolution: {integrity: sha512-fX1Onk0tdVPC7obPWB5EbJ1z7NVhLq4m2xZLq2YXBkxzMXIGRpNMU88n0EPgWseKl12J7zXs7qrDxPK4sRs2fg==} - brace-expansion@5.0.4: - resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} - engines: {node: 18 || 20 || >=22} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} + brace-expansion@5.0.12: + resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==} + engines: {node: 20 || >=22} - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + browserslist@4.29.3: + resolution: {integrity: sha512-1R4kiYKXGViqEN0CnoDrXc1StD9niAwu+j2dukWzrD4bJgsD4lDmEp0CRbc6E/vYJIfTHwPmwyaKtVSudICdPA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - caniuse-lite@1.0.30001775: - resolution: {integrity: sha512-s3Qv7Lht9zbVKE9XoTyRG6wVDCKdtOFIjBGg3+Yhn6JaytuNKPIjBMTMIY1AnOH3seL5mvF+x33oGAyK3hVt3A==} + cacheable@2.5.0: + resolution: {integrity: sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==} + + caniuse-lite@1.0.30001816: + resolution: {integrity: sha512-+8Yx7BXCoqk6IF8yTicjfUR6D/ldJzdlsodlEOiOSPmhK844WIgk67/zIQaGAOxNkZyyvBlrRFnLvqKIoqbAFw==} - chai@6.2.2: - resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + chai@6.3.0: + resolution: {integrity: sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==} engines: {node: '>=18'} cli-cursor@5.0.0: @@ -1386,8 +1394,8 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - css-tree@3.2.0: - resolution: {integrity: sha512-t99A4LolkP0ZX9WUoaHz4YrPT1FKNlV8IDCeCPPpGaWyxegh64tt/BSUqN3u5necrYRon+ddZ6mPMjxIlfpobg==} + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} css.escape@1.5.1: @@ -1433,35 +1441,32 @@ packages: dom-accessibility-api@0.6.3: resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} - dompurify@3.2.7: - resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==} + dompurify@3.4.17: + resolution: {integrity: sha512-B/pSlYVHQ58kqISD/yDjuJ1yfzI34m1gF4lAod2bwSRhiN4K5Cl3H8Af7hqB2PmTL911tdEudnnXn5FnhRoz0w==} - dompurify@3.3.1: - resolution: {integrity: sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==} - - electron-to-chromium@1.5.307: - resolution: {integrity: sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==} + electron-to-chromium@1.5.459: + resolution: {integrity: sha512-4SC9HHSFjO/liAhifpdOL5hG9b4BP7/5G3y3UPZVO8trlAXr1CaUEEJL0gWK3kOcYcZrOA5rkwG45Gra/lTIgg==} emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} - enhanced-resolve@5.20.0: - resolution: {integrity: sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==} + enhanced-resolve@5.26.0: + resolution: {integrity: sha512-9vhedylFonb2YGogzUKX6+Ja72gOJbN1QHAqdrvqLwhdl/QWbKopzoUC9EbQNVsAns/bx/4uyqalrQAoy1IByw==} engines: {node: '>=10.13.0'} - entities@6.0.1: - resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} - engines: {node: '>=0.12'} + entities@8.1.0: + resolution: {integrity: sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==} + engines: {node: '>=20.19.0'} environment@1.1.0: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} engines: {node: '>=18'} - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-module-lexer@2.3.2: + resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} - esbuild@0.27.3: - resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} engines: {node: '>=18'} hasBin: true @@ -1479,14 +1484,14 @@ packages: peerDependencies: eslint: '>=7.0.0' - eslint-plugin-react-hooks@7.0.1: - resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==} + eslint-plugin-react-hooks@7.1.1: + resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} engines: {node: '>=18'} peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 - eslint-scope@9.1.1: - resolution: {integrity: sha512-GaUN0sWim5qc8KVErfPBWmc31LEsOkrUJbvJZV+xuL3u2phMUK4HIvXlWAakfC8W4nzlK+chPEAkYOYb5ZScIw==} + eslint-scope@9.1.2: + resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} eslint-visitor-keys@3.4.3: @@ -1497,8 +1502,8 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@10.0.2: - resolution: {integrity: sha512-uYixubwmqJZH+KLVYIVKY1JQt7tysXhtj21WSvjcSmU5SVNzMus1bgLe+pAt816yQ8opKfheVVoPLqvVMGejYw==} + eslint@10.13.0: + resolution: {integrity: sha512-UohDjD4zSzEwhf58M3O7vc/ycc8O1I7dNlhtD0WxE8Px8EHNJKtUwzBqrzeGhisRuv2ag4sAYswszCJRgKXYUg==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: @@ -1507,8 +1512,8 @@ packages: jiti: optional: true - espree@11.1.1: - resolution: {integrity: sha512-AVHPqQoZYc+RUM4/3Ly5udlZY/U4LS8pIG05jEjWM2lQMU/oaZ7qshzAl2YP1tfNmXfftH3ohurfwNAug+MnsQ==} + espree@11.2.0: + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} esquery@1.7.0: @@ -1533,8 +1538,8 @@ packages: eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} - expect-type@1.3.0: - resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} engines: {node: '>=12.0.0'} fast-deep-equal@3.1.3: @@ -1555,27 +1560,21 @@ packages: picomatch: optional: true - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} + file-entry-cache@11.1.5: + resolution: {integrity: sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==} find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} + flat-cache@6.1.23: + resolution: {integrity: sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==} - flatted@3.3.4: - resolution: {integrity: sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==} + flatted@3.4.4: + resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} - framer-motion@12.34.4: - resolution: {integrity: sha512-q1PwNhc1XJ3qYG7nc9+pEU5P3tnjB6Eh9vv5gGzy61nedDLB4+xk5peMCWhKM0Zn6sfhgunf/q9n0UgCoyKOBA==} + framer-motion@12.43.0: + resolution: {integrity: sha512-1eaL3RvR/kAlbG7UYcpMptEyzPoENO0c6w7ZnB3/hh2vSAz/6uGAFn6fdoqTBguNstf3MsFhJHsD/0DHiclG+g==} peerDependencies: '@emotion/is-prop-valid': '*' react: ^18.0.0 || ^19.0.0 @@ -1597,8 +1596,8 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - get-east-asian-width@1.5.0: - resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} + get-east-asian-width@1.7.0: + resolution: {integrity: sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q==} engines: {node: '>=18'} glob-parent@6.0.2: @@ -1612,12 +1611,22 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + hashery@1.5.1: + resolution: {integrity: sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==} + engines: {node: '>=20'} + hermes-estree@0.25.1: resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + hookified@1.15.1: + resolution: {integrity: sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==} + + hookified@2.2.0: + resolution: {integrity: sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==} + html-encoding-sniffer@6.0.0: resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} @@ -1642,8 +1651,8 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + ignore@7.0.12: + resolution: {integrity: sha512-/8UvqAPU9DGTI9k4mxtf49U37Isfwr8Uts96+SBHIkFxPJnHS0Ew4f00sM4Scd8V8EjM0jUNtVDdv1kPdt35lg==} engines: {node: '>= 4'} imurmurhash@0.1.4: @@ -1666,10 +1675,6 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} @@ -1688,8 +1693,8 @@ packages: resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} engines: {node: '>=8'} - jiti@2.6.1: - resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true js-tokens@10.0.0: @@ -1712,9 +1717,6 @@ packages: engines: {node: '>=6'} hasBin: true - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -1726,89 +1728,85 @@ packages: engines: {node: '>=6'} hasBin: true - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + keyv@5.6.0: + resolution: {integrity: sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==} levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lightningcss-android-arm64@1.31.1: - resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.31.1: - resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==} + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.31.1: - resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==} + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.31.1: - resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==} + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.31.1: - resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==} + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.31.1: - resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==} + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] - lightningcss-linux-arm64-musl@1.31.1: - resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [musl] - lightningcss-linux-x64-gnu@1.31.1: - resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [glibc] - lightningcss-linux-x64-musl@1.31.1: - resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [musl] - lightningcss-win32-arm64-msvc@1.31.1: - resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.31.1: - resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==} + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.31.1: - resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==} + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} - lint-staged@16.3.2: - resolution: {integrity: sha512-xKqhC2AeXLwiAHXguxBjuChoTTWFC6Pees0SHPwOpwlvI3BH7ZADFPddAdN3pgo3aiKgPUx/bxE78JfUnxQnlg==} + lint-staged@16.4.0: + resolution: {integrity: sha512-lBWt8hujh/Cjysw5GYVmZpFHXDCgZzhrOm8vbcUdobADZNOK/bRshr2kM3DfgrrtR1DQhfupW9gnIXOfiFi+bw==} engines: {node: '>=20.17'} hasBin: true @@ -1824,8 +1822,8 @@ packages: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} - lru-cache@11.2.6: - resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} + lru-cache@11.5.3: + resolution: {integrity: sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==} engines: {node: 20 || >=22} lru-cache@5.1.1: @@ -1838,8 +1836,8 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - magicast@0.5.2: - resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==} + magicast@0.5.5: + resolution: {integrity: sha512-UicdXN8zQ3JHlxVq+28afMXPr1z7WNY6+7EJnzTdQWkTAlMLF5fNCCKxJHBQwGaNGR11581EiQmQzx73+MvszA==} make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} @@ -1853,10 +1851,6 @@ packages: mdn-data@2.27.1: resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - mimic-function@5.0.1: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} @@ -1865,32 +1859,32 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} - minimatch@10.2.4: - resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} engines: {node: 18 || 20 || >=22} monaco-editor@0.55.1: resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==} - motion-dom@12.34.3: - resolution: {integrity: sha512-sYgFe+pR9aIM7o4fhs2aXtOI+oqlUd33N9Yoxcgo1Fv7M20sRkHtCmzE/VRNIcq7uNJ+qio+Xubt1FXH3pQ+eQ==} + motion-dom@12.43.0: + resolution: {integrity: sha512-azKON4d9S65PEoFUiQTMTgPheEmzf2QngdRc50AKfJp9Q9mmcBVw22c8eMq9k8kxOFHdL7+WZY7N/5F/lwiDag==} - motion-utils@12.29.2: - resolution: {integrity: sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A==} + motion-utils@12.39.0: + resolution: {integrity: sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==} ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + nanoid@3.3.20: + resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - next@16.1.6: - resolution: {integrity: sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==} + next@16.4.2: + resolution: {integrity: sha512-r+oBJojfefUjOiWkBhXgLS+igxX/7BWyK59uHnyOyplMSLtBZ+QLP3okrdYTbrfrbrmNTVWLBPaHDX9KRaIt3w==} engines: {node: '>=20.9.0'} hasBin: true peerDependencies: @@ -1910,11 +1904,13 @@ packages: sass: optional: true - node-releases@2.0.36: - resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} + node-releases@2.0.59: + resolution: {integrity: sha512-5qr2okC4ItAI0hG5SaV0HoYMpnM/Y6+Oqr7AmPYy/2uEoGvS+GbSKLeRxSS1uAdu59yz0ouzcuXievSgg///WA==} + engines: {node: '>=18'} - obug@2.1.1: - resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + obug@2.2.1: + resolution: {integrity: sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==} + engines: {node: '>=12.20.0'} onetime@7.0.0: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} @@ -1932,8 +1928,8 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - parse5@8.0.0: - resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} + parse5@8.0.1: + resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} @@ -1949,28 +1945,24 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} engines: {node: '>=12'} - postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + postcss@8.5.23: + resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} engines: {node: ^10 || ^12 || >=14} - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + postcss@8.5.30: + resolution: {integrity: sha512-zkd+e9S1AQHhmaBKye9zlFHWjOwVgqXl1q3ECYy8561K7qxR2cREf/STLskulBFd78k6AOFeA+ff1TtEzk9bAA==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.8.1: - resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + prettier@3.9.10: + resolution: {integrity: sha512-skGHTH1Yb9QvaTC4hWnRTzEYtCpApF0UMBPz+t/0ZPzP8ihefo/btKd+QA7pUE0fEwA1SbS/NmhyEcstdXOIdA==} engines: {node: '>=14'} hasBin: true @@ -1982,21 +1974,25 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + qified@0.10.1: + resolution: {integrity: sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==} + engines: {node: '>=20'} + qrcode.react@4.2.0: resolution: {integrity: sha512-QpgqWi8rD9DsS9EP3z7BT+5lY5SFhsqGjpgW5DY/i3mK4M9DTBNz3ErMi8BWYEfI3L0d8GIbGmcdFAS1uIRGjA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom@19.2.4: - resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} + react-dom@19.3.1: + resolution: {integrity: sha512-Y0bARz53lhEC1NMCASs0/j+faB/zqt3R8hpvg1e8+61ZVJ4UL0UdC4cBbXfZMcIuhrfgeILTLe+ZeBCavQPtKQ==} peerDependencies: - react: ^19.2.4 + react: ^19.3.1 react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - react@19.2.4: - resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + react@19.3.1: + resolution: {integrity: sha512-QNhWdt7nrgVWWQG58QuGsAR3jv3Hbe4mb4vz7w2csnHavciZJgda1CPNaldF6eVxv90ud3jUXpKlHL69gO38yw==} engines: {node: '>=0.10.0'} redent@3.0.0: @@ -2014,8 +2010,8 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rollup@4.59.0: - resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} + rollup@4.64.9: + resolution: {integrity: sha512-mnPSQINChN7PpT+a5CI0/+87hm/+6zxSKBK1XonrzQ0zFnglaTjhkTP2Br4yNCTcLHUEvrAfZffH57jGf+8xBQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2023,21 +2019,26 @@ packages: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} - scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + scheduler@0.28.0: + resolution: {integrity: sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==} semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.7.4: - resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} hasBin: true - sharp@0.34.5: - resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + sharp@0.35.5: + resolution: {integrity: sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==} + engines: {node: '>=20.9.0'} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} @@ -2062,8 +2063,8 @@ packages: resolution: {integrity: sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==} engines: {node: '>=20'} - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + source-map-js@1.2.2: + resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} engines: {node: '>=0.10.0'} stackback@0.0.2: @@ -2072,8 +2073,8 @@ packages: state-local@1.0.7: resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + std-env@4.3.0: + resolution: {integrity: sha512-OtU/EgQ1kIm5KwqQpBC6ZEMXrZRui11w8zgfTWp8cdO9B8OaPsbA8bTHO2P+HNo1VlUTGMVBwPhydu6poeXiag==} string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} @@ -2083,8 +2084,8 @@ packages: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} - string-width@8.2.0: - resolution: {integrity: sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==} + string-width@8.3.0: + resolution: {integrity: sha512-ZbmZM0JCihQN91dWnxoipT2KOEyHqEyfRXUyjuRhW8b/xnqPDoq4gWEVApTVa9db2wN8mmoikgFBbjh71+cGeQ==} engines: {node: '>=20'} strip-ansi@7.2.0: @@ -2115,49 +2116,45 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - tailwindcss@4.2.1: - resolution: {integrity: sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==} + tailwindcss@4.3.3: + resolution: {integrity: sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==} - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@1.0.2: - resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + tinyexec@1.3.1: + resolution: {integrity: sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==} engines: {node: '>=18'} - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} - tinyrainbow@3.0.3: - resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + tinyrainbow@3.2.0: + resolution: {integrity: sha512-LgO3D9yZJjApUiuUfl9iFAwrtaX4+lok3wJIqttGoKCHlWUqHqbQpnxCf82L8FjgKsh4iGo78hqJwgL8F6To2A==} engines: {node: '>=14.0.0'} - tldts-core@7.0.24: - resolution: {integrity: sha512-pj7yygNMoMRqG7ML2SDQ0xNIOfN3IBDUcPVM2Sg6hP96oFNN2nqnzHreT3z9xLq85IWJyNTvD38O002DdOrPMw==} + tldts-core@7.4.18: + resolution: {integrity: sha512-KI2PKvCmvQI/xD6ypPqkU0i7oxNXR/O58RLRaHR4svsgVUQ2JE/XC8BtMbG6PSehD27I8sZJRcC1ASnCy6lp3g==} - tldts@7.0.24: - resolution: {integrity: sha512-1r6vQTTt1rUiJkI5vX7KG8PR342Ru/5Oh13kEQP2SMbRSZpOey9SrBe27IDxkoWulx8ShWu4K6C0BkctP8Z1bQ==} + tldts@7.4.18: + resolution: {integrity: sha512-somxA8xKAUzlAxl0TX/jMSYIbRNFIVGnI96pVGJPeMc5BsHmfVXn6mOJT6U++ELnl04eGfzpfcEuZe8WiASkXg==} hasBin: true - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - tough-cookie@6.0.0: - resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} + tough-cookie@6.0.2: + resolution: {integrity: sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==} engines: {node: '>=16'} tr46@6.0.0: resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} engines: {node: '>=20'} - ts-api-utils@2.4.0: - resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' @@ -2172,27 +2169,27 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - typescript-eslint@8.56.1: - resolution: {integrity: sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==} + typescript-eslint@8.71.2: + resolution: {integrity: sha512-Rz4effbMy2g9wnvOJZG6SbVavX313Lap1vNEbk1RUochzickvzP8P4HB+bkNg5e50eVz1hQGjh9K1omI1xB4Bw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true - undici-types@7.18.2: - resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + undici-types@7.24.6: + resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} - undici@7.22.0: - resolution: {integrity: sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==} + undici@7.30.1: + resolution: {integrity: sha512-03KrMbjIFDWQR5RNPrSw3bd1r12JpyFQl9/yxjUbJtqkjmllqC5lFjZh6ujeuJCKr8EOQvRW872Oy/az+nLYxg==} engines: {node: '>=20.18.1'} - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + update-browserslist-db@1.3.4: + resolution: {integrity: sha512-t8wonIOdQyOjtPd2VktlBu6QjTVTks6v8bSi7kd0r2Vll8TK1JYDZtRRdbmCHOAMphkZgrzK+L+vXK4pyZ8t4A==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -2200,8 +2197,8 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + vite@7.3.7: + resolution: {integrity: sha512-AHEzTORMbi7/7aXp7w7KZ5+DCUdSeLsJz0grY8xHpc9DHdYb0vQu6DqJfm2tOw3gDExNgPgnJTXxM6syYFHaCA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -2240,20 +2237,23 @@ packages: yaml: optional: true - vitest@4.0.18: - resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==} + vitest@4.1.12: + resolution: {integrity: sha512-5eWdz2yb3ajxWF3C8C4TjkXl7FGm3n2E/VlazALrQHzK7nYMSGFnCZto0bbPNl77AwkOZVLk0YnBAejUu0NiWA==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.18 - '@vitest/browser-preview': 4.0.18 - '@vitest/browser-webdriverio': 4.0.18 - '@vitest/ui': 4.0.18 + '@vitest/browser-playwright': 4.1.12 + '@vitest/browser-preview': 4.1.12 + '@vitest/browser-webdriverio': ^4.1.11 + '@vitest/coverage-istanbul': 4.1.12 + '@vitest/coverage-v8': 4.1.12 + '@vitest/ui': 4.1.12 happy-dom: '*' jsdom: '*' + vite: ^7.3.5 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -2267,6 +2267,10 @@ packages: optional: true '@vitest/browser-webdriverio': optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true '@vitest/ui': optional: true happy-dom: @@ -2318,8 +2322,8 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yaml@2.8.2: - resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + yaml@2.9.1: + resolution: {integrity: sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==} engines: {node: '>= 14.6'} hasBin: true @@ -2333,54 +2337,56 @@ packages: peerDependencies: zod: ^3.25.0 || ^4.0.0 - zod@4.3.6: - resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + zod@4.6.7: + resolution: {integrity: sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==} snapshots: - '@acemir/cssom@0.9.31': {} + '@acemir/cssom@0.9.32': {} - '@adobe/css-tools@4.4.4': {} + '@adobe/css-tools@4.5.0': {} - '@alloc/quick-lru@5.2.0': {} + '@alloc/quick-lru@5.3.0': {} - '@asamuzakjp/css-color@5.0.1': + '@asamuzakjp/css-color@5.1.11': dependencies: - '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-color-parser': 4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - lru-cache: 11.2.6 + '@asamuzakjp/generational-cache': 1.0.1 + '@csstools/css-calc': 3.4.3(@csstools/css-parser-algorithms@4.0.2(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2) + '@csstools/css-color-parser': 4.2.6(@csstools/css-parser-algorithms@4.0.2(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2) + '@csstools/css-parser-algorithms': 4.0.2(@csstools/css-tokenizer@4.0.2) + '@csstools/css-tokenizer': 4.0.2 '@asamuzakjp/dom-selector@6.8.1': dependencies: '@asamuzakjp/nwsapi': 2.3.9 - bidi-js: 1.0.3 - css-tree: 3.2.0 + bidi-js: 1.1.0 + css-tree: 3.2.1 is-potential-custom-element-name: 1.0.1 - lru-cache: 11.2.6 + lru-cache: 11.5.3 + + '@asamuzakjp/generational-cache@1.0.1': {} '@asamuzakjp/nwsapi@2.3.9': {} - '@babel/code-frame@7.29.0': + '@babel/code-frame@7.29.7': dependencies: - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-validator-identifier': 7.29.7 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.29.0': {} + '@babel/compat-data@7.29.7': {} - '@babel/core@7.29.0': + '@babel/core@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.28.6 - '@babel/parser': 7.29.0 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.10 + '@babel/parser': 7.29.9 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.10 + '@babel/types': 7.29.8 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 @@ -2390,85 +2396,97 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.29.1': + '@babel/generator@7.29.8': dependencies: - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.9 + '@babel/types': 7.29.8 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/helper-compilation-targets@7.28.6': + '@babel/helper-compilation-targets@7.29.7': dependencies: - '@babel/compat-data': 7.29.0 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.29.3 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-globals@7.28.0': {} + '@babel/helper-globals@7.29.7': {} - '@babel/helper-module-imports@7.28.6': + '@babel/helper-module-imports@7.29.7': dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/traverse': 7.29.10 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.10 transitivePeerDependencies: - supports-color - '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-string-parser@7.29.7': {} - '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-identifier@7.29.7': {} - '@babel/helper-validator-option@7.27.1': {} + '@babel/helper-validator-option@7.29.7': {} - '@babel/helpers@7.28.6': + '@babel/helpers@7.29.10': dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 - '@babel/parser@7.29.0': + '@babel/parser@7.29.9': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.8 - '@babel/runtime@7.28.6': {} + '@babel/runtime@7.29.10': {} - '@babel/template@7.28.6': + '@babel/template@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.9 + '@babel/types': 7.29.8 - '@babel/traverse@7.29.0': + '@babel/traverse@7.29.10': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.0 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.9 + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.29.0': + '@babel/types@7.29.8': dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 '@bcoe/v8-coverage@1.0.2': {} - '@bramus/specificity@2.4.2': + '@bramus/specificity@2.4.3': + dependencies: + css-tree: 3.2.1 + + '@cacheable/memory@2.2.0': dependencies: - css-tree: 3.2.0 + '@cacheable/utils': 2.5.0 + '@keyv/bigmap': 1.3.1(keyv@5.6.0) + hookified: 1.15.1 + keyv: 5.6.0 + + '@cacheable/utils@2.5.0': + dependencies: + hashery: 1.5.1 + keyv: 5.6.0 '@create-markdown/core@0.2.0': {} @@ -2476,270 +2494,287 @@ snapshots: dependencies: '@create-markdown/core': 0.2.0 - '@create-markdown/react@0.2.0(@create-markdown/core@0.2.0)(react@19.2.4)': + '@create-markdown/react@0.2.0(@create-markdown/core@0.2.0)(react@19.3.1)': dependencies: '@create-markdown/core': 0.2.0 - react: 19.2.4 + react: 19.3.1 - '@csstools/color-helpers@6.0.2': {} + '@csstools/color-helpers@6.1.2': {} - '@csstools/css-calc@3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + '@csstools/css-calc@3.4.3(@csstools/css-parser-algorithms@4.0.2(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2)': dependencies: - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 + '@csstools/css-parser-algorithms': 4.0.2(@csstools/css-tokenizer@4.0.2) + '@csstools/css-tokenizer': 4.0.2 - '@csstools/css-color-parser@4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + '@csstools/css-color-parser@4.2.6(@csstools/css-parser-algorithms@4.0.2(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2)': dependencies: - '@csstools/color-helpers': 6.0.2 - '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 + '@csstools/color-helpers': 6.1.2 + '@csstools/css-calc': 3.4.3(@csstools/css-parser-algorithms@4.0.2(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2) + '@csstools/css-parser-algorithms': 4.0.2(@csstools/css-tokenizer@4.0.2) + '@csstools/css-tokenizer': 4.0.2 - '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + '@csstools/css-parser-algorithms@4.0.2(@csstools/css-tokenizer@4.0.2)': dependencies: - '@csstools/css-tokenizer': 4.0.0 + '@csstools/css-tokenizer': 4.0.2 - '@csstools/css-syntax-patches-for-csstree@1.0.29': {} + '@csstools/css-syntax-patches-for-csstree@1.1.15(css-tree@3.2.1)': + optionalDependencies: + css-tree: 3.2.1 - '@csstools/css-tokenizer@4.0.0': {} + '@csstools/css-tokenizer@4.0.2': {} - '@emnapi/runtime@1.8.1': + '@emnapi/runtime@1.11.3': dependencies: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.27.3': + '@esbuild/aix-ppc64@0.28.2': optional: true - '@esbuild/android-arm64@0.27.3': + '@esbuild/android-arm64@0.28.2': optional: true - '@esbuild/android-arm@0.27.3': + '@esbuild/android-arm@0.28.2': optional: true - '@esbuild/android-x64@0.27.3': + '@esbuild/android-x64@0.28.2': optional: true - '@esbuild/darwin-arm64@0.27.3': + '@esbuild/darwin-arm64@0.28.2': optional: true - '@esbuild/darwin-x64@0.27.3': + '@esbuild/darwin-x64@0.28.2': optional: true - '@esbuild/freebsd-arm64@0.27.3': + '@esbuild/freebsd-arm64@0.28.2': optional: true - '@esbuild/freebsd-x64@0.27.3': + '@esbuild/freebsd-x64@0.28.2': optional: true - '@esbuild/linux-arm64@0.27.3': + '@esbuild/linux-arm64@0.28.2': optional: true - '@esbuild/linux-arm@0.27.3': + '@esbuild/linux-arm@0.28.2': optional: true - '@esbuild/linux-ia32@0.27.3': + '@esbuild/linux-ia32@0.28.2': optional: true - '@esbuild/linux-loong64@0.27.3': + '@esbuild/linux-loong64@0.28.2': optional: true - '@esbuild/linux-mips64el@0.27.3': + '@esbuild/linux-mips64el@0.28.2': optional: true - '@esbuild/linux-ppc64@0.27.3': + '@esbuild/linux-ppc64@0.28.2': optional: true - '@esbuild/linux-riscv64@0.27.3': + '@esbuild/linux-riscv64@0.28.2': optional: true - '@esbuild/linux-s390x@0.27.3': + '@esbuild/linux-s390x@0.28.2': optional: true - '@esbuild/linux-x64@0.27.3': + '@esbuild/linux-x64@0.28.2': optional: true - '@esbuild/netbsd-arm64@0.27.3': + '@esbuild/netbsd-arm64@0.28.2': optional: true - '@esbuild/netbsd-x64@0.27.3': + '@esbuild/netbsd-x64@0.28.2': optional: true - '@esbuild/openbsd-arm64@0.27.3': + '@esbuild/openbsd-arm64@0.28.2': optional: true - '@esbuild/openbsd-x64@0.27.3': + '@esbuild/openbsd-x64@0.28.2': optional: true - '@esbuild/openharmony-arm64@0.27.3': + '@esbuild/openharmony-arm64@0.28.2': optional: true - '@esbuild/sunos-x64@0.27.3': + '@esbuild/sunos-x64@0.28.2': optional: true - '@esbuild/win32-arm64@0.27.3': + '@esbuild/win32-arm64@0.28.2': optional: true - '@esbuild/win32-ia32@0.27.3': + '@esbuild/win32-ia32@0.28.2': optional: true - '@esbuild/win32-x64@0.27.3': + '@esbuild/win32-x64@0.28.2': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.0.2(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.10.1(eslint@10.13.0(jiti@2.7.0))': dependencies: - eslint: 10.0.2(jiti@2.6.1) + eslint: 10.13.0(jiti@2.7.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.23.2': + '@eslint/config-array@0.23.5': dependencies: - '@eslint/object-schema': 3.0.2 + '@eslint/object-schema': 3.0.5 debug: 4.4.3 - minimatch: 10.2.4 + minimatch: 10.2.6 transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.5.2': + '@eslint/config-helpers@0.7.0': dependencies: - '@eslint/core': 1.1.0 + '@eslint/core': 1.2.1 - '@eslint/core@1.1.0': + '@eslint/core@1.2.1': dependencies: '@types/json-schema': 7.0.15 - '@eslint/js@10.0.1(eslint@10.0.2(jiti@2.6.1))': + '@eslint/js@10.0.1(eslint@10.13.0(jiti@2.7.0))': optionalDependencies: - eslint: 10.0.2(jiti@2.6.1) + eslint: 10.13.0(jiti@2.7.0) - '@eslint/object-schema@3.0.2': {} + '@eslint/object-schema@3.0.5': {} - '@eslint/plugin-kit@0.6.0': + '@eslint/plugin-kit@0.7.3': dependencies: - '@eslint/core': 1.1.0 + '@eslint/core': 1.2.1 levn: 0.4.1 - '@exodus/bytes@1.15.0': {} + '@exodus/bytes@1.16.0': {} - '@humanfs/core@0.19.1': {} + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 - '@humanfs/node@0.16.7': + '@humanfs/node@0.16.8': dependencies: - '@humanfs/core': 0.19.1 + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 '@humanwhocodes/retry': 0.4.3 + '@humanfs/types@0.15.0': {} + '@humanwhocodes/module-importer@1.0.1': {} '@humanwhocodes/retry@0.4.3': {} - '@iconify/react@6.0.2(react@19.2.4)': + '@iconify/react@6.0.2(react@19.3.1)': dependencies: '@iconify/types': 2.0.0 - react: 19.2.4 + react: 19.3.1 '@iconify/types@2.0.0': {} - '@img/colour@1.0.0': + '@img/colour@1.1.0': optional: true - '@img/sharp-darwin-arm64@0.34.5': + '@img/sharp-darwin-arm64@0.35.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-arm64': 1.3.4 optional: true - '@img/sharp-darwin-x64@0.34.5': + '@img/sharp-darwin-x64@0.35.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.3.4 + optional: true + + '@img/sharp-freebsd-wasm32@0.35.5': + dependencies: + '@img/sharp-wasm32': 0.35.5 optional: true - '@img/sharp-libvips-darwin-arm64@1.2.4': + '@img/sharp-libvips-darwin-arm64@1.3.4': optional: true - '@img/sharp-libvips-darwin-x64@1.2.4': + '@img/sharp-libvips-darwin-x64@1.3.4': optional: true - '@img/sharp-libvips-linux-arm64@1.2.4': + '@img/sharp-libvips-linux-arm64@1.3.4': optional: true - '@img/sharp-libvips-linux-arm@1.2.4': + '@img/sharp-libvips-linux-arm@1.3.4': optional: true - '@img/sharp-libvips-linux-ppc64@1.2.4': + '@img/sharp-libvips-linux-ppc64@1.3.4': optional: true - '@img/sharp-libvips-linux-riscv64@1.2.4': + '@img/sharp-libvips-linux-riscv64@1.3.4': optional: true - '@img/sharp-libvips-linux-s390x@1.2.4': + '@img/sharp-libvips-linux-s390x@1.3.4': optional: true - '@img/sharp-libvips-linux-x64@1.2.4': + '@img/sharp-libvips-linux-x64@1.3.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + '@img/sharp-libvips-linuxmusl-arm64@1.3.4': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.2.4': + '@img/sharp-libvips-linuxmusl-x64@1.3.4': optional: true - '@img/sharp-linux-arm64@0.34.5': + '@img/sharp-linux-arm64@0.35.5': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.3.4 optional: true - '@img/sharp-linux-arm@0.34.5': + '@img/sharp-linux-arm@0.35.5': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.3.4 optional: true - '@img/sharp-linux-ppc64@0.34.5': + '@img/sharp-linux-ppc64@0.35.5': optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.3.4 optional: true - '@img/sharp-linux-riscv64@0.34.5': + '@img/sharp-linux-riscv64@0.35.5': optionalDependencies: - '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.3.4 optional: true - '@img/sharp-linux-s390x@0.34.5': + '@img/sharp-linux-s390x@0.35.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.3.4 optional: true - '@img/sharp-linux-x64@0.34.5': + '@img/sharp-linux-x64@0.35.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.3.4 optional: true - '@img/sharp-linuxmusl-arm64@0.34.5': + '@img/sharp-linuxmusl-arm64@0.35.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.4 optional: true - '@img/sharp-linuxmusl-x64@0.34.5': + '@img/sharp-linuxmusl-x64@0.35.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.4 + optional: true + + '@img/sharp-wasm32@0.35.5': + dependencies: + '@emnapi/runtime': 1.11.3 optional: true - '@img/sharp-wasm32@0.34.5': + '@img/sharp-webcontainers-wasm32@0.35.5': dependencies: - '@emnapi/runtime': 1.8.1 + '@img/sharp-wasm32': 0.35.5 optional: true - '@img/sharp-win32-arm64@0.34.5': + '@img/sharp-win32-arm64@0.35.5': optional: true - '@img/sharp-win32-ia32@0.34.5': + '@img/sharp-win32-ia32@0.35.5': optional: true - '@img/sharp-win32-x64@0.34.5': + '@img/sharp-win32-x64@0.35.5': optional: true '@jridgewell/gen-mapping@0.3.13': dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.6.0 '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/remapping@2.3.5': @@ -2749,273 +2784,284 @@ snapshots: '@jridgewell/resolve-uri@3.1.2': {} - '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/sourcemap-codec@1.6.0': {} '@jridgewell/trace-mapping@0.3.31': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.6.0 + + '@keyv/bigmap@1.3.1(keyv@5.6.0)': + dependencies: + hashery: 1.5.1 + hookified: 1.15.1 + keyv: 5.6.0 + + '@keyv/serialize@1.1.1': {} '@monaco-editor/loader@1.7.0': dependencies: state-local: 1.0.7 - '@monaco-editor/react@4.7.0(monaco-editor@0.55.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@monaco-editor/react@4.7.0(monaco-editor@0.55.1)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)': dependencies: '@monaco-editor/loader': 1.7.0 monaco-editor: 0.55.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + optional: true - '@next/env@16.1.6': {} + '@next/env@16.4.2': {} - '@next/swc-darwin-arm64@16.1.6': + '@next/swc-darwin-arm64@16.4.2': optional: true - '@next/swc-darwin-x64@16.1.6': + '@next/swc-darwin-x64@16.4.2': optional: true - '@next/swc-linux-arm64-gnu@16.1.6': + '@next/swc-linux-arm64-gnu@16.4.2': optional: true - '@next/swc-linux-arm64-musl@16.1.6': + '@next/swc-linux-arm64-musl@16.4.2': optional: true - '@next/swc-linux-x64-gnu@16.1.6': + '@next/swc-linux-x64-gnu@16.4.2': optional: true - '@next/swc-linux-x64-musl@16.1.6': + '@next/swc-linux-x64-musl@16.4.2': optional: true - '@next/swc-win32-arm64-msvc@16.1.6': + '@next/swc-win32-arm64-msvc@16.4.2': optional: true - '@next/swc-win32-x64-msvc@16.1.6': + '@next/swc-win32-x64-msvc@16.4.2': optional: true - '@rollup/rollup-android-arm-eabi@4.59.0': + '@rollup/rollup-android-arm-eabi@4.64.9': optional: true - '@rollup/rollup-android-arm64@4.59.0': + '@rollup/rollup-android-arm64@4.64.9': optional: true - '@rollup/rollup-darwin-arm64@4.59.0': + '@rollup/rollup-darwin-arm64@4.64.9': optional: true - '@rollup/rollup-darwin-x64@4.59.0': + '@rollup/rollup-darwin-x64@4.64.9': optional: true - '@rollup/rollup-freebsd-arm64@4.59.0': + '@rollup/rollup-freebsd-arm64@4.64.9': optional: true - '@rollup/rollup-freebsd-x64@4.59.0': + '@rollup/rollup-freebsd-x64@4.64.9': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': + '@rollup/rollup-linux-arm-gnueabihf@4.64.9': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.59.0': + '@rollup/rollup-linux-arm-musleabihf@4.64.9': optional: true - '@rollup/rollup-linux-arm64-gnu@4.59.0': + '@rollup/rollup-linux-arm64-gnu@4.64.9': optional: true - '@rollup/rollup-linux-arm64-musl@4.59.0': + '@rollup/rollup-linux-arm64-musl@4.64.9': optional: true - '@rollup/rollup-linux-loong64-gnu@4.59.0': + '@rollup/rollup-linux-loong64-gnu@4.64.9': optional: true - '@rollup/rollup-linux-loong64-musl@4.59.0': + '@rollup/rollup-linux-loong64-musl@4.64.9': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.59.0': + '@rollup/rollup-linux-ppc64-gnu@4.64.9': optional: true - '@rollup/rollup-linux-ppc64-musl@4.59.0': + '@rollup/rollup-linux-ppc64-musl@4.64.9': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.59.0': + '@rollup/rollup-linux-riscv64-gnu@4.64.9': optional: true - '@rollup/rollup-linux-riscv64-musl@4.59.0': + '@rollup/rollup-linux-riscv64-musl@4.64.9': optional: true - '@rollup/rollup-linux-s390x-gnu@4.59.0': + '@rollup/rollup-linux-s390x-gnu@4.64.9': optional: true - '@rollup/rollup-linux-x64-gnu@4.59.0': + '@rollup/rollup-linux-x64-gnu@4.64.9': optional: true - '@rollup/rollup-linux-x64-musl@4.59.0': + '@rollup/rollup-linux-x64-musl@4.64.9': optional: true - '@rollup/rollup-openbsd-x64@4.59.0': + '@rollup/rollup-openbsd-x64@4.64.9': optional: true - '@rollup/rollup-openharmony-arm64@4.59.0': + '@rollup/rollup-openharmony-arm64@4.64.9': optional: true - '@rollup/rollup-win32-arm64-msvc@4.59.0': + '@rollup/rollup-win32-arm64-msvc@4.64.9': optional: true - '@rollup/rollup-win32-ia32-msvc@4.59.0': + '@rollup/rollup-win32-ia32-msvc@4.64.9': optional: true - '@rollup/rollup-win32-x64-gnu@4.59.0': + '@rollup/rollup-win32-x64-gnu@4.64.9': optional: true - '@rollup/rollup-win32-x64-msvc@4.59.0': + '@rollup/rollup-win32-x64-msvc@4.64.9': optional: true '@standard-schema/spec@1.1.0': {} - '@swc/helpers@0.5.15': + '@swc/helpers@0.5.23': dependencies: tslib: 2.8.1 - '@tailwindcss/node@4.2.1': + '@tailwindcss/node@4.3.3': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.20.0 - jiti: 2.6.1 - lightningcss: 1.31.1 + enhanced-resolve: 5.26.0 + jiti: 2.7.0 + lightningcss: 1.32.0 magic-string: 0.30.21 - source-map-js: 1.2.1 - tailwindcss: 4.2.1 + source-map-js: 1.2.2 + tailwindcss: 4.3.3 - '@tailwindcss/oxide-android-arm64@4.2.1': + '@tailwindcss/oxide-android-arm64@4.3.3': optional: true - '@tailwindcss/oxide-darwin-arm64@4.2.1': + '@tailwindcss/oxide-darwin-arm64@4.3.3': optional: true - '@tailwindcss/oxide-darwin-x64@4.2.1': + '@tailwindcss/oxide-darwin-x64@4.3.3': optional: true - '@tailwindcss/oxide-freebsd-x64@4.2.1': + '@tailwindcss/oxide-freebsd-x64@4.3.3': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.2.1': + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.2.1': + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.2.1': + '@tailwindcss/oxide-linux-x64-musl@4.3.3': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.2.1': + '@tailwindcss/oxide-wasm32-wasi@4.3.3': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.2.1': + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': optional: true - '@tailwindcss/oxide@4.2.1': + '@tailwindcss/oxide@4.3.3': optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.2.1 - '@tailwindcss/oxide-darwin-arm64': 4.2.1 - '@tailwindcss/oxide-darwin-x64': 4.2.1 - '@tailwindcss/oxide-freebsd-x64': 4.2.1 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.1 - '@tailwindcss/oxide-linux-arm64-gnu': 4.2.1 - '@tailwindcss/oxide-linux-arm64-musl': 4.2.1 - '@tailwindcss/oxide-linux-x64-gnu': 4.2.1 - '@tailwindcss/oxide-linux-x64-musl': 4.2.1 - '@tailwindcss/oxide-wasm32-wasi': 4.2.1 - '@tailwindcss/oxide-win32-arm64-msvc': 4.2.1 - '@tailwindcss/oxide-win32-x64-msvc': 4.2.1 - - '@tailwindcss/postcss@4.2.1': - dependencies: - '@alloc/quick-lru': 5.2.0 - '@tailwindcss/node': 4.2.1 - '@tailwindcss/oxide': 4.2.1 - postcss: 8.5.6 - tailwindcss: 4.2.1 - - '@tauri-apps/api@2.10.1': {} - - '@tauri-apps/cli-darwin-arm64@2.10.0': + '@tailwindcss/oxide-android-arm64': 4.3.3 + '@tailwindcss/oxide-darwin-arm64': 4.3.3 + '@tailwindcss/oxide-darwin-x64': 4.3.3 + '@tailwindcss/oxide-freebsd-x64': 4.3.3 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.3 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.3 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.3 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.3 + '@tailwindcss/oxide-linux-x64-musl': 4.3.3 + '@tailwindcss/oxide-wasm32-wasi': 4.3.3 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.3 + + '@tailwindcss/postcss@4.3.3': + dependencies: + '@alloc/quick-lru': 5.3.0 + '@tailwindcss/node': 4.3.3 + '@tailwindcss/oxide': 4.3.3 + postcss: 8.5.30 + tailwindcss: 4.3.3 + + '@tauri-apps/api@2.12.4': {} + + '@tauri-apps/cli-darwin-arm64@2.12.3': optional: true - '@tauri-apps/cli-darwin-x64@2.10.0': + '@tauri-apps/cli-darwin-x64@2.12.3': optional: true - '@tauri-apps/cli-linux-arm-gnueabihf@2.10.0': + '@tauri-apps/cli-linux-arm-gnueabihf@2.12.3': optional: true - '@tauri-apps/cli-linux-arm64-gnu@2.10.0': + '@tauri-apps/cli-linux-arm64-gnu@2.12.3': optional: true - '@tauri-apps/cli-linux-arm64-musl@2.10.0': + '@tauri-apps/cli-linux-arm64-musl@2.12.3': optional: true - '@tauri-apps/cli-linux-riscv64-gnu@2.10.0': + '@tauri-apps/cli-linux-riscv64-gnu@2.12.3': optional: true - '@tauri-apps/cli-linux-x64-gnu@2.10.0': + '@tauri-apps/cli-linux-x64-gnu@2.12.3': optional: true - '@tauri-apps/cli-linux-x64-musl@2.10.0': + '@tauri-apps/cli-linux-x64-musl@2.12.3': optional: true - '@tauri-apps/cli-win32-arm64-msvc@2.10.0': + '@tauri-apps/cli-win32-arm64-msvc@2.12.3': optional: true - '@tauri-apps/cli-win32-ia32-msvc@2.10.0': + '@tauri-apps/cli-win32-ia32-msvc@2.12.3': optional: true - '@tauri-apps/cli-win32-x64-msvc@2.10.0': + '@tauri-apps/cli-win32-x64-msvc@2.12.3': optional: true - '@tauri-apps/cli@2.10.0': + '@tauri-apps/cli@2.12.3': optionalDependencies: - '@tauri-apps/cli-darwin-arm64': 2.10.0 - '@tauri-apps/cli-darwin-x64': 2.10.0 - '@tauri-apps/cli-linux-arm-gnueabihf': 2.10.0 - '@tauri-apps/cli-linux-arm64-gnu': 2.10.0 - '@tauri-apps/cli-linux-arm64-musl': 2.10.0 - '@tauri-apps/cli-linux-riscv64-gnu': 2.10.0 - '@tauri-apps/cli-linux-x64-gnu': 2.10.0 - '@tauri-apps/cli-linux-x64-musl': 2.10.0 - '@tauri-apps/cli-win32-arm64-msvc': 2.10.0 - '@tauri-apps/cli-win32-ia32-msvc': 2.10.0 - '@tauri-apps/cli-win32-x64-msvc': 2.10.0 + '@tauri-apps/cli-darwin-arm64': 2.12.3 + '@tauri-apps/cli-darwin-x64': 2.12.3 + '@tauri-apps/cli-linux-arm-gnueabihf': 2.12.3 + '@tauri-apps/cli-linux-arm64-gnu': 2.12.3 + '@tauri-apps/cli-linux-arm64-musl': 2.12.3 + '@tauri-apps/cli-linux-riscv64-gnu': 2.12.3 + '@tauri-apps/cli-linux-x64-gnu': 2.12.3 + '@tauri-apps/cli-linux-x64-musl': 2.12.3 + '@tauri-apps/cli-win32-arm64-msvc': 2.12.3 + '@tauri-apps/cli-win32-ia32-msvc': 2.12.3 + '@tauri-apps/cli-win32-x64-msvc': 2.12.3 - '@tauri-apps/plugin-clipboard-manager@2.3.2': + '@tauri-apps/plugin-clipboard-manager@2.5.0': dependencies: - '@tauri-apps/api': 2.10.1 + '@tauri-apps/api': 2.12.4 - '@tauri-apps/plugin-dialog@2.6.0': + '@tauri-apps/plugin-dialog@2.8.3': dependencies: - '@tauri-apps/api': 2.10.1 + '@tauri-apps/api': 2.12.4 - '@tauri-apps/plugin-http@2.5.7': + '@tauri-apps/plugin-http@2.8.3': dependencies: - '@tauri-apps/api': 2.10.1 + '@tauri-apps/api': 2.12.4 - '@tauri-apps/plugin-shell@2.3.5': + '@tauri-apps/plugin-shell@2.5.0': dependencies: - '@tauri-apps/api': 2.10.1 + '@tauri-apps/api': 2.12.4 - '@tauri-apps/plugin-window-state@2.4.1': + '@tauri-apps/plugin-window-state@2.5.0': dependencies: - '@tauri-apps/api': 2.10.1 + '@tauri-apps/api': 2.12.4 '@testing-library/dom@10.4.1': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/runtime': 7.28.6 + '@babel/code-frame': 7.29.7 + '@babel/runtime': 7.29.10 '@types/aria-query': 5.0.4 aria-query: 5.3.0 dom-accessibility-api: 0.5.16 @@ -3025,22 +3071,22 @@ snapshots: '@testing-library/jest-dom@6.9.1': dependencies: - '@adobe/css-tools': 4.4.4 + '@adobe/css-tools': 4.5.0 aria-query: 5.3.2 css.escape: 1.5.1 dom-accessibility-api: 0.6.3 picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@testing-library/react@16.3.3(@testing-library/dom@10.4.1)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.1(react@19.3.1))(react@19.3.1)': dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.10 '@testing-library/dom': 10.4.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) '@types/aria-query@5.0.4': {} @@ -3053,172 +3099,174 @@ snapshots: '@types/dompurify@3.2.0': dependencies: - dompurify: 3.3.1 + dompurify: 3.4.17 '@types/esrecurse@4.3.1': {} - '@types/estree@1.0.8': {} + '@types/estree@1.0.9': {} '@types/json-schema@7.0.15': {} - '@types/node@25.3.3': + '@types/node@25.9.9': dependencies: - undici-types: 7.18.2 + undici-types: 7.24.6 - '@types/react-dom@19.2.3(@types/react@19.2.14)': + '@types/react-dom@19.3.0(@types/react@19.3.0)': dependencies: - '@types/react': 19.2.14 + '@types/react': 19.3.0 - '@types/react@19.2.14': + '@types/react@19.3.0': dependencies: csstype: 3.2.3 '@types/trusted-types@2.0.7': optional: true - '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.71.2(@typescript-eslint/parser@8.71.2(eslint@10.13.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.13.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/type-utils': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.56.1 - eslint: 10.0.2(jiti@2.6.1) - ignore: 7.0.5 + '@typescript-eslint/parser': 8.71.2(eslint@10.13.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.71.2 + '@typescript-eslint/type-utils': 8.71.2(eslint@10.13.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.71.2(eslint@10.13.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.71.2 + eslint: 10.13.0(jiti@2.7.0) + ignore: 7.0.12 natural-compare: 1.4.0 - ts-api-utils: 2.4.0(typescript@5.9.3) + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.71.2(eslint@10.13.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/scope-manager': 8.71.2 + '@typescript-eslint/types': 8.71.2 + '@typescript-eslint/typescript-estree': 8.71.2(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.71.2 debug: 4.4.3 - eslint: 10.0.2(jiti@2.6.1) + eslint: 10.13.0(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.56.1(typescript@5.9.3)': + '@typescript-eslint/project-service@8.71.2(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) - '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/tsconfig-utils': 8.71.2(typescript@5.9.3) + '@typescript-eslint/types': 8.71.2 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.56.1': + '@typescript-eslint/scope-manager@8.71.2': dependencies: - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/types': 8.71.2 + '@typescript-eslint/visitor-keys': 8.71.2 - '@typescript-eslint/tsconfig-utils@8.56.1(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.71.2(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.71.2(eslint@10.13.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.71.2 + '@typescript-eslint/typescript-estree': 8.71.2(typescript@5.9.3) + '@typescript-eslint/utils': 8.71.2(eslint@10.13.0(jiti@2.7.0))(typescript@5.9.3) debug: 4.4.3 - eslint: 10.0.2(jiti@2.6.1) - ts-api-utils: 2.4.0(typescript@5.9.3) + eslint: 10.13.0(jiti@2.7.0) + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.56.1': {} + '@typescript-eslint/types@8.71.2': {} - '@typescript-eslint/typescript-estree@8.56.1(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.71.2(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.56.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/project-service': 8.71.2(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.71.2(typescript@5.9.3) + '@typescript-eslint/types': 8.71.2 + '@typescript-eslint/visitor-keys': 8.71.2 debug: 4.4.3 - minimatch: 10.2.4 - semver: 7.7.4 - tinyglobby: 0.2.15 - ts-api-utils: 2.4.0(typescript@5.9.3) + minimatch: 10.2.6 + semver: 7.8.5 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.71.2(eslint@10.13.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.2(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - eslint: 10.0.2(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.10.1(eslint@10.13.0(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.71.2 + '@typescript-eslint/types': 8.71.2 + '@typescript-eslint/typescript-estree': 8.71.2(typescript@5.9.3) + eslint: 10.13.0(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.56.1': + '@typescript-eslint/visitor-keys@8.71.2': dependencies: - '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/types': 8.71.2 eslint-visitor-keys: 5.0.1 - '@vitest/coverage-v8@4.0.18(vitest@4.0.18(@types/node@25.3.3)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(yaml@2.8.2))': + '@vitest/coverage-v8@4.1.12(vitest@4.1.12)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.0.18 - ast-v8-to-istanbul: 0.3.12 + '@vitest/utils': 4.1.12 + ast-v8-to-istanbul: 1.0.7 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-reports: 3.2.0 - magicast: 0.5.2 - obug: 2.1.1 - std-env: 3.10.0 - tinyrainbow: 3.0.3 - vitest: 4.0.18(@types/node@25.3.3)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(yaml@2.8.2) + magicast: 0.5.5 + obug: 2.2.1 + std-env: 4.3.0 + tinyrainbow: 3.2.0 + vitest: 4.1.12(@types/node@25.9.9)(@vitest/coverage-v8@4.1.12)(jsdom@28.1.0)(vite@7.3.7(@types/node@25.9.9)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.1)) - '@vitest/expect@4.0.18': + '@vitest/expect@4.1.12': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - chai: 6.2.2 - tinyrainbow: 3.0.3 + '@vitest/spy': 4.1.12 + '@vitest/utils': 4.1.12 + chai: 6.3.0 + tinyrainbow: 3.2.0 - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2))': + '@vitest/mocker@4.1.12(vite@7.3.7(@types/node@25.9.9)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.1))': dependencies: - '@vitest/spy': 4.0.18 + '@vitest/spy': 4.1.12 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) + vite: 7.3.7(@types/node@25.9.9)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.1) - '@vitest/pretty-format@4.0.18': + '@vitest/pretty-format@4.1.12': dependencies: - tinyrainbow: 3.0.3 + tinyrainbow: 3.2.0 - '@vitest/runner@4.0.18': + '@vitest/runner@4.1.12': dependencies: - '@vitest/utils': 4.0.18 + '@vitest/utils': 4.1.12 pathe: 2.0.3 - '@vitest/snapshot@4.0.18': + '@vitest/snapshot@4.1.12': dependencies: - '@vitest/pretty-format': 4.0.18 + '@vitest/pretty-format': 4.1.12 + '@vitest/utils': 4.1.12 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.0.18': {} + '@vitest/spy@4.1.12': {} - '@vitest/utils@4.0.18': + '@vitest/utils@4.1.12': dependencies: - '@vitest/pretty-format': 4.0.18 - tinyrainbow: 3.0.3 + '@vitest/pretty-format': 4.1.12 + convert-source-map: 2.0.0 + tinyrainbow: 3.2.0 '@xterm/addon-fit@0.11.0': {} @@ -3226,15 +3274,15 @@ snapshots: '@xterm/xterm@6.0.0': {} - acorn-jsx@5.3.2(acorn@8.16.0): + acorn-jsx@5.3.2(acorn@8.19.0): dependencies: - acorn: 8.16.0 + acorn: 8.19.0 - acorn@8.16.0: {} + acorn@8.19.0: {} agent-base@7.1.4: {} - ajv@6.14.0: + ajv@6.15.0: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 @@ -3247,7 +3295,7 @@ snapshots: ansi-regex@5.0.1: {} - ansi-regex@6.2.2: {} + ansi-regex@6.4.0: {} ansi-styles@5.2.0: {} @@ -3261,7 +3309,7 @@ snapshots: assertion-error@2.0.1: {} - ast-v8-to-istanbul@0.3.12: + ast-v8-to-istanbul@1.0.7: dependencies: '@jridgewell/trace-mapping': 0.3.31 estree-walker: 3.0.3 @@ -3269,31 +3317,35 @@ snapshots: balanced-match@4.0.4: {} - baseline-browser-mapping@2.10.0: {} + baseline-browser-mapping@2.11.29: {} - bidi-js@1.0.3: + bidi-js@1.1.0: dependencies: require-from-string: 2.0.2 - brace-expansion@5.0.4: + brace-expansion@5.0.12: dependencies: balanced-match: 4.0.4 - braces@3.0.3: + browserslist@4.29.3: dependencies: - fill-range: 7.1.1 + baseline-browser-mapping: 2.11.29 + caniuse-lite: 1.0.30001816 + electron-to-chromium: 1.5.459 + node-releases: 2.0.59 + update-browserslist-db: 1.3.4(browserslist@4.29.3) - browserslist@4.28.1: + cacheable@2.5.0: dependencies: - baseline-browser-mapping: 2.10.0 - caniuse-lite: 1.0.30001775 - electron-to-chromium: 1.5.307 - node-releases: 2.0.36 - update-browserslist-db: 1.2.3(browserslist@4.28.1) + '@cacheable/memory': 2.2.0 + '@cacheable/utils': 2.5.0 + hookified: 1.15.1 + keyv: 5.6.0 + qified: 0.10.1 - caniuse-lite@1.0.30001775: {} + caniuse-lite@1.0.30001816: {} - chai@6.2.2: {} + chai@6.3.0: {} cli-cursor@5.0.0: dependencies: @@ -3302,7 +3354,7 @@ snapshots: cli-truncate@5.2.0: dependencies: slice-ansi: 8.0.0 - string-width: 8.2.0 + string-width: 8.3.0 client-only@0.0.1: {} @@ -3312,13 +3364,13 @@ snapshots: convert-source-map@2.0.0: {} - create-markdown@0.4.0(react@19.2.4): + create-markdown@0.4.0(react@19.3.1): dependencies: '@create-markdown/core': 0.2.0 '@create-markdown/preview': 0.2.0(@create-markdown/core@0.2.0) - '@create-markdown/react': 0.2.0(@create-markdown/core@0.2.0)(react@19.2.4) + '@create-markdown/react': 0.2.0(@create-markdown/core@0.2.0)(react@19.3.1) optionalDependencies: - react: 19.2.4 + react: 19.3.1 cross-env@7.0.3: dependencies: @@ -3330,19 +3382,19 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - css-tree@3.2.0: + css-tree@3.2.1: dependencies: mdn-data: 2.27.1 - source-map-js: 1.2.1 + source-map-js: 1.2.2 css.escape@1.5.1: {} cssstyle@6.2.0: dependencies: - '@asamuzakjp/css-color': 5.0.1 - '@csstools/css-syntax-patches-for-csstree': 1.0.29 - css-tree: 3.2.0 - lru-cache: 11.2.6 + '@asamuzakjp/css-color': 5.1.11 + '@csstools/css-syntax-patches-for-csstree': 1.1.15(css-tree@3.2.1) + css-tree: 3.2.1 + lru-cache: 11.5.3 csstype@3.2.3: {} @@ -3369,81 +3421,77 @@ snapshots: dom-accessibility-api@0.6.3: {} - dompurify@3.2.7: - optionalDependencies: - '@types/trusted-types': 2.0.7 - - dompurify@3.3.1: + dompurify@3.4.17: optionalDependencies: '@types/trusted-types': 2.0.7 - electron-to-chromium@1.5.307: {} + electron-to-chromium@1.5.459: {} emoji-regex@10.6.0: {} - enhanced-resolve@5.20.0: + enhanced-resolve@5.26.0: dependencies: graceful-fs: 4.2.11 - tapable: 2.3.0 + tapable: 2.3.3 - entities@6.0.1: {} + entities@8.1.0: {} environment@1.1.0: {} - es-module-lexer@1.7.0: {} + es-module-lexer@2.3.2: {} - esbuild@0.27.3: + esbuild@0.28.2: optionalDependencies: - '@esbuild/aix-ppc64': 0.27.3 - '@esbuild/android-arm': 0.27.3 - '@esbuild/android-arm64': 0.27.3 - '@esbuild/android-x64': 0.27.3 - '@esbuild/darwin-arm64': 0.27.3 - '@esbuild/darwin-x64': 0.27.3 - '@esbuild/freebsd-arm64': 0.27.3 - '@esbuild/freebsd-x64': 0.27.3 - '@esbuild/linux-arm': 0.27.3 - '@esbuild/linux-arm64': 0.27.3 - '@esbuild/linux-ia32': 0.27.3 - '@esbuild/linux-loong64': 0.27.3 - '@esbuild/linux-mips64el': 0.27.3 - '@esbuild/linux-ppc64': 0.27.3 - '@esbuild/linux-riscv64': 0.27.3 - '@esbuild/linux-s390x': 0.27.3 - '@esbuild/linux-x64': 0.27.3 - '@esbuild/netbsd-arm64': 0.27.3 - '@esbuild/netbsd-x64': 0.27.3 - '@esbuild/openbsd-arm64': 0.27.3 - '@esbuild/openbsd-x64': 0.27.3 - '@esbuild/openharmony-arm64': 0.27.3 - '@esbuild/sunos-x64': 0.27.3 - '@esbuild/win32-arm64': 0.27.3 - '@esbuild/win32-ia32': 0.27.3 - '@esbuild/win32-x64': 0.27.3 + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 escalade@3.2.0: {} escape-string-regexp@4.0.0: {} - eslint-config-prettier@10.1.8(eslint@10.0.2(jiti@2.6.1)): + eslint-config-prettier@10.1.8(eslint@10.13.0(jiti@2.7.0)): dependencies: - eslint: 10.0.2(jiti@2.6.1) + eslint: 10.13.0(jiti@2.7.0) - eslint-plugin-react-hooks@7.0.1(eslint@10.0.2(jiti@2.6.1)): + eslint-plugin-react-hooks@7.1.1(eslint@10.13.0(jiti@2.7.0)): dependencies: - '@babel/core': 7.29.0 - '@babel/parser': 7.29.0 - eslint: 10.0.2(jiti@2.6.1) + '@babel/core': 7.29.7 + '@babel/parser': 7.29.9 + eslint: 10.13.0(jiti@2.7.0) hermes-parser: 0.25.1 - zod: 4.3.6 - zod-validation-error: 4.0.2(zod@4.3.6) + zod: 4.6.7 + zod-validation-error: 4.0.2(zod@4.6.7) transitivePeerDependencies: - supports-color - eslint-scope@9.1.1: + eslint-scope@9.1.2: dependencies: '@types/esrecurse': 4.3.1 - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 esrecurse: 4.3.0 estraverse: 5.3.0 @@ -3451,47 +3499,47 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.0.2(jiti@2.6.1): + eslint@10.13.0(jiti@2.7.0): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.10.1(eslint@10.13.0(jiti@2.7.0)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.23.2 - '@eslint/config-helpers': 0.5.2 - '@eslint/core': 1.1.0 - '@eslint/plugin-kit': 0.6.0 - '@humanfs/node': 0.16.7 + '@eslint/config-array': 0.23.5 + '@eslint/config-helpers': 0.7.0 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.3 + '@humanfs/node': 0.16.8 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.14.0 + '@types/estree': 1.0.9 + ajv: 6.15.0 cross-spawn: 7.0.6 debug: 4.4.3 escape-string-regexp: 4.0.0 - eslint-scope: 9.1.1 + eslint-scope: 9.1.2 eslint-visitor-keys: 5.0.1 - espree: 11.1.1 + espree: 11.2.0 esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 + file-entry-cache: 11.1.5 find-up: 5.0.0 glob-parent: 6.0.2 ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 - minimatch: 10.2.4 + minimatch: 10.2.6 natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: - jiti: 2.6.1 + jiti: 2.7.0 transitivePeerDependencies: - supports-color - espree@11.1.1: + espree@11.2.0: dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) + acorn: 8.19.0 + acorn-jsx: 5.3.2(acorn@8.19.0) eslint-visitor-keys: 5.0.1 esquery@1.7.0: @@ -3506,13 +3554,13 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 esutils@2.0.3: {} eventemitter3@5.0.4: {} - expect-type@1.3.0: {} + expect-type@1.4.0: {} fast-deep-equal@3.1.3: {} @@ -3520,45 +3568,42 @@ snapshots: fast-levenshtein@2.0.6: {} - fdir@6.5.0(picomatch@4.0.3): + fdir@6.5.0(picomatch@4.0.7): optionalDependencies: - picomatch: 4.0.3 - - file-entry-cache@8.0.0: - dependencies: - flat-cache: 4.0.1 + picomatch: 4.0.7 - fill-range@7.1.1: + file-entry-cache@11.1.5: dependencies: - to-regex-range: 5.0.1 + flat-cache: 6.1.23 find-up@5.0.0: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - flat-cache@4.0.1: + flat-cache@6.1.23: dependencies: - flatted: 3.3.4 - keyv: 4.5.4 + cacheable: 2.5.0 + flatted: 3.4.4 + hookified: 1.15.1 - flatted@3.3.4: {} + flatted@3.4.4: {} - framer-motion@12.34.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + framer-motion@12.43.0(react-dom@19.3.1(react@19.3.1))(react@19.3.1): dependencies: - motion-dom: 12.34.3 - motion-utils: 12.29.2 + motion-dom: 12.43.0 + motion-utils: 12.39.0 tslib: 2.8.1 optionalDependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) fsevents@2.3.3: optional: true gensync@1.0.0-beta.2: {} - get-east-asian-width@1.5.0: {} + get-east-asian-width@1.7.0: {} glob-parent@6.0.2: dependencies: @@ -3568,15 +3613,23 @@ snapshots: has-flag@4.0.0: {} + hashery@1.5.1: + dependencies: + hookified: 1.15.1 + hermes-estree@0.25.1: {} hermes-parser@0.25.1: dependencies: hermes-estree: 0.25.1 + hookified@1.15.1: {} + + hookified@2.2.0: {} + html-encoding-sniffer@6.0.0: dependencies: - '@exodus/bytes': 1.15.0 + '@exodus/bytes': 1.16.0 transitivePeerDependencies: - '@noble/hashes' @@ -3600,7 +3653,7 @@ snapshots: ignore@5.3.2: {} - ignore@7.0.5: {} + ignore@7.0.12: {} imurmurhash@0.1.4: {} @@ -3610,14 +3663,12 @@ snapshots: is-fullwidth-code-point@5.1.0: dependencies: - get-east-asian-width: 1.5.0 + get-east-asian-width: 1.7.0 is-glob@4.0.3: dependencies: is-extglob: 2.1.1 - is-number@7.0.0: {} - is-potential-custom-element-name@1.0.1: {} isexe@2.0.0: {} @@ -3635,7 +3686,7 @@ snapshots: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 - jiti@2.6.1: {} + jiti@2.7.0: {} js-tokens@10.0.0: {} @@ -3643,10 +3694,10 @@ snapshots: jsdom@28.1.0: dependencies: - '@acemir/cssom': 0.9.31 + '@acemir/cssom': 0.9.32 '@asamuzakjp/dom-selector': 6.8.1 - '@bramus/specificity': 2.4.2 - '@exodus/bytes': 1.15.0 + '@bramus/specificity': 2.4.3 + '@exodus/bytes': 1.16.0 cssstyle: 6.2.0 data-urls: 7.0.0 decimal.js: 10.6.0 @@ -3654,11 +3705,11 @@ snapshots: http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 is-potential-custom-element-name: 1.0.1 - parse5: 8.0.0 + parse5: 8.0.1 saxes: 6.0.0 symbol-tree: 3.2.4 - tough-cookie: 6.0.0 - undici: 7.22.0 + tough-cookie: 6.0.2 + undici: 7.30.1 w3c-xmlserializer: 5.0.0 webidl-conversions: 8.0.1 whatwg-mimetype: 5.0.0 @@ -3670,80 +3721,78 @@ snapshots: jsesc@3.1.0: {} - json-buffer@3.0.1: {} - json-schema-traverse@0.4.1: {} json-stable-stringify-without-jsonify@1.0.1: {} json5@2.2.3: {} - keyv@4.5.4: + keyv@5.6.0: dependencies: - json-buffer: 3.0.1 + '@keyv/serialize': 1.1.1 levn@0.4.1: dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 - lightningcss-android-arm64@1.31.1: + lightningcss-android-arm64@1.32.0: optional: true - lightningcss-darwin-arm64@1.31.1: + lightningcss-darwin-arm64@1.32.0: optional: true - lightningcss-darwin-x64@1.31.1: + lightningcss-darwin-x64@1.32.0: optional: true - lightningcss-freebsd-x64@1.31.1: + lightningcss-freebsd-x64@1.32.0: optional: true - lightningcss-linux-arm-gnueabihf@1.31.1: + lightningcss-linux-arm-gnueabihf@1.32.0: optional: true - lightningcss-linux-arm64-gnu@1.31.1: + lightningcss-linux-arm64-gnu@1.32.0: optional: true - lightningcss-linux-arm64-musl@1.31.1: + lightningcss-linux-arm64-musl@1.32.0: optional: true - lightningcss-linux-x64-gnu@1.31.1: + lightningcss-linux-x64-gnu@1.32.0: optional: true - lightningcss-linux-x64-musl@1.31.1: + lightningcss-linux-x64-musl@1.32.0: optional: true - lightningcss-win32-arm64-msvc@1.31.1: + lightningcss-win32-arm64-msvc@1.32.0: optional: true - lightningcss-win32-x64-msvc@1.31.1: + lightningcss-win32-x64-msvc@1.32.0: optional: true - lightningcss@1.31.1: + lightningcss@1.32.0: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-android-arm64: 1.31.1 - lightningcss-darwin-arm64: 1.31.1 - lightningcss-darwin-x64: 1.31.1 - lightningcss-freebsd-x64: 1.31.1 - lightningcss-linux-arm-gnueabihf: 1.31.1 - lightningcss-linux-arm64-gnu: 1.31.1 - lightningcss-linux-arm64-musl: 1.31.1 - lightningcss-linux-x64-gnu: 1.31.1 - lightningcss-linux-x64-musl: 1.31.1 - lightningcss-win32-arm64-msvc: 1.31.1 - lightningcss-win32-x64-msvc: 1.31.1 - - lint-staged@16.3.2: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + lint-staged@16.4.0: dependencies: commander: 14.0.3 listr2: 9.0.5 - micromatch: 4.0.8 + picomatch: 4.0.7 string-argv: 0.3.2 - tinyexec: 1.0.2 - yaml: 2.8.2 + tinyexec: 1.3.1 + yaml: 2.9.1 listr2@9.0.5: dependencies: @@ -3766,7 +3815,7 @@ snapshots: strip-ansi: 7.2.0 wrap-ansi: 9.0.2 - lru-cache@11.2.6: {} + lru-cache@11.5.3: {} lru-cache@5.1.1: dependencies: @@ -3776,79 +3825,75 @@ snapshots: magic-string@0.30.21: dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.6.0 - magicast@0.5.2: + magicast@0.5.5: dependencies: - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 - source-map-js: 1.2.1 + '@babel/parser': 7.29.9 + '@babel/types': 7.29.8 + source-map-js: 1.2.2 make-dir@4.0.0: dependencies: - semver: 7.7.4 + semver: 7.8.5 marked@14.0.0: {} mdn-data@2.27.1: {} - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - mimic-function@5.0.1: {} min-indent@1.0.1: {} - minimatch@10.2.4: + minimatch@10.2.6: dependencies: - brace-expansion: 5.0.4 + brace-expansion: 5.0.12 monaco-editor@0.55.1: dependencies: - dompurify: 3.2.7 + dompurify: 3.4.17 marked: 14.0.0 - motion-dom@12.34.3: + motion-dom@12.43.0: dependencies: - motion-utils: 12.29.2 + motion-utils: 12.39.0 - motion-utils@12.29.2: {} + motion-utils@12.39.0: {} ms@2.1.3: {} - nanoid@3.3.11: {} + nanoid@3.3.20: {} natural-compare@1.4.0: {} - next@16.1.6(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + next@16.4.2(@babel/core@7.29.7)(@types/node@25.9.9)(react-dom@19.3.1(react@19.3.1))(react@19.3.1): dependencies: - '@next/env': 16.1.6 - '@swc/helpers': 0.5.15 - baseline-browser-mapping: 2.10.0 - caniuse-lite: 1.0.30001775 - postcss: 8.4.31 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.4) + '@next/env': 16.4.2 + '@swc/helpers': 0.5.23 + baseline-browser-mapping: 2.11.29 + caniuse-lite: 1.0.30001816 + postcss: 8.5.23 + react: 19.3.1 + react-dom: 19.3.1(react@19.3.1) + styled-jsx: 5.1.6(@babel/core@7.29.7)(react@19.3.1) optionalDependencies: - '@next/swc-darwin-arm64': 16.1.6 - '@next/swc-darwin-x64': 16.1.6 - '@next/swc-linux-arm64-gnu': 16.1.6 - '@next/swc-linux-arm64-musl': 16.1.6 - '@next/swc-linux-x64-gnu': 16.1.6 - '@next/swc-linux-x64-musl': 16.1.6 - '@next/swc-win32-arm64-msvc': 16.1.6 - '@next/swc-win32-x64-msvc': 16.1.6 - sharp: 0.34.5 + '@next/swc-darwin-arm64': 16.4.2 + '@next/swc-darwin-x64': 16.4.2 + '@next/swc-linux-arm64-gnu': 16.4.2 + '@next/swc-linux-arm64-musl': 16.4.2 + '@next/swc-linux-x64-gnu': 16.4.2 + '@next/swc-linux-x64-musl': 16.4.2 + '@next/swc-win32-arm64-msvc': 16.4.2 + '@next/swc-win32-x64-msvc': 16.4.2 + sharp: 0.35.5(@types/node@25.9.9) transitivePeerDependencies: - '@babel/core' + - '@types/node' - babel-plugin-macros - node-releases@2.0.36: {} + node-releases@2.0.59: {} - obug@2.1.1: {} + obug@2.2.1: {} onetime@7.0.0: dependencies: @@ -3871,9 +3916,9 @@ snapshots: dependencies: p-limit: 3.1.0 - parse5@8.0.0: + parse5@8.0.1: dependencies: - entities: 6.0.1 + entities: 8.1.0 path-exists@4.0.0: {} @@ -3883,25 +3928,23 @@ snapshots: picocolors@1.1.1: {} - picomatch@2.3.1: {} - - picomatch@4.0.3: {} + picomatch@4.0.7: {} - postcss@8.4.31: + postcss@8.5.23: dependencies: - nanoid: 3.3.11 + nanoid: 3.3.20 picocolors: 1.1.1 - source-map-js: 1.2.1 + source-map-js: 1.2.2 - postcss@8.5.6: + postcss@8.5.30: dependencies: - nanoid: 3.3.11 + nanoid: 3.3.20 picocolors: 1.1.1 - source-map-js: 1.2.1 + source-map-js: 1.2.2 prelude-ls@1.2.1: {} - prettier@3.8.1: {} + prettier@3.9.10: {} pretty-format@27.5.1: dependencies: @@ -3911,18 +3954,22 @@ snapshots: punycode@2.3.1: {} - qrcode.react@4.2.0(react@19.2.4): + qified@0.10.1: + dependencies: + hookified: 2.2.0 + + qrcode.react@4.2.0(react@19.3.1): dependencies: - react: 19.2.4 + react: 19.3.1 - react-dom@19.2.4(react@19.2.4): + react-dom@19.3.1(react@19.3.1): dependencies: - react: 19.2.4 - scheduler: 0.27.0 + react: 19.3.1 + scheduler: 0.28.0 react-is@17.0.2: {} - react@19.2.4: {} + react@19.3.1: {} redent@3.0.0: dependencies: @@ -3938,77 +3985,80 @@ snapshots: rfdc@1.4.1: {} - rollup@4.59.0: + rollup@4.64.9: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.59.0 - '@rollup/rollup-android-arm64': 4.59.0 - '@rollup/rollup-darwin-arm64': 4.59.0 - '@rollup/rollup-darwin-x64': 4.59.0 - '@rollup/rollup-freebsd-arm64': 4.59.0 - '@rollup/rollup-freebsd-x64': 4.59.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 - '@rollup/rollup-linux-arm-musleabihf': 4.59.0 - '@rollup/rollup-linux-arm64-gnu': 4.59.0 - '@rollup/rollup-linux-arm64-musl': 4.59.0 - '@rollup/rollup-linux-loong64-gnu': 4.59.0 - '@rollup/rollup-linux-loong64-musl': 4.59.0 - '@rollup/rollup-linux-ppc64-gnu': 4.59.0 - '@rollup/rollup-linux-ppc64-musl': 4.59.0 - '@rollup/rollup-linux-riscv64-gnu': 4.59.0 - '@rollup/rollup-linux-riscv64-musl': 4.59.0 - '@rollup/rollup-linux-s390x-gnu': 4.59.0 - '@rollup/rollup-linux-x64-gnu': 4.59.0 - '@rollup/rollup-linux-x64-musl': 4.59.0 - '@rollup/rollup-openbsd-x64': 4.59.0 - '@rollup/rollup-openharmony-arm64': 4.59.0 - '@rollup/rollup-win32-arm64-msvc': 4.59.0 - '@rollup/rollup-win32-ia32-msvc': 4.59.0 - '@rollup/rollup-win32-x64-gnu': 4.59.0 - '@rollup/rollup-win32-x64-msvc': 4.59.0 + '@napi-rs/lzma-linux-x64-gnu': 1.5.1 + '@rollup/rollup-android-arm-eabi': 4.64.9 + '@rollup/rollup-android-arm64': 4.64.9 + '@rollup/rollup-darwin-arm64': 4.64.9 + '@rollup/rollup-darwin-x64': 4.64.9 + '@rollup/rollup-freebsd-arm64': 4.64.9 + '@rollup/rollup-freebsd-x64': 4.64.9 + '@rollup/rollup-linux-arm-gnueabihf': 4.64.9 + '@rollup/rollup-linux-arm-musleabihf': 4.64.9 + '@rollup/rollup-linux-arm64-gnu': 4.64.9 + '@rollup/rollup-linux-arm64-musl': 4.64.9 + '@rollup/rollup-linux-loong64-gnu': 4.64.9 + '@rollup/rollup-linux-loong64-musl': 4.64.9 + '@rollup/rollup-linux-ppc64-gnu': 4.64.9 + '@rollup/rollup-linux-ppc64-musl': 4.64.9 + '@rollup/rollup-linux-riscv64-gnu': 4.64.9 + '@rollup/rollup-linux-riscv64-musl': 4.64.9 + '@rollup/rollup-linux-s390x-gnu': 4.64.9 + '@rollup/rollup-linux-x64-gnu': 4.64.9 + '@rollup/rollup-linux-x64-musl': 4.64.9 + '@rollup/rollup-openbsd-x64': 4.64.9 + '@rollup/rollup-openharmony-arm64': 4.64.9 + '@rollup/rollup-win32-arm64-msvc': 4.64.9 + '@rollup/rollup-win32-ia32-msvc': 4.64.9 + '@rollup/rollup-win32-x64-gnu': 4.64.9 + '@rollup/rollup-win32-x64-msvc': 4.64.9 fsevents: 2.3.3 saxes@6.0.0: dependencies: xmlchars: 2.2.0 - scheduler@0.27.0: {} + scheduler@0.28.0: {} semver@6.3.1: {} - semver@7.7.4: {} + semver@7.8.5: {} - sharp@0.34.5: + sharp@0.35.5(@types/node@25.9.9): dependencies: - '@img/colour': 1.0.0 + '@img/colour': 1.1.0 detect-libc: 2.1.2 - semver: 7.7.4 + semver: 7.8.5 optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.5 - '@img/sharp-darwin-x64': 0.34.5 - '@img/sharp-libvips-darwin-arm64': 1.2.4 - '@img/sharp-libvips-darwin-x64': 1.2.4 - '@img/sharp-libvips-linux-arm': 1.2.4 - '@img/sharp-libvips-linux-arm64': 1.2.4 - '@img/sharp-libvips-linux-ppc64': 1.2.4 - '@img/sharp-libvips-linux-riscv64': 1.2.4 - '@img/sharp-libvips-linux-s390x': 1.2.4 - '@img/sharp-libvips-linux-x64': 1.2.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 - '@img/sharp-linux-arm': 0.34.5 - '@img/sharp-linux-arm64': 0.34.5 - '@img/sharp-linux-ppc64': 0.34.5 - '@img/sharp-linux-riscv64': 0.34.5 - '@img/sharp-linux-s390x': 0.34.5 - '@img/sharp-linux-x64': 0.34.5 - '@img/sharp-linuxmusl-arm64': 0.34.5 - '@img/sharp-linuxmusl-x64': 0.34.5 - '@img/sharp-wasm32': 0.34.5 - '@img/sharp-win32-arm64': 0.34.5 - '@img/sharp-win32-ia32': 0.34.5 - '@img/sharp-win32-x64': 0.34.5 + '@img/sharp-darwin-arm64': 0.35.5 + '@img/sharp-darwin-x64': 0.35.5 + '@img/sharp-freebsd-wasm32': 0.35.5 + '@img/sharp-libvips-darwin-arm64': 1.3.4 + '@img/sharp-libvips-darwin-x64': 1.3.4 + '@img/sharp-libvips-linux-arm': 1.3.4 + '@img/sharp-libvips-linux-arm64': 1.3.4 + '@img/sharp-libvips-linux-ppc64': 1.3.4 + '@img/sharp-libvips-linux-riscv64': 1.3.4 + '@img/sharp-libvips-linux-s390x': 1.3.4 + '@img/sharp-libvips-linux-x64': 1.3.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.4 + '@img/sharp-linux-arm': 0.35.5 + '@img/sharp-linux-arm64': 0.35.5 + '@img/sharp-linux-ppc64': 0.35.5 + '@img/sharp-linux-riscv64': 0.35.5 + '@img/sharp-linux-s390x': 0.35.5 + '@img/sharp-linux-x64': 0.35.5 + '@img/sharp-linuxmusl-arm64': 0.35.5 + '@img/sharp-linuxmusl-x64': 0.35.5 + '@img/sharp-webcontainers-wasm32': 0.35.5 + '@img/sharp-win32-arm64': 0.35.5 + '@img/sharp-win32-ia32': 0.35.5 + '@img/sharp-win32-x64': 0.35.5 + '@types/node': 25.9.9 optional: true shebang-command@2.0.0: @@ -4031,41 +4081,41 @@ snapshots: ansi-styles: 6.2.3 is-fullwidth-code-point: 5.1.0 - source-map-js@1.2.1: {} + source-map-js@1.2.2: {} stackback@0.0.2: {} state-local@1.0.7: {} - std-env@3.10.0: {} + std-env@4.3.0: {} string-argv@0.3.2: {} string-width@7.2.0: dependencies: emoji-regex: 10.6.0 - get-east-asian-width: 1.5.0 + get-east-asian-width: 1.7.0 strip-ansi: 7.2.0 - string-width@8.2.0: + string-width@8.3.0: dependencies: - get-east-asian-width: 1.5.0 + get-east-asian-width: 1.7.0 strip-ansi: 7.2.0 strip-ansi@7.2.0: dependencies: - ansi-regex: 6.2.2 + ansi-regex: 6.4.0 strip-indent@3.0.0: dependencies: min-indent: 1.0.1 - styled-jsx@5.1.6(@babel/core@7.29.0)(react@19.2.4): + styled-jsx@5.1.6(@babel/core@7.29.7)(react@19.3.1): dependencies: client-only: 0.0.1 - react: 19.2.4 + react: 19.3.1 optionalDependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 supports-color@7.2.0: dependencies: @@ -4073,40 +4123,36 @@ snapshots: symbol-tree@3.2.4: {} - tailwindcss@4.2.1: {} + tailwindcss@4.3.3: {} - tapable@2.3.0: {} + tapable@2.3.3: {} tinybench@2.9.0: {} - tinyexec@1.0.2: {} + tinyexec@1.3.1: {} - tinyglobby@0.2.15: + tinyglobby@0.2.17: dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - - tinyrainbow@3.0.3: {} + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 - tldts-core@7.0.24: {} + tinyrainbow@3.2.0: {} - tldts@7.0.24: - dependencies: - tldts-core: 7.0.24 + tldts-core@7.4.18: {} - to-regex-range@5.0.1: + tldts@7.4.18: dependencies: - is-number: 7.0.0 + tldts-core: 7.4.18 - tough-cookie@6.0.0: + tough-cookie@6.0.2: dependencies: - tldts: 7.0.24 + tldts: 7.4.18 tr46@6.0.0: dependencies: punycode: 2.3.1 - ts-api-utils@2.4.0(typescript@5.9.3): + ts-api-utils@2.5.0(typescript@5.9.3): dependencies: typescript: 5.9.3 @@ -4118,26 +4164,26 @@ snapshots: dependencies: prelude-ls: 1.2.1 - typescript-eslint@8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.71.2(eslint@10.13.0(jiti@2.7.0))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) - eslint: 10.0.2(jiti@2.6.1) + '@typescript-eslint/eslint-plugin': 8.71.2(@typescript-eslint/parser@8.71.2(eslint@10.13.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.13.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.71.2(eslint@10.13.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.71.2(typescript@5.9.3) + '@typescript-eslint/utils': 8.71.2(eslint@10.13.0(jiti@2.7.0))(typescript@5.9.3) + eslint: 10.13.0(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color typescript@5.9.3: {} - undici-types@7.18.2: {} + undici-types@7.24.6: {} - undici@7.22.0: {} + undici@7.30.1: {} - update-browserslist-db@1.2.3(browserslist@4.28.1): + update-browserslist-db@1.3.4(browserslist@4.29.3): dependencies: - browserslist: 4.28.1 + browserslist: 4.29.3 escalade: 3.2.0 picocolors: 1.1.1 @@ -4145,58 +4191,49 @@ snapshots: dependencies: punycode: 2.3.1 - vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2): + vite@7.3.7(@types/node@25.9.9)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.1): dependencies: - esbuild: 0.27.3 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.59.0 - tinyglobby: 0.2.15 + esbuild: 0.28.2 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + postcss: 8.5.30 + rollup: 4.64.9 + tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 25.3.3 + '@types/node': 25.9.9 fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.31.1 - yaml: 2.8.2 - - vitest@4.0.18(@types/node@25.3.3)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(yaml@2.8.2): - dependencies: - '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2)) - '@vitest/pretty-format': 4.0.18 - '@vitest/runner': 4.0.18 - '@vitest/snapshot': 4.0.18 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - es-module-lexer: 1.7.0 - expect-type: 1.3.0 + jiti: 2.7.0 + lightningcss: 1.32.0 + yaml: 2.9.1 + + vitest@4.1.12(@types/node@25.9.9)(@vitest/coverage-v8@4.1.12)(jsdom@28.1.0)(vite@7.3.7(@types/node@25.9.9)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.1)): + dependencies: + '@vitest/expect': 4.1.12 + '@vitest/mocker': 4.1.12(vite@7.3.7(@types/node@25.9.9)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.1)) + '@vitest/pretty-format': 4.1.12 + '@vitest/runner': 4.1.12 + '@vitest/snapshot': 4.1.12 + '@vitest/spy': 4.1.12 + '@vitest/utils': 4.1.12 + es-module-lexer: 2.3.2 + expect-type: 1.4.0 magic-string: 0.30.21 - obug: 2.1.1 + obug: 2.2.1 pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 + picomatch: 4.0.7 + std-env: 4.3.0 tinybench: 2.9.0 - tinyexec: 1.0.2 - tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) + tinyexec: 1.3.1 + tinyglobby: 0.2.17 + tinyrainbow: 3.2.0 + vite: 7.3.7(@types/node@25.9.9)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.1) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 25.3.3 + '@types/node': 25.9.9 + '@vitest/coverage-v8': 4.1.12(vitest@4.1.12) jsdom: 28.1.0 transitivePeerDependencies: - - jiti - - less - - lightningcss - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml w3c-xmlserializer@5.0.0: dependencies: @@ -4208,7 +4245,7 @@ snapshots: whatwg-url@16.0.1: dependencies: - '@exodus/bytes': 1.15.0 + '@exodus/bytes': 1.16.0 tr46: 6.0.0 webidl-conversions: 8.0.1 transitivePeerDependencies: @@ -4237,12 +4274,12 @@ snapshots: yallist@3.1.1: {} - yaml@2.8.2: {} + yaml@2.9.1: {} yocto-queue@0.1.0: {} - zod-validation-error@4.0.2(zod@4.3.6): + zod-validation-error@4.0.2(zod@4.6.7): dependencies: - zod: 4.3.6 + zod: 4.6.7 - zod@4.3.6: {} + zod@4.6.7: {} diff --git a/scripts/secrets-scan.sh b/scripts/secrets-scan.sh index af15d1a..1378dcb 100755 --- a/scripts/secrets-scan.sh +++ b/scripts/secrets-scan.sh @@ -8,6 +8,10 @@ MODE="${1:-staged}" BASELINE_PATH="${GITLEAKS_BASELINE:-.gitleaks.baseline.json}" resolve_gitleaks() { + if command -v gitleaks >/dev/null 2>&1; then + command -v gitleaks + return 0 + fi if [ -x "$ROOT/.tools/bin/gitleaks" ]; then echo "$ROOT/.tools/bin/gitleaks" return 0 diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 5361af9..90e84e3 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -8,37 +8,26 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" -[[package]] -name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom 0.2.17", - "once_cell", - "version_check", -] - [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" dependencies = [ "memchr", ] [[package]] name = "alloc-no-stdlib" -version = "2.0.4" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" +checksum = "c2fb6cfd47bf496ff64095c20eaba0c201404ee38714d4142fcfa1dc334fcc7a" [[package]] name = "alloc-stdlib" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +checksum = "0b5c1865780388bfa186411ab5f247819487fc4864c6e9c3106611fa347586e1" dependencies = [ "alloc-no-stdlib", ] @@ -62,18 +51,18 @@ dependencies = [ [[package]] name = "android_system_properties" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" dependencies = [ "libc", ] [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "app" @@ -100,9 +89,9 @@ dependencies = [ [[package]] name = "arboard" -version = "3.6.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0348a1c054491f4bfe6ab86a7b6ab1e44e45d899005de92f58b3df180b36ddaf" +checksum = "aeb9553e62312c8756a5979254fc6d7da8bbeb5986a1e17037fab932f7037917" dependencies = [ "clipboard-win", "image", @@ -114,17 +103,11 @@ dependencies = [ "objc2-foundation", "parking_lot", "percent-encoding", - "windows-sys 0.60.2", + "windows-sys 0.61.2", "wl-clipboard-rs", "x11rb", ] -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - [[package]] name = "ascii" version = "1.1.0" @@ -162,9 +145,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "base64" @@ -178,6 +161,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + [[package]] name = "bit-set" version = "0.8.0" @@ -201,25 +190,13 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.0" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" dependencies = [ "serde_core", ] -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - [[package]] name = "block-buffer" version = "0.10.4" @@ -238,34 +215,11 @@ dependencies = [ "objc2", ] -[[package]] -name = "borsh" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" -dependencies = [ - "borsh-derive", - "cfg_aliases", -] - -[[package]] -name = "borsh-derive" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" -dependencies = [ - "once_cell", - "proc-macro-crate 3.5.0", - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "brotli" -version = "8.0.2" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +checksum = "f8b851b75c23ca7873623d612fe49bd1989aeb03d08fb9432187eb253d3d4c6b" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -274,59 +228,34 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "5.0.0" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +checksum = "941cd9bd4ddab83cb46fa5a2d428f1c857b24ac78cb876cf7beb710840934bd7" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", ] [[package]] -name = "bumpalo" -version = "3.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" - -[[package]] -name = "byte-unit" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6d47a4e2961fb8721bcfc54feae6455f2f64e7054f9bc67e875f0e77f4c58d" -dependencies = [ - "rust_decimal", - "schemars 1.2.1", - "serde", - "utf8-width", -] - -[[package]] -name = "bytecheck" -version = "0.6.12" +name = "bs58" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ - "bytecheck_derive", - "ptr_meta", - "simdutf8", + "tinyvec", ] [[package]] -name = "bytecheck_derive" -version = "0.6.12" +name = "bumpalo" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "bytemuck" -version = "1.25.0" +version = "1.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" [[package]] name = "byteorder" @@ -342,9 +271,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.11.1" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" dependencies = [ "serde", ] @@ -355,7 +284,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "cairo-sys-rs", "glib", "libc", @@ -376,9 +305,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.2.2" +version = "1.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +checksum = "bbbad30e4b4c14a39e3cc8aed085a12a327257c316619c93581e017bc52be591" dependencies = [ "serde_core", ] @@ -403,24 +332,25 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.21", ] [[package]] name = "cargo_toml" -version = "0.22.3" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" +checksum = "82f4b26e751e711a5302649417f2da046dce6391b2ea30a4820f37462314f0b9" dependencies = [ + "semver", "serde", - "toml 0.9.12+spec-1.1.0", + "toml 1.1.8+spec-1.1.0", ] [[package]] name = "cc" -version = "1.2.56" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +checksum = "6651c9ed80effdc7db0ff72512157f901af5e3549e341e24b1dd4887d836d838" dependencies = [ "find-msvc-tools", "shlex", @@ -434,13 +364,13 @@ checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cfb" -version = "0.7.3" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +checksum = "a347dcabdae9c31b0825fd6a8bed285ec9c2acb89c47827126d52fa4f59cece3" dependencies = [ - "byteorder", "fnv", "uuid", + "web-time", ] [[package]] @@ -455,26 +385,37 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] name = "cfg_aliases" -version = "0.2.1" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[package]] +name = "chacha20" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "rand_core", +] [[package]] name = "chrono" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -494,49 +435,25 @@ dependencies = [ [[package]] name = "combine" -version = "4.6.7" +version = "4.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +checksum = "4356eba6976435498d05a311ee9fc486da3bc81c200d3f0d7dd9703b41913f92" dependencies = [ "bytes", "memchr", ] -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "cookie" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +checksum = "1a373e3602691c3cdea496d2f0ee5935151e6168fe87739483c463db1b2f2f87" dependencies = [ "percent-encoding", "time", "version_check", ] -[[package]] -name = "cookie_store" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eac901828f88a5241ee0600950ab981148a18f2f756900ffba1b125ca6a3ef9" -dependencies = [ - "cookie", - "document-features", - "idna", - "log", - "publicsuffix", - "serde", - "serde_derive", - "serde_json", - "time", - "url", -] - [[package]] name = "cookie_store" version = "0.22.1" @@ -587,7 +504,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "core-foundation 0.10.1", "core-graphics-types", "foreign-types", @@ -600,11 +517,17 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "core-foundation 0.10.1", "libc", ] +[[package]] +name = "core_detect" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -614,29 +537,38 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" -version = "1.5.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +checksum = "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.15" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +checksum = "98b0cc327b5bc766e7fda9c9260cc0fa81b43a8e240440422dff70788e3f9ef1" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" [[package]] name = "crunchy" @@ -656,59 +588,38 @@ dependencies = [ [[package]] name = "cssparser" -version = "0.29.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa", - "matches", - "phf 0.10.1", - "proc-macro2", - "quote", - "smallvec", - "syn 1.0.109", -] - -[[package]] -name = "cssparser" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" +checksum = "8c9cdaae01d5ed7882b04d795e7f752f46ff52d2fa3b50a20d28c464510bba98" dependencies = [ "cssparser-macros", "dtoa-short", "itoa", - "phf 0.13.1", + "phf", "smallvec", ] [[package]] name = "cssparser-macros" -version = "0.6.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +checksum = "d045de693cb712d0b22c6a64be5b953f67b3ce00ab5ad3dd5d8b441886ab8e1a" dependencies = [ "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] name = "ctor" -version = "0.2.9" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" -dependencies = [ - "quote", - "syn 2.0.117", -] +checksum = "914a755b7c2d4af2bdcff7ce1739e2db9a1b81a9b07123d8015786ae03c0980d" [[package]] name = "darling" -version = "0.21.3" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +checksum = "ed17f5901b6630b993ca003def43f2f8ef4014fc13b047b57aad617ff32bc2ec" dependencies = [ "darling_core", "darling_macro", @@ -716,27 +627,26 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.21.3" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +checksum = "6837e2cf7485aaae18f86181d2f0e9a7ed297a025e220aeabf63fdebd3a2ddff" dependencies = [ - "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] name = "darling_macro" -version = "0.21.3" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +checksum = "2ac7135c3ef02b2f7833bbeb1be5ba7f966dcde8a87c6b87f65a778d71a02785" dependencies = [ "darling_core", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] @@ -746,26 +656,54 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" [[package]] -name = "deranged" -version = "0.5.8" +name = "dbus" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +checksum = "3ab69f03cc8c4340c9c8e315114e1658e6775a9b16a04357973aa21cec22b32e" dependencies = [ - "powerfmt", - "serde_core", + "libc", + "libdbus-sys", + "windows-sys 0.61.2", ] [[package]] -name = "derive_more" -version = "0.99.20" +name = "defmt" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a0795ac740cb54d7b3775c9c17345f6aaecf884c01733b39d6017738e0e3e1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +checksum = "840bb056bd99c495c9188198a258ab787c79f306d864db3e6e8451442d6d8366" dependencies = [ - "convert_case", + "defmt-parser", "proc-macro2", "quote", - "rustc_version", - "syn 2.0.117", + "syn 3.0.9", +] + +[[package]] +name = "defmt-parser" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71958f69fb2de856c5dd51ac9377e986ca1aa5919f931bf5395a807277f889a0" +dependencies = [ + "thiserror 2.0.21", +] + +[[package]] +name = "deranged" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e9de72ce2ad1f90dc62fa25f0f430ef85eb4b0d8fa0be4f30373bc40a21d28e" +dependencies = [ + "serde_core", ] [[package]] @@ -786,7 +724,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -801,9 +739,9 @@ dependencies = [ [[package]] name = "dirs" -version = "6.0.0" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +checksum = "8d57d423b3c82e89b9a24ca3091fee61f456a26edbd28d26c65906f4bc1dcd8f" dependencies = [ "dirs-sys", ] @@ -826,7 +764,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2", "libc", "objc2", @@ -834,13 +772,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] @@ -863,7 +801,7 @@ checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -877,16 +815,16 @@ dependencies = [ [[package]] name = "dom_query" -version = "0.25.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d9c2e7f1d22d0f2ce07626d259b8a55f4a47cb0938d4006dd8ae037f17d585e" +checksum = "fac5fca71e65e94cc718a6e2af65d6e0f9c6027751c2aa562fbb5087fda639bc" dependencies = [ "bit-set", - "cssparser 0.36.0", + "cssparser", "foldhash 0.2.0", - "html5ever 0.36.1", + "html5ever", "precomputed-hash", - "selectors 0.35.0", + "selectors", "tendril", ] @@ -934,16 +872,16 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "embed-resource" -version = "3.0.6" +version = "3.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55a075fc573c64510038d7ee9abc7990635863992f83ebc52c8b433b8411a02e" +checksum = "6168487b5e7eb2673e6efe1200b1848016e436a6ca0b8031bf04bd9d493a249f" dependencies = [ "cc", "memchr", "rustc_version", - "toml 0.9.12+spec-1.1.0", + "toml 1.1.8+spec-1.1.0", "vswhom", - "winreg 0.55.0", + "winreg 0.56.0", ] [[package]] @@ -954,11 +892,16 @@ checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" [[package]] name = "encoding_rs" -version = "0.8.35" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +checksum = "8e985e0451871ad22fb8d2b6b076e2028a502a0d3950998c2c5c0a4f9b5d9679" dependencies = [ "cfg-if", + "core_detect", + "multiversion_no_op", + "rustversion", + "scopeguard", + "simdutf8", ] [[package]] @@ -973,9 +916,9 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826" [[package]] name = "erased-serde" @@ -1000,35 +943,21 @@ dependencies = [ [[package]] name = "error-code" -version = "3.3.2" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" +checksum = "0b5343afd4a8365a643ac588dab4cf234a190c7f6c88c9f6dd6ffe00837661b7" [[package]] name = "fastrand" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" [[package]] name = "fax" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" -dependencies = [ - "fax_derive", -] - -[[package]] -name = "fax_derive" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] +checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a" [[package]] name = "fdeflate" @@ -1071,9 +1000,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.9" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484" [[package]] name = "fixedbitset" @@ -1083,12 +1012,13 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.9.1", + "zlib-rs", ] [[package]] @@ -1121,13 +1051,13 @@ dependencies = [ [[package]] name = "foreign-types-macros" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +checksum = "ea5190182e6915eb873ddbc16e23b711b6eb1f9c00a0d0a3a91b5f6228475225" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] @@ -1145,42 +1075,26 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - [[package]] name = "futures-channel" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" [[package]] name = "futures-executor" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" dependencies = [ "futures-core", "futures-task", @@ -1189,38 +1103,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" [[package]] name = "futures-macro" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] name = "futures-sink" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" [[package]] name = "futures-task" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" [[package]] name = "futures-util" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" dependencies = [ "futures-core", "futures-io", @@ -1232,15 +1146,6 @@ dependencies = [ "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "gdk" version = "0.18.2" @@ -1357,18 +1262,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" dependencies = [ "rustix", - "windows-link 0.2.1", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", + "windows-link", ] [[package]] @@ -1380,7 +1274,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] @@ -1391,24 +1285,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", - "js-sys", "libc", "r-efi 5.3.0", "wasip2", - "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi 6.0.0", - "wasip2", - "wasip3", + "rand_core", + "wasm-bindgen", ] [[package]] @@ -1449,7 +1342,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "futures-channel", "futures-core", "futures-executor", @@ -1477,7 +1370,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -1492,9 +1385,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" [[package]] name = "gobject-sys" @@ -1556,14 +1449,14 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "h2" -version = "0.4.13" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +checksum = "7d29020232d6aa3fb1daca64c1127cf662cf97f254ae16c18c05b8ab635fc118" dependencies = [ "atomic-waker", "bytes", @@ -1571,7 +1464,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.13.0", + "indexmap 2.14.2", "slab", "tokio", "tokio-util", @@ -1594,9 +1487,6 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash", -] [[package]] name = "hashbrown" @@ -1609,9 +1499,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.1" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "heck" @@ -1633,31 +1523,19 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "html5ever" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" -dependencies = [ - "log", - "mac", - "markup5ever 0.14.1", - "match_token", -] - -[[package]] -name = "html5ever" -version = "0.36.1" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6452c4751a24e1b99c3260d505eaeee76a050573e61f30ac2c924ddc7236f01e" +checksum = "46a1761807faccc9a19e86944bbf40610014066306f96edcdedc2fb714bcb7b8" dependencies = [ "log", - "markup5ever 0.36.1", + "markup5ever", ] [[package]] name = "http" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" dependencies = [ "bytes", "itoa", @@ -1665,9 +1543,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" dependencies = [ "bytes", "http", @@ -1675,9 +1553,9 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" dependencies = [ "bytes", "futures-core", @@ -1700,9 +1578,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.8.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "2c3e324da4c95177d6291d4c8730197c0d1822f8a9766814a4a44fa5ab797c9c" dependencies = [ "atomic-waker", "bytes", @@ -1714,7 +1592,6 @@ dependencies = [ "httparse", "itoa", "pin-project-lite", - "pin-utils", "smallvec", "tokio", "want", @@ -1722,15 +1599,14 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.7" +version = "0.27.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +checksum = "dfa8e654703247911e29c23fbeaa261834bd9bb74efba2f9acddc37bfb127f53" dependencies = [ "http", "hyper", "hyper-util", "rustls", - "rustls-pki-types", "tokio", "tokio-rustls", "tower-service", @@ -1739,16 +1615,17 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +checksum = "ddc03d96684f9226b8a787cdb71488417b53ab5ea8fdb1dac946cb9431cc8bff" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", "bytes", "futures-channel", "futures-util", "http", "http-body", + "httparse", "hyper", "ipnet", "libc", @@ -1774,7 +1651,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core", ] [[package]] @@ -1798,12 +1675,13 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" dependencies = [ "displaydoc", "potential_utf", + "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -1811,9 +1689,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" dependencies = [ "displaydoc", "litemap", @@ -1824,9 +1702,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1838,16 +1716,17 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" [[package]] name = "icu_properties" -version = "2.1.2" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" dependencies = [ + "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", @@ -1858,15 +1737,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" [[package]] name = "icu_provider" -version = "2.1.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" dependencies = [ "displaydoc", "icu_locale_core", @@ -1877,12 +1756,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - [[package]] name = "ident_case" version = "1.0.1" @@ -1902,9 +1775,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" dependencies = [ "icu_normalizer", "icu_properties", @@ -1912,9 +1785,9 @@ dependencies = [ [[package]] name = "image" -version = "0.25.9" +version = "0.25.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" dependencies = [ "bytemuck", "byteorder-lite", @@ -1937,21 +1810,21 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.0" +version = "2.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.1", "serde", "serde_core", ] [[package]] name = "infer" -version = "0.19.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" +checksum = "f4200d433cbd5178df7797c9c2e75b348b728e39631cf14520d1e2fc424201f4" dependencies = [ "cfb", ] @@ -1967,19 +1840,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.12.0" +version = "2.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" - -[[package]] -name = "iri-string" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" -dependencies = [ - "memchr", - "serde", -] +checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0" [[package]] name = "is-docker" @@ -2002,9 +1865,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "javascriptcore-rs" @@ -2029,6 +1892,60 @@ dependencies = [ "system-deps", ] +[[package]] +name = "jiff" +version = "0.2.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b005715dcbeb0089a3c0dab99f2ff1cc3b2525323552703d648585d342a383" +dependencies = [ + "defmt", + "jiff-core", + "jiff-static", + "jiff-tzdb-platform", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", + "windows-link", +] + +[[package]] +name = "jiff-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e52fe76043ccecc9005d2305ebaadf7d7fc0cc89ca6baa10a94d6bc68c7128c" +dependencies = [ + "defmt", + "log", +] + +[[package]] +name = "jiff-static" +version = "0.2.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cc9817253cf7c7ee4684451bd327e88d6f3658014e54a29198625590650695c" +dependencies = [ + "jiff-core", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa8377070c6bae868759445e5a77f66d84f0b72f3a054bfb00e6d038b8282da7" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + [[package]] name = "jni" version = "0.21.1" @@ -2038,7 +1955,7 @@ dependencies = [ "cesu8", "cfg-if", "combine", - "jni-sys", + "jni-sys 0.3.1", "log", "thiserror 1.0.69", "walkdir", @@ -2047,37 +1964,60 @@ dependencies = [ [[package]] name = "jni-sys" -version = "0.3.0" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.119", +] [[package]] name = "js-sys" -version = "0.3.91" +version = "0.3.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +checksum = "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5" dependencies = [ - "once_cell", + "cfg-if", + "futures-util", "wasm-bindgen", ] [[package]] name = "json-patch" -version = "3.0.1" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" +checksum = "7421438de105a0827e44fadd05377727847d717c80ce29a229f85fd04c427b72" dependencies = [ "jsonptr", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.21", ] [[package]] name = "jsonptr" -version = "0.6.3" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" +checksum = "a5a3cc660ba5d72bce0b3bb295bf20847ccbb40fd423f3f05b61273672e561fe" dependencies = [ "serde", "serde_json", @@ -2085,13 +2025,12 @@ dependencies = [ [[package]] name = "keyboard-types" -version = "0.7.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +checksum = "0fbe853b403ae61a04233030ae8a79d94975281ed9770a1f9e246732b534b28d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "serde", - "unicode-segmentation", ] [[package]] @@ -2104,29 +2043,11 @@ dependencies = [ "zeroize", ] -[[package]] -name = "kuchikiki" -version = "0.8.8-speedreader" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" -dependencies = [ - "cssparser 0.29.6", - "html5ever 0.29.1", - "indexmap 2.13.0", - "selectors 0.24.0", -] - [[package]] name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "leb128fmt" -version = "0.1.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" +checksum = "20870f649af7073d53e38067b2a84312175d56ea15217e1b15bc83506ec50afb" [[package]] name = "libappindicator" @@ -2154,9 +2075,18 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.183" +version = "0.2.191" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a" + +[[package]] +name = "libdbus-sys" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" +dependencies = [ + "pkg-config", +] [[package]] name = "libloading" @@ -2170,9 +2100,9 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.14" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" +checksum = "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d" dependencies = [ "libc", ] @@ -2185,15 +2115,15 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" [[package]] name = "litrs" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" +checksum = "4744e383959f0db86ede514b809b1c53251889093803c05267acc7d4e7030d70" [[package]] name = "lock_api" @@ -2206,72 +2136,32 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" -dependencies = [ - "value-bag", -] +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" [[package]] name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - -[[package]] -name = "markup5ever" -version = "0.14.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" -dependencies = [ - "log", - "phf 0.11.3", - "phf_codegen 0.11.3", - "string_cache 0.8.9", - "string_cache_codegen 0.5.4", - "tendril", -] +checksum = "4050469837a6ff301cd14c1f8f24f88549e6d548f24f64e2148eb0f72cebc51f" [[package]] name = "markup5ever" -version = "0.36.1" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c3294c4d74d0742910f8c7b466f44dda9eb2d5742c1e430138df290a1e8451c" +checksum = "7122d987ec5f704ee56f6e5b41a7d93722e9aae27ae07cafa4036c4d3f9757de" dependencies = [ "log", "tendril", "web_atoms", ] -[[package]] -name = "match_token" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "memoffset" @@ -2307,22 +2197,32 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "miniz_oxide" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" +dependencies = [ + "adler2", + "simd-adler32", +] + [[package]] name = "mio" -version = "1.1.1" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "1788edb87fdc09c7e26304471e2f5be8cdefb1b6930d6e3985fc02ff53bf86ee" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "windows-sys 0.61.2", ] [[package]] name = "moxcms" -version = "0.7.11" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" dependencies = [ "num-traits", "pxfm", @@ -2330,9 +2230,9 @@ dependencies = [ [[package]] name = "muda" -version = "0.17.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c1738382f66ed56b3b9c8119e794a2e23148ac8ea214eda86622d4cb9d415a" +checksum = "cca139e57da4383727f189e43e66e84fa372347027fc996f9f1a007ec0a37996" dependencies = [ "crossbeam-channel", "dpi", @@ -2343,20 +2243,26 @@ dependencies = [ "objc2-core-foundation", "objc2-foundation", "once_cell", - "png 0.17.16", + "png 0.18.1", "serde", - "thiserror 2.0.18", - "windows-sys 0.60.2", + "thiserror 2.0.21", + "windows-sys 0.61.2", ] +[[package]] +name = "multiversion_no_op" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743fb55ba31b18fb1ecef6bdc9aa2743314978ac084044301a7eee33fb99a20d" + [[package]] name = "ndk" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.11.0", - "jni-sys", + "bitflags 2.13.2", + "jni-sys 0.3.1", "log", "ndk-sys", "num_enum", @@ -2376,7 +2282,7 @@ version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ - "jni-sys", + "jni-sys 0.3.1", ] [[package]] @@ -2399,12 +2305,6 @@ dependencies = [ "pin-utils", ] -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - [[package]] name = "nom" version = "8.0.0" @@ -2416,9 +2316,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-traits" @@ -2431,9 +2331,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" dependencies = [ "num_enum_derive", "rustversion", @@ -2441,30 +2341,30 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ "proc-macro-crate 3.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "num_threads" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +checksum = "cabcc654086861f9e1bc5115258de62ef92c79b20f4615a1b0cc57c4e82027d4" dependencies = [ "libc", ] [[package]] name = "objc2" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +checksum = "08849bbd4767dfae9457696856ae1c84fe4e0281bbe4a7abff2d0e06fb7981f8" dependencies = [ "objc2-encode", "objc2-exception-helper", @@ -2476,12 +2376,34 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2", "objc2", "objc2-core-foundation", "objc2-core-graphics", "objc2-foundation", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" +dependencies = [ + "bitflags 2.13.2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" +dependencies = [ + "objc2", + "objc2-foundation", ] [[package]] @@ -2490,7 +2412,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "dispatch2", "objc2", ] @@ -2501,13 +2423,45 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "dispatch2", "objc2", "objc2-core-foundation", "objc2-io-surface", ] +[[package]] +name = "objc2-core-image" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-location" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +dependencies = [ + "bitflags 2.13.2", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", +] + [[package]] name = "objc2-encode" version = "4.1.0" @@ -2529,8 +2483,9 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2", + "libc", "objc2", "objc2-core-foundation", ] @@ -2541,7 +2496,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "objc2", "objc2-core-foundation", ] @@ -2552,7 +2507,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "objc2", "objc2-core-foundation", "objc2-foundation", @@ -2564,9 +2519,28 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", + "block2", "objc2", + "objc2-cloud-kit", + "objc2-core-data", "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image", + "objc2-core-location", + "objc2-core-text", + "objc2-foundation", + "objc2-quartz-core", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" +dependencies = [ + "objc2", "objc2-foundation", ] @@ -2576,7 +2550,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2", "objc2", "objc2-app-kit", @@ -2586,20 +2560,19 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "open" -version = "5.3.3" +version = "5.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43bb73a7fa3799b198970490a51174027ba0d4ec504b03cd08caf513d40024bc" +checksum = "aa576c76302b7b808eecc68061e67336c47833ef9d22caa74dda10fa9675eebc" dependencies = [ "dunce", "is-wsl", "libc", - "pathdiff", ] [[package]] @@ -2663,15 +2636,9 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-link 0.2.1", + "windows-link", ] -[[package]] -name = "pathdiff" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" - [[package]] name = "percent-encoding" version = "2.3.2" @@ -2686,37 +2653,7 @@ checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" dependencies = [ "fixedbitset", "hashbrown 0.15.5", - "indexmap 2.13.0", -] - -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_shared 0.8.0", -] - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_macros 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", -] - -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_macros 0.11.3", - "phf_shared 0.11.3", + "indexmap 2.14.2", ] [[package]] @@ -2725,69 +2662,19 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ - "phf_macros 0.13.1", - "phf_shared 0.13.1", + "phf_macros", + "phf_shared", "serde", ] -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", -] - -[[package]] -name = "phf_codegen" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", -] - [[package]] name = "phf_codegen" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" dependencies = [ - "phf_generator 0.13.1", - "phf_shared 0.13.1", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", -] - -[[package]] -name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" -dependencies = [ - "phf_shared 0.11.3", - "rand 0.8.5", + "phf_generator", + "phf_shared", ] [[package]] @@ -2797,34 +2684,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" dependencies = [ "fastrand", - "phf_shared 0.13.1", -] - -[[package]] -name = "phf_macros" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "phf_macros" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", - "syn 2.0.117", + "phf_shared", ] [[package]] @@ -2833,38 +2693,11 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" dependencies = [ - "phf_generator 0.13.1", - "phf_shared 0.13.1", + "phf_generator", + "phf_shared", "proc-macro2", "quote", - "syn 2.0.117", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher 1.0.2", + "syn 2.0.119", ] [[package]] @@ -2873,7 +2706,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ - "siphasher 1.0.2", + "siphasher", ] [[package]] @@ -2884,25 +2717,25 @@ checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pin-utils" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "13bee6c73da26345c729282832b60b0363cf3dd9f4bfd81d8551b7a1c889a113" [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" [[package]] name = "plist" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" +checksum = "2896bade328c13f7042a297ea5ac5b0951f6cf989dea5f32c2fd98da398195cb" dependencies = [ - "base64 0.22.1", - "indexmap 2.13.0", - "quick-xml 0.38.4", + "base64 0.23.1", + "indexmap 2.14.2", + "quick-xml 0.42.0", "serde", "time", ] @@ -2917,7 +2750,7 @@ dependencies = [ "crc32fast", "fdeflate", "flate2", - "miniz_oxide", + "miniz_oxide 0.8.9", ] [[package]] @@ -2926,11 +2759,26 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "crc32fast", "fdeflate", "flate2", - "miniz_oxide", + "miniz_oxide 0.8.9", +] + +[[package]] +name = "portable-atomic" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" + +[[package]] +name = "portable-atomic-util" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715" +dependencies = [ + "portable-atomic", ] [[package]] @@ -2956,27 +2804,18 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" dependencies = [ "zerovec", ] [[package]] name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] +checksum = "4a6394b9e965e73d0a289ee54f589087e2c676aedf60885baf52c76b771e4958" [[package]] name = "precomputed-hash" @@ -2984,16 +2823,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.117", -] - [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -3020,7 +2849,7 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.25.4+spec-1.1.0", + "toml_edit 0.25.17+spec-1.1.0", ] [[package]] @@ -3047,17 +2876,11 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] @@ -3068,26 +2891,6 @@ version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" -[[package]] -name = "ptr_meta" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" -dependencies = [ - "ptr_meta_derive", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "publicsuffix" version = "2.3.0" @@ -3100,9 +2903,9 @@ dependencies = [ [[package]] name = "pxfm" -version = "0.1.28" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d" +checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" [[package]] name = "quick-error" @@ -3112,27 +2915,27 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.38.4" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" dependencies = [ "memchr", ] [[package]] name = "quick-xml" -version = "0.39.2" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d" +checksum = "41b1177fdf999d2321d3fb46ff47159d9c1fb9ad66a4879f8c50a0b504615e9b" dependencies = [ "memchr", ] [[package]] name = "quinn" -version = "0.11.9" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +checksum = "4051e23e9185c255a7e33ef59cdbca87a22d359052eecd22fc6b901fb37d9d11" dependencies = [ "bytes", "cfg_aliases", @@ -3142,7 +2945,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.18", + "thiserror 2.0.21", "tokio", "tracing", "web-time", @@ -3150,20 +2953,21 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.14" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +checksum = "0e750cca55fe4f0439a15d0bb529da9651e79993e8e72c61a899a36d462befbe" dependencies = [ "bytes", - "getrandom 0.3.4", + "getrandom 0.4.3", "lru-slab", - "rand 0.9.2", + "rand", + "rand_pcg", "ring", "rustc-hash", "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.18", + "thiserror 2.0.21", "tinyvec", "tracing", "web-time", @@ -3171,23 +2975,23 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.14" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +checksum = "af66907df18639dcf4db56ca65490cabc4b27a97dbadd96f2926cca73298f016" dependencies = [ "cfg_aliases", "libc", "once_cell", "socket2", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "quote" -version = "1.0.45" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] @@ -3204,120 +3008,30 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - [[package]] name = "rand" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.5", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.5", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" dependencies = [ - "getrandom 0.2.17", + "chacha20", + "getrandom 0.4.3", + "rand_core", ] [[package]] name = "rand_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" -dependencies = [ - "getrandom 0.3.4", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "rand_pcg" -version = "0.2.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" dependencies = [ - "rand_core 0.5.1", + "rand_core", ] [[package]] @@ -3332,45 +3046,44 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", ] [[package]] name = "redox_users" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +checksum = "60dc65c0ff1a7ae1294b0c67b9f14baf70b644404010370171787bfac1038fc0" dependencies = [ - "getrandom 0.2.17", "libredox", - "thiserror 2.0.18", + "thiserror 2.0.21", ] [[package]] name = "ref-cast" -version = "1.0.25" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.25" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] name = "regex" -version = "1.12.3" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" dependencies = [ "aho-corasick", "memchr", @@ -3380,9 +3093,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" dependencies = [ "aho-corasick", "memchr", @@ -3391,18 +3104,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" - -[[package]] -name = "rend" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" -dependencies = [ - "bytecheck", -] +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "reqwest" @@ -3413,7 +3117,7 @@ dependencies = [ "base64 0.22.1", "bytes", "cookie", - "cookie_store 0.22.1", + "cookie_store", "encoding_rs", "futures-core", "h2", @@ -3449,11 +3153,11 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.13.2" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" +checksum = "16a1cfa75cc186dd73d5818e510e042e40927bccc9c236b061cea97e1eb08029" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", "bytes", "futures-core", "futures-util", @@ -3519,56 +3223,11 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rkyv" -version = "0.7.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" -dependencies = [ - "bitvec", - "bytecheck", - "bytes", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", - "tinyvec", - "uuid", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "rust_decimal" -version = "1.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0" -dependencies = [ - "arrayvec", - "borsh", - "bytes", - "num-traits", - "rand 0.8.5", - "rkyv", - "serde", - "serde_json", -] - [[package]] name = "rustc-hash" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" [[package]] name = "rustc_version" @@ -3581,11 +3240,11 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "errno", "libc", "linux-raw-sys", @@ -3594,9 +3253,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.37" +version = "0.23.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +checksum = "48e13bd8c0e9365c43cfa5c9e8f9ad49d3c8444926c9aac819e0e4dc503c8fdf" dependencies = [ "once_cell", "ring", @@ -3608,9 +3267,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" dependencies = [ "web-time", "zeroize", @@ -3618,9 +3277,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.9" +version = "0.103.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" dependencies = [ "ring", "rustls-pki-types", @@ -3629,9 +3288,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "ryu" @@ -3677,9 +3336,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.2.1" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +checksum = "ab508826f74a77ca9d5aba6ff19b522583ee3eaf28a19384ff3d0e5835fadf6e" dependencies = [ "dyn-clone", "ref-cast", @@ -3696,7 +3355,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -3705,54 +3364,30 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "seahash" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" - -[[package]] -name = "selectors" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" -dependencies = [ - "bitflags 1.3.2", - "cssparser 0.29.6", - "derive_more 0.99.20", - "fxhash", - "log", - "phf 0.8.0", - "phf_codegen 0.8.0", - "precomputed-hash", - "servo_arc 0.2.0", - "smallvec", -] - [[package]] name = "selectors" -version = "0.35.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fdfed56cd634f04fe8b9ddf947ae3dc493483e819593d2ba17df9ad05db8b2" +checksum = "8adfa1c298912827b8a28b223b3b874357397ae706e6190acd9bf28cee99114d" dependencies = [ - "bitflags 2.11.0", - "cssparser 0.36.0", - "derive_more 2.1.1", + "bitflags 2.13.2", + "cssparser", + "derive_more", "log", "new_debug_unreachable", - "phf 0.13.1", - "phf_codegen 0.13.1", + "phf", + "phf_codegen", "precomputed-hash", "rustc-hash", - "servo_arc 0.4.3", + "servo_arc", "smallvec", ] [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" dependencies = [ "serde", "serde_core", @@ -3760,9 +3395,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", "serde_derive", @@ -3782,22 +3417,22 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] @@ -3808,14 +3443,14 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ "itoa", "memchr", @@ -3826,13 +3461,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] @@ -3846,9 +3481,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.4" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +checksum = "4e7523beb55eece201a2356bee0bbca0d1ab466c14c07703b2e0ee6d42cb0c2c" dependencies = [ "serde_core", ] @@ -3867,17 +3502,19 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.17.0" +version = "3.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "381b283ce7bc6b476d903296fb59d0d36633652b633b27f64db4fb46dcbfc3b9" +checksum = "df9adc193c780ef8f159aee8b61e2d5801aaa555e6eb0947fe45530ec506296f" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", + "bs58", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.13.0", + "indexmap 2.14.2", + "jiff", "schemars 0.9.0", - "schemars 1.2.1", + "schemars 1.2.3", "serde_core", "serde_json", "serde_with_macros", @@ -3886,14 +3523,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.17.0" +version = "3.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6d4e30573c8cb306ed6ab1dca8423eec9a463ea0e155f45399455e0368b27e0" +checksum = "3e17bbc68e28663bbbb90df47e058aa7eda4fb445b89fe70457bb94fbccf6e49" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] @@ -3957,17 +3594,7 @@ checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", -] - -[[package]] -name = "servo_arc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741" -dependencies = [ - "nodrop", - "stable_deref_trait", + "syn 2.0.119", ] [[package]] @@ -3986,19 +3613,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest", ] [[package]] name = "shared_child" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e362d9935bc50f019969e2f9ecd66786612daae13e8f277be7bfb66e8bed3f7" +checksum = "607549934f6cc26b89cfecfdc46fa90f1e5d1536a68349b0c3a4f9d1c0d37959" dependencies = [ "libc", - "sigchld", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4019,46 +3645,15 @@ checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" [[package]] name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "sigchld" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47106eded3c154e70176fc83df9737335c94ce22f821c32d17ed1db1f83badb1" -dependencies = [ - "libc", - "os_pipe", - "signal-hook", -] - -[[package]] -name = "signal-hook" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.8" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" -dependencies = [ - "errno", - "libc", -] +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "simd-adler32" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" [[package]] name = "simdutf8" @@ -4068,15 +3663,9 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "siphasher" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" +checksum = "33f4fe9184a62d842c9ef383018f3306d8ba224fd9d836f56d7288308847c256" [[package]] name = "slab" @@ -4086,15 +3675,15 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.15.1" +version = "1.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "5b3dc8af474f516a851ff4bd12db780f948b9250ad37211e4eec0bccea54e01b" [[package]] name = "socket2" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", "windows-sys 0.61.2", @@ -4155,17 +3744,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] -name = "string_cache" -version = "0.8.9" +name = "static_vcruntime" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" -dependencies = [ - "new_debug_unreachable", - "parking_lot", - "phf_shared 0.11.3", - "precomputed-hash", - "serde", -] +checksum = "ff7589a1859b09232522bb9edf076ca7fcf14ded96685d3fa629db73023ffbb7" [[package]] name = "string_cache" @@ -4175,30 +3757,18 @@ checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901" dependencies = [ "new_debug_unreachable", "parking_lot", - "phf_shared 0.13.1", + "phf_shared", "precomputed-hash", ] -[[package]] -name = "string_cache_codegen" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", -] - [[package]] name = "string_cache_codegen" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" dependencies = [ - "phf_generator 0.13.1", - "phf_shared 0.13.1", + "phf_generator", + "phf_shared", "proc-macro2", "quote", ] @@ -4217,9 +3787,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "swift-rs" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" +checksum = "cefd87076fd385308ee4aff597256c902f1fbb4d031de1558efc12f8ffefadd9" dependencies = [ "base64 0.21.7", "serde", @@ -4231,6 +3801,16 @@ name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" dependencies = [ "proc-macro2", "quote", @@ -4239,9 +3819,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.117" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" dependencies = [ "proc-macro2", "quote", @@ -4259,13 +3839,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] @@ -4274,7 +3854,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -4304,15 +3884,16 @@ dependencies = [ [[package]] name = "tao" -version = "0.34.6" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d52c379e63da659a483a958110bbde891695a0ecb53e48cc7786d5eda7bb" +checksum = "f37f381f4e048e6cdf038b5705f8cf14ad108279d46eb968140a7b291aba9400" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "block2", "core-foundation 0.10.1", "core-graphics", "crossbeam-channel", + "dbus", "dispatch2", "dlopen2", "dpi", @@ -4328,35 +3909,30 @@ dependencies = [ "objc2", "objc2-app-kit", "objc2-foundation", - "once_cell", + "objc2-ui-kit", "parking_lot", + "percent-encoding", "raw-window-handle", "tao-macros", "unicode-segmentation", "url", "windows", - "windows-core 0.61.2", + "windows-core", "windows-version", "x11-dl", ] [[package]] name = "tao-macros" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +checksum = "5f7eeb6d99155545da6150a1795945f16ac9c178deb2a5f2e74d776107bd5849" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "target-lexicon" version = "0.12.16" @@ -4365,9 +3941,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.10.3" +version = "2.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da77cc00fb9028caf5b5d4650f75e31f1ef3693459dfca7f7e506d1ecef0ba2d" +checksum = "f316751027fc2644221d1a448564d519efb07067fda584879d9cda966391d212" dependencies = [ "anyhow", "bytes", @@ -4393,7 +3969,7 @@ dependencies = [ "percent-encoding", "plist", "raw-window-handle", - "reqwest 0.13.2", + "reqwest 0.13.5", "serde", "serde_json", "serde_repr", @@ -4404,21 +3980,21 @@ dependencies = [ "tauri-runtime", "tauri-runtime-wry", "tauri-utils", - "thiserror 2.0.18", + "thiserror 2.0.21", "tokio", "tray-icon", "url", "webkit2gtk", "webview2-com", - "window-vibrancy 0.6.0", + "window-vibrancy 0.8.1", "windows", ] [[package]] name = "tauri-build" -version = "2.5.6" +version = "2.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bbc990d1dbf57a8e1c7fa2327f2a614d8b757805603c1b9ba5c81bade09fd4d" +checksum = "641dd5fd297c99ab92717b0428cca5b9c6f960b2ac96ca131b3eebc9d70b8ddc" dependencies = [ "anyhow", "cargo_toml", @@ -4430,33 +4006,34 @@ dependencies = [ "semver", "serde", "serde_json", + "static_vcruntime", + "strsim", "tauri-utils", "tauri-winres", - "toml 0.9.12+spec-1.1.0", "walkdir", ] [[package]] name = "tauri-codegen" -version = "2.5.5" +version = "2.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a24476afd977c5d5d169f72425868613d82747916dd29e0a357c84c4bd6d29" +checksum = "a6585c5b536c00f039d12ce70a9755172d5423bbcfd3969863baa70314c3e02f" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", "brotli", "ico", "json-patch", "plist", - "png 0.17.16", + "png 0.18.1", "proc-macro2", "quote", "semver", "serde", "serde_json", "sha2", - "syn 2.0.117", + "syn 2.0.119", "tauri-utils", - "thiserror 2.0.18", + "thiserror 2.0.21", "time", "url", "uuid", @@ -4465,23 +4042,23 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.5.5" +version = "2.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39b349a98dadaffebb73f0a40dcd1f23c999211e5a2e744403db384d0c33de7" +checksum = "e2e83a0cfa1bae376e8fbbdc0b1692707aed50cd6072ce85cae4789af5d6c19f" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", "tauri-codegen", "tauri-utils", ] [[package]] name = "tauri-plugin" -version = "2.5.4" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddde7d51c907b940fb573006cdda9a642d6a7c8153657e88f8a5c3c9290cd4aa" +checksum = "67fb21a77e8f94e8beb3325e583102488659365af0a3948b7ea244c5b779c291" dependencies = [ "anyhow", "glob", @@ -4490,15 +4067,14 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "toml 0.9.12+spec-1.1.0", "walkdir", ] [[package]] name = "tauri-plugin-clipboard-manager" -version = "2.3.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206dc20af4ed210748ba945c2774e60fd0acd52b9a73a028402caf809e9b6ecf" +checksum = "9be5ed8d94c33afe8377e885119069f6508780659271d0a25cfc54d441f2bc81" dependencies = [ "arboard", "log", @@ -4506,14 +4082,14 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.18", + "thiserror 2.0.21", ] [[package]] name = "tauri-plugin-dialog" -version = "2.6.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9204b425d9be8d12aa60c2a83a289cf7d1caae40f57f336ed1155b3a5c0e359b" +checksum = "b7461aaacf1901915ea7b9f5cd74f8224a351ed96af0a62c07fce934003cb34b" dependencies = [ "log", "raw-window-handle", @@ -4523,19 +4099,21 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-plugin-fs", - "thiserror 2.0.18", + "thiserror 2.0.21", "url", ] [[package]] name = "tauri-plugin-fs" -version = "2.4.5" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed390cc669f937afeb8b28032ce837bac8ea023d975a2e207375ec05afaf1804" +checksum = "5d58eb1d4984e535f47a642ffec09a2da6f5c18a12b5902d12126cb7626d628b" dependencies = [ "anyhow", "dunce", "glob", + "log", + "objc2-foundation", "percent-encoding", "schemars 0.8.22", "serde", @@ -4544,19 +4122,19 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-utils", - "thiserror 2.0.18", - "toml 0.9.12+spec-1.1.0", + "thiserror 2.0.21", + "toml 1.1.8+spec-1.1.0", "url", ] [[package]] name = "tauri-plugin-http" -version = "2.5.7" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8f069451c4e87e7e2636b7f065a4c52866c4ce5e60e2d53fa1038edb6d184dc" +checksum = "2c57e3451553f95a1db3bfed6a358a77ce5080b6399a242c6eadac113f97abd2" dependencies = [ "bytes", - "cookie_store 0.21.1", + "cookie_store", "data-url", "http", "regex", @@ -4567,7 +4145,7 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-plugin-fs", - "thiserror 2.0.18", + "thiserror 2.0.21", "tokio", "url", "urlpattern", @@ -4575,27 +4153,26 @@ dependencies = [ [[package]] name = "tauri-plugin-localhost" -version = "2.3.2" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c8d72c024121b1a3d9268293d49a56baf01a8c785561c85d17872588b839e55" +checksum = "a8c9c1c5b33e5f19317f30520a9ce542e231fabc1b793da70337151dc01f3bb4" dependencies = [ "http", "log", "serde", "serde_json", "tauri", - "thiserror 2.0.18", + "thiserror 2.0.21", "tiny_http", ] [[package]] name = "tauri-plugin-log" -version = "2.8.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7545bd67f070a4500432c826e2e0682146a1d6712aee22a2786490156b574d93" +checksum = "d83980f6765feb86cf2224959246be28b0488e14a23204a719f7f9deecfc64c9" dependencies = [ "android_logger", - "byte-unit", "fern", "log", "objc2", @@ -4606,17 +4183,18 @@ dependencies = [ "swift-rs", "tauri", "tauri-plugin", - "thiserror 2.0.18", + "thiserror 2.0.21", "time", ] [[package]] name = "tauri-plugin-shell" -version = "2.3.5" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8457dbf9e2bab1edd8df22bb2c20857a59a9868e79cb3eac5ed639eec4d0c73b" +checksum = "8567d42b2c7264355daa1df415ec77f52aa42e885924c86a969be2e920e05521" dependencies = [ "encoding_rs", + "libc", "log", "open", "os_pipe", @@ -4627,30 +4205,31 @@ dependencies = [ "shared_child", "tauri", "tauri-plugin", - "thiserror 2.0.18", + "thiserror 2.0.21", "tokio", + "windows-sys 0.60.2", ] [[package]] name = "tauri-plugin-window-state" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73736611e14142408d15353e21e3cca2f12a3cfb523ad0ce85999b6d2ef1a704" +checksum = "5d6815cab7b212f9cfe16a9d79d8d22f9e14159e4a9460f7dec1467167a008e3" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "log", "serde", "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.18", + "thiserror 2.0.21", ] [[package]] name = "tauri-runtime" -version = "2.10.1" +version = "2.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2826d79a3297ed08cd6ea7f412644ef58e32969504bc4fbd8d7dbeabc4445ea2" +checksum = "7c55766d99cea69055904d1735b93c2049302b2e09effd462120deb5581d78e9" dependencies = [ "cookie", "dpi", @@ -4664,7 +4243,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "thiserror 2.0.18", + "thiserror 2.0.21", "url", "webkit2gtk", "webview2-com", @@ -4673,9 +4252,9 @@ dependencies = [ [[package]] name = "tauri-runtime-wry" -version = "2.10.1" +version = "2.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e11ea2e6f801d275fdd890d6c9603736012742a1c33b96d0db788c9cdebf7f9e" +checksum = "8d61892587aea2a85245bcaec98c6fe46268874c0a0deae5535fb71ca7b93eae" dependencies = [ "gtk", "http", @@ -4699,24 +4278,24 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "2.8.3" +version = "2.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219a1f983a2af3653f75b5747f76733b0da7ff03069c7a41901a5eb3ace4557d" +checksum = "362ab21cd4cc713f2a02b1a9b5688198b1541cfb6907c4281e9190e0f0ef4aa3" dependencies = [ "anyhow", "brotli", "cargo_metadata", "ctor", + "dom_query", "dunce", "glob", - "html5ever 0.29.1", "http", "infer", "json-patch", - "kuchikiki", "log", "memchr", - "phf 0.11.3", + "phf", + "plist", "proc-macro2", "quote", "regex", @@ -4727,8 +4306,8 @@ dependencies = [ "serde_json", "serde_with", "swift-rs", - "thiserror 2.0.18", - "toml 0.9.12+spec-1.1.0", + "thiserror 2.0.21", + "toml 1.1.8+spec-1.1.0", "url", "urlpattern", "uuid", @@ -4737,24 +4316,22 @@ dependencies = [ [[package]] name = "tauri-winres" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1087b111fe2b005e42dbdc1990fc18593234238d47453b0c99b7de1c9ab2c1e0" +checksum = "cc65d45c68858bfe420dd29e834b5d15dbecf8a07a8a16cf4d532c7b1f69d4b6" dependencies = [ "dunce", "embed-resource", - "toml 0.9.12+spec-1.1.0", + "toml 1.1.8+spec-1.1.0", ] [[package]] name = "tendril" -version = "0.4.3" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +checksum = "5fed54709c5b3a53d09bb1c113ea4f5ceafd1e772ddcb0030a82e1d56c087b08" dependencies = [ - "futf", - "mac", - "utf-8", + "new_debug_unreachable", ] [[package]] @@ -4777,11 +4354,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" dependencies = [ - "thiserror-impl 2.0.18", + "thiserror-impl 2.0.21", ] [[package]] @@ -4792,25 +4369,25 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] name = "tiff" -version = "0.10.3" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" +checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" dependencies = [ "fax", "flate2", @@ -4822,12 +4399,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.47" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" dependencies = [ "deranged", - "itoa", "libc", "num-conv", "num_threads", @@ -4839,15 +4415,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" dependencies = [ "num-conv", "time-core", @@ -4867,9 +4443,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" dependencies = [ "displaydoc", "zerovec", @@ -4877,24 +4453,15 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" [[package]] name = "tokio" -version = "1.50.0" +version = "1.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +checksum = "ce3335fa71841cda333a58d7615b03901380ecf09d59b3296d21f8bbac0dde4e" dependencies = [ "bytes", "libc", @@ -4907,20 +4474,20 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.6.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] [[package]] name = "tokio-rustls" -version = "0.26.4" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +checksum = "c9cc2678c2cdd569ef8215e2afd7954ada2ae20b4fdd2c5fe6139a3b02d105db" dependencies = [ "rustls", "tokio", @@ -4928,13 +4495,14 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.18" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +checksum = "e464cf451ba96ebfc6f9b6542f17ee8b8956e33f1e40d9690624e59d7a7f8a4b" dependencies = [ "bytes", "futures-core", "futures-sink", + "libc", "pin-project-lite", "tokio", ] @@ -4953,17 +4521,17 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.12+spec-1.1.0" +version = "1.1.8+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +checksum = "20489e00e4d8741d6be680764cc12e270655e375a20d1011e844a9c3379e678d" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.2", "serde_core", - "serde_spanned 1.0.4", - "toml_datetime 0.7.5+spec-1.1.0", + "serde_spanned 1.1.2", + "toml_datetime 1.1.2+spec-1.1.0", "toml_parser", "toml_writer", - "winnow 0.7.15", + "winnow 1.0.4", ] [[package]] @@ -4977,18 +4545,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.5+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" -dependencies = [ - "serde_core", -] - -[[package]] -name = "toml_datetime" -version = "1.0.0+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" +checksum = "2b86d767906c6c42421dcba507eb9d203e779497710a47782a224bb871653053" dependencies = [ "serde_core", ] @@ -4999,7 +4558,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.2", "toml_datetime 0.6.3", "winnow 0.5.40", ] @@ -5010,7 +4569,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.2", "serde", "serde_spanned 0.6.9", "toml_datetime 0.6.3", @@ -5019,30 +4578,30 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.4+spec-1.1.0" +version = "0.25.17+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2" +checksum = "e3641d5bbb5349a79e1020a242d251efbc546ad8048d133958323ce9c40a9c9c" dependencies = [ - "indexmap 2.13.0", - "toml_datetime 1.0.0+spec-1.1.0", + "indexmap 2.14.2", + "toml_datetime 1.1.2+spec-1.1.0", "toml_parser", - "winnow 0.7.15", + "winnow 1.0.4", ] [[package]] name = "toml_parser" -version = "1.0.9+spec-1.1.0" +version = "1.1.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c" dependencies = [ - "winnow 0.7.15", + "winnow 1.0.4", ] [[package]] name = "toml_writer" -version = "1.0.6+spec-1.1.0" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" +checksum = "06bdbd8cfc056b8d2e2e85f29b56a3bdbecb527cef81eb39e3e7b98af4652770" [[package]] name = "tower" @@ -5061,20 +4620,20 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "bytes", "futures-util", "http", "http-body", - "iri-string", "pin-project-lite", "tower", "tower-layer", "tower-service", + "url", ] [[package]] @@ -5110,9 +4669,9 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.21.3" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e85aa143ceb072062fc4d6356c1b520a51d636e7bc8e77ec94be3608e5e80c" +checksum = "b2b9c52859a94554803ccd4a24b98f74148ebc73b90676d783f3490b1bff9d72" dependencies = [ "crossbeam-channel", "dirs", @@ -5124,10 +4683,10 @@ dependencies = [ "objc2-core-graphics", "objc2-foundation", "once_cell", - "png 0.17.16", + "png 0.18.1", "serde", - "thiserror 2.0.18", - "windows-sys 0.60.2", + "thiserror 2.0.21", + "windows-sys 0.61.2", ] [[package]] @@ -5155,68 +4714,21 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-ucd-ident" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" [[package]] name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-xid" -version = "0.2.6" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "untrusted" @@ -5239,28 +4751,16 @@ dependencies = [ [[package]] name = "urlpattern" -version = "0.3.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" +checksum = "df16f50ef4cc145211879a3867ba757076b25dfee812040dcb0658bd9ae7904b" dependencies = [ + "icu_properties", "regex", "serde", - "unic-ucd-ident", "url", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "utf8-width" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1292c0d970b54115d14f2492fe0170adf21d68a1de108eebc51c1df4f346a091" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -5269,22 +4769,16 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.22.0" +version = "1.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" +checksum = "7cc1186384beb7dd8eedea376413fd654937285ea6c9cfbb928dc3043ea4b606" dependencies = [ - "getrandom 0.4.2", + "getrandom 0.4.3", "js-sys", "serde_core", "wasm-bindgen", ] -[[package]] -name = "value-bag" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" - [[package]] name = "version-compare" version = "0.2.1" @@ -5329,19 +4823,13 @@ dependencies = [ [[package]] name = "want" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +checksum = "ec4cdd0dd910afe868b7ef477227d8d538b46b3075031afee8a9f2acb0a2ed0b" dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -5350,27 +4838,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.114" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409" dependencies = [ "cfg-if", "once_cell", @@ -5381,23 +4860,20 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.64" +version = "0.4.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" +checksum = "3cbab34de2d982e9b48e18d216d04c4a6f641066ff19ffb699980f591ee3610e" dependencies = [ - "cfg-if", - "futures-util", "js-sys", - "once_cell", + "tokio", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.114" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5405,48 +4881,26 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.114" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.114" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6" dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap 2.13.0", - "wasm-encoder", - "wasmparser", -] - [[package]] name = "wasm-streams" version = "0.5.0" @@ -5460,23 +4914,11 @@ dependencies = [ "web-sys", ] -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags 2.11.0", - "hashbrown 0.15.5", - "indexmap 2.13.0", - "semver", -] - [[package]] name = "wayland-backend" -version = "0.3.14" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa75f400b7f719bcd68b3f47cd939ba654cedeef690f486db71331eec4c6a406" +checksum = "38a91b4eaddff87b1cd1074985e3713da4af2c49742d1b356b2c01670a67a078" dependencies = [ "cc", "downcast-rs", @@ -5487,11 +4929,11 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.13" +version = "0.31.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab51d9f7c071abeee76007e2b742499e535148035bb835f97aaed1338cf516c3" +checksum = "e3c36a0f861ad76d0901f2800b46321410d9f73f2ea88aac0650d86c32688073" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "rustix", "wayland-backend", "wayland-scanner", @@ -5499,11 +4941,11 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.32.11" +version = "0.32.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b23b5df31ceff1328f06ac607591d5ba360cf58f90c8fad4ac8d3a55a3c4aec7" +checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "wayland-backend", "wayland-client", "wayland-scanner", @@ -5511,11 +4953,11 @@ dependencies = [ [[package]] name = "wayland-protocols-wlr" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78248e4cc0eff8163370ba5c158630dcae1f3497a586b826eca2ef5f348d6235" +checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.13.2", "wayland-backend", "wayland-client", "wayland-protocols", @@ -5524,29 +4966,29 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.9" +version = "0.31.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c86287151a309799b821ca709b7345a048a2956af05957c89cb824ab919fa4e3" +checksum = "338e30461b3a2b67d70eb30a6d89f8e0c93a833e07d2ae89085cd070c4a00ac0" dependencies = [ "proc-macro2", - "quick-xml 0.39.2", + "quick-xml 0.41.0", "quote", ] [[package]] name = "wayland-sys" -version = "0.31.10" +version = "0.31.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374f6b70e8e0d6bf9461a32988fd553b59ff630964924dad6e4a4eb6bd538d17" +checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be" dependencies = [ "pkg-config", ] [[package]] name = "web-sys" -version = "0.3.91" +version = "0.3.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" +checksum = "88261b9deccee56594c11a3460c462c41f58d148598fe70ad77070126a68aba4" dependencies = [ "js-sys", "wasm-bindgen", @@ -5564,14 +5006,14 @@ dependencies = [ [[package]] name = "web_atoms" -version = "0.2.3" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a9779e9f04d2ac1ce317aee707aa2f6b773afba7b931222bff6983843b1576" +checksum = "ba8b815c1b593dc0baf78dd0f4fc8fdb2de53198fb1163738093e9a311c33fb3" dependencies = [ - "phf 0.13.1", - "phf_codegen 0.13.1", - "string_cache 0.9.0", - "string_cache_codegen 0.6.1", + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", ] [[package]] @@ -5620,25 +5062,23 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" dependencies = [ "rustls-pki-types", ] [[package]] name = "webview2-com" -version = "0.38.2" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" +checksum = "3f89fca7a704cee10dcb3654c1dbb8941d1783132f1917358af75bec37a7d7e6" dependencies = [ "webview2-com-macros", "webview2-com-sys", "windows", - "windows-core 0.61.2", - "windows-implement", - "windows-interface", + "windows-core", ] [[package]] @@ -5649,18 +5089,18 @@ checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "webview2-com-sys" -version = "0.38.2" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" +checksum = "b3a07132775117d6065853d9d1178157b8c90e228de47129d6bce2c7edebedfb" dependencies = [ - "thiserror 2.0.18", + "thiserror 2.0.21", "windows", - "windows-core 0.61.2", + "windows-core", ] [[package]] @@ -5702,67 +5142,54 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "window-vibrancy" -version = "0.6.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" +checksum = "010797bd7c40396fbc59d3105089fed0885fe267a0ef4a0a4646df54e28647f6" dependencies = [ "objc2", "objc2-app-kit", "objc2-core-foundation", "objc2-foundation", "raw-window-handle", - "windows-sys 0.59.0", + "windows-sys 0.60.2", "windows-version", ] [[package]] name = "window-vibrancy" -version = "0.7.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "010797bd7c40396fbc59d3105089fed0885fe267a0ef4a0a4646df54e28647f6" +checksum = "111e51caca442cafd9bab396628ac4d814880eaea4e63dfd76a12e9f342b5580" dependencies = [ "objc2", "objc2-app-kit", "objc2-core-foundation", "objc2-foundation", + "objc2-quartz-core", "raw-window-handle", - "windows-sys 0.60.2", + "windows-sys 0.61.2", "windows-version", ] [[package]] name = "windows" -version = "0.61.3" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" dependencies = [ "windows-collections", - "windows-core 0.61.2", + "windows-core", "windows-future", - "windows-link 0.1.3", "windows-numerics", ] [[package]] name = "windows-collections" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" -dependencies = [ - "windows-core 0.61.2", -] - -[[package]] -name = "windows-core" -version = "0.61.2" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ - "windows-implement", - "windows-interface", - "windows-link 0.1.3", - "windows-result 0.3.4", - "windows-strings 0.4.2", + "windows-core", ] [[package]] @@ -5773,19 +5200,19 @@ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.2.1", - "windows-result 0.4.1", - "windows-strings 0.5.1", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] name = "windows-future" -version = "0.2.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.3", + "windows-core", + "windows-link", "windows-threading", ] @@ -5797,7 +5224,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -5808,15 +5235,9 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - [[package]] name = "windows-link" version = "0.2.1" @@ -5825,12 +5246,12 @@ checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-numerics" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.3", + "windows-core", + "windows-link", ] [[package]] @@ -5839,18 +5260,9 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" dependencies = [ - "windows-link 0.2.1", - "windows-result 0.4.1", - "windows-strings 0.5.1", -] - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link 0.1.3", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] @@ -5859,16 +5271,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link 0.1.3", + "windows-link", ] [[package]] @@ -5877,7 +5280,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -5898,15 +5301,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.60.2" @@ -5922,7 +5316,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -5962,7 +5356,7 @@ version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.2.1", + "windows-link", "windows_aarch64_gnullvm 0.53.1", "windows_aarch64_msvc 0.53.1", "windows_i686_gnu 0.53.1", @@ -5975,11 +5369,11 @@ dependencies = [ [[package]] name = "windows-threading" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" dependencies = [ - "windows-link 0.1.3", + "windows-link", ] [[package]] @@ -5988,7 +5382,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -6140,9 +5534,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.15" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" dependencies = [ "memchr", ] @@ -6158,113 +5552,31 @@ dependencies = [ [[package]] name = "winreg" -version = "0.55.0" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" +checksum = "7d6f32a0ff4a9f6f01231eb2059cc85479330739333e0e58cadf03b6af2cca10" dependencies = [ "cfg-if", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck 0.5.0", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck 0.5.0", - "indexmap 2.13.0", - "prettyplease", - "syn 2.0.117", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.117", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags 2.11.0", - "indexmap 2.13.0", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap 2.13.0", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "wl-clipboard-rs" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9651471a32e87d96ef3a127715382b2d11cc7c8bb9822ded8a7cc94072eb0a3" +checksum = "4d7888ccd4896447b2d14d3a9350a85df2aeb6f181e2e7a31349d104ac46cac1" dependencies = [ "libc", "log", "os_pipe", "rustix", - "thiserror 2.0.18", + "thiserror 2.0.21", "tree_magic_mini", "wayland-backend", "wayland-client", @@ -6274,15 +5586,15 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" [[package]] name = "wry" -version = "0.54.3" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a24eda84b5d488f99344e54b807138896cee8df0b2d16c793f1f6b80e6d8df1f" +checksum = "a819957a01b3119af85e638a38d242af76dbc87d130dca67bfd0441072e21ff0" dependencies = [ "base64 0.22.1", "block2", @@ -6311,26 +5623,17 @@ dependencies = [ "sha2", "soup3", "tao-macros", - "thiserror 2.0.18", + "thiserror 2.0.21", "url", "webkit2gtk", "webkit2gtk-sys", "webview2-com", "windows", - "windows-core 0.61.2", + "windows-core", "windows-version", "x11-dl", ] -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - [[package]] name = "x11" version = "2.21.0" @@ -6371,9 +5674,9 @@ checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -6382,68 +5685,68 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.42" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" +checksum = "e5fe1f8f1b06191a00962174c61aa5005e0bb391a6d80d07e24d115c01a92ed8" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.42" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" +checksum = "863ad3ac83293fb4d740aedbfdc9240dd8d1a50c1099acd76ce80ce7c7230c7f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.2" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +checksum = "e13084392c5e4bc371903e2935a5eaeed24905a7511356b883835e18a78f6879" [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" dependencies = [ "displaydoc", "yoke", @@ -6452,9 +5755,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" dependencies = [ "yoke", "zerofrom", @@ -6463,32 +5766,38 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.9", ] +[[package]] +name = "zlib-rs" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112" + [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" [[package]] name = "zune-core" -version = "0.4.12" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" +checksum = "d56377fd46368984a170bc5aac5567e52ca5da874caa60bea39fcbca78fb658b" [[package]] name = "zune-jpeg" -version = "0.4.21" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" dependencies = [ "zune-core", ] From 2ff0b69463055c6fc40db0c39fc0267af568d862 Mon Sep 17 00:00:00 2001 From: Alex Cinovoj <135995822+Alexi5000@users.noreply.github.com> Date: Sun, 18 Oct 2026 01:20:56 -0400 Subject: [PATCH 4/7] fix: backport upstream GLib iterator soundness patch for GTK3 (#4) Co-authored-by: zocomputer --- .github/workflows/ci.yml | 9 + src-tauri/Cargo.lock | 2 - src-tauri/Cargo.toml | 3 + src-tauri/vendor/glib/.gitignore | 1 + src-tauri/vendor/glib/COPYRIGHT | 14 + src-tauri/vendor/glib/Cargo.lock | 1055 ++++ src-tauri/vendor/glib/Cargo.toml | 185 + src-tauri/vendor/glib/Cargo.toml.orig | 74 + src-tauri/vendor/glib/Gir.toml | 816 +++ src-tauri/vendor/glib/Gir_GObject.toml | 149 + src-tauri/vendor/glib/LICENSE | 18 + src-tauri/vendor/glib/README.md | 101 + src-tauri/vendor/glib/SECURITY-BACKPORT.md | 17 + src-tauri/vendor/glib/benches/gstring.rs | 46 + src-tauri/vendor/glib/src/auto/alias.rs | 13 + src-tauri/vendor/glib/src/auto/checksum.rs | 46 + src-tauri/vendor/glib/src/auto/constants.rs | 105 + src-tauri/vendor/glib/src/auto/date_time.rs | 502 ++ src-tauri/vendor/glib/src/auto/enums.rs | 2661 ++++++++++ src-tauri/vendor/glib/src/auto/flags.rs | 636 +++ src-tauri/vendor/glib/src/auto/functions.rs | 863 ++++ src-tauri/vendor/glib/src/auto/key_file.rs | 487 ++ .../vendor/glib/src/auto/main_context.rs | 142 + src-tauri/vendor/glib/src/auto/main_loop.rs | 56 + .../glib/src/auto/markup_parse_context.rs | 99 + src-tauri/vendor/glib/src/auto/mod.rs | 123 + src-tauri/vendor/glib/src/auto/source.rs | 128 + src-tauri/vendor/glib/src/auto/time_zone.rs | 91 + src-tauri/vendor/glib/src/auto/uri.rs | 535 ++ src-tauri/vendor/glib/src/auto/versions.txt | 2 + src-tauri/vendor/glib/src/boxed.rs | 606 +++ src-tauri/vendor/glib/src/boxed_any_object.rs | 191 + src-tauri/vendor/glib/src/boxed_inline.rs | 643 +++ src-tauri/vendor/glib/src/bridged_logging.rs | 385 ++ src-tauri/vendor/glib/src/byte_array.rs | 160 + src-tauri/vendor/glib/src/bytes.rs | 277 + src-tauri/vendor/glib/src/char.rs | 220 + src-tauri/vendor/glib/src/checksum.rs | 74 + src-tauri/vendor/glib/src/clone.rs | 101 + src-tauri/vendor/glib/src/closure.rs | 447 ++ src-tauri/vendor/glib/src/collections/list.rs | 894 ++++ src-tauri/vendor/glib/src/collections/mod.rs | 16 + .../vendor/glib/src/collections/ptr_slice.rs | 1371 +++++ .../vendor/glib/src/collections/slice.rs | 991 ++++ .../vendor/glib/src/collections/slist.rs | 887 ++++ src-tauri/vendor/glib/src/collections/strv.rs | 1544 ++++++ src-tauri/vendor/glib/src/control_flow.rs | 103 + src-tauri/vendor/glib/src/convert.rs | 448 ++ src-tauri/vendor/glib/src/date.rs | 443 ++ src-tauri/vendor/glib/src/date_time.rs | 15 + src-tauri/vendor/glib/src/enums.rs | 966 ++++ src-tauri/vendor/glib/src/error.rs | 325 ++ src-tauri/vendor/glib/src/exit_code.rs | 33 + .../vendor/glib/src/future_with_timeout.rs | 103 + .../vendor/glib/src/gobject/auto/binding.rs | 59 + .../glib/src/gobject/auto/binding_group.rs | 94 + .../vendor/glib/src/gobject/auto/flags.rs | 152 + src-tauri/vendor/glib/src/gobject/auto/mod.rs | 24 + .../glib/src/gobject/auto/signal_group.rs | 73 + src-tauri/vendor/glib/src/gobject/binding.rs | 307 ++ .../vendor/glib/src/gobject/binding_group.rs | 507 ++ src-tauri/vendor/glib/src/gobject/flags.rs | 59 + src-tauri/vendor/glib/src/gobject/mod.rs | 22 + .../vendor/glib/src/gobject/signal_group.rs | 248 + src-tauri/vendor/glib/src/gstring.rs | 2547 +++++++++ src-tauri/vendor/glib/src/gstring_builder.rs | 367 ++ src-tauri/vendor/glib/src/key_file.rs | 282 + src-tauri/vendor/glib/src/lib.rs | 231 + src-tauri/vendor/glib/src/log.rs | 1069 ++++ src-tauri/vendor/glib/src/main_context.rs | 279 + .../vendor/glib/src/main_context_channel.rs | 896 ++++ .../vendor/glib/src/main_context_futures.rs | 810 +++ src-tauri/vendor/glib/src/manual_functions.rs | 288 ++ src-tauri/vendor/glib/src/object.rs | 4542 +++++++++++++++++ src-tauri/vendor/glib/src/param_spec.rs | 2316 +++++++++ src-tauri/vendor/glib/src/prelude.rs | 9 + src-tauri/vendor/glib/src/property.rs | 303 ++ src-tauri/vendor/glib/src/quark.rs | 103 + src-tauri/vendor/glib/src/shared.rs | 588 +++ src-tauri/vendor/glib/src/signal.rs | 226 + src-tauri/vendor/glib/src/source.rs | 1197 +++++ src-tauri/vendor/glib/src/source_futures.rs | 482 ++ src-tauri/vendor/glib/src/subclass/basic.rs | 72 + src-tauri/vendor/glib/src/subclass/boxed.rs | 109 + .../vendor/glib/src/subclass/interface.rs | 217 + src-tauri/vendor/glib/src/subclass/mod.rs | 267 + src-tauri/vendor/glib/src/subclass/object.rs | 717 +++ .../glib/src/subclass/object_impl_ref.rs | 163 + src-tauri/vendor/glib/src/subclass/shared.rs | 295 ++ src-tauri/vendor/glib/src/subclass/signal.rs | 715 +++ src-tauri/vendor/glib/src/subclass/types.rs | 1127 ++++ src-tauri/vendor/glib/src/thread_guard.rs | 114 + src-tauri/vendor/glib/src/thread_pool.rs | 254 + src-tauri/vendor/glib/src/time_span.rs | 99 + src-tauri/vendor/glib/src/time_zone.rs | 15 + src-tauri/vendor/glib/src/translate.rs | 2969 +++++++++++ src-tauri/vendor/glib/src/types.rs | 678 +++ src-tauri/vendor/glib/src/unichar.rs | 243 + src-tauri/vendor/glib/src/unicollate.rs | 88 + src-tauri/vendor/glib/src/utils.rs | 278 + src-tauri/vendor/glib/src/value.rs | 1665 ++++++ src-tauri/vendor/glib/src/value_array.rs | 251 + src-tauri/vendor/glib/src/variant.rs | 2520 +++++++++ src-tauri/vendor/glib/src/variant_dict.rs | 293 ++ src-tauri/vendor/glib/src/variant_iter.rs | 371 ++ src-tauri/vendor/glib/src/variant_type.rs | 1083 ++++ src-tauri/vendor/glib/src/win32.rs | 95 + src-tauri/vendor/glib/src/wrapper.rs | 445 ++ src-tauri/vendor/glib/tests/check_gir.rs | 8 + src-tauri/vendor/glib/tests/clone.rs | 635 +++ src-tauri/vendor/glib/tests/derive.rs | 33 + src-tauri/vendor/glib/tests/log.rs | 106 + src-tauri/vendor/glib/tests/print.rs | 49 + src-tauri/vendor/glib/tests/structured_log.rs | 152 + .../vendor/glib/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 + src-tauri/vendor/glib/tests/value.rs | 67 + .../glib/tests/variant_str_iter_backport.rs | 13 + 127 files changed, 54931 insertions(+), 2 deletions(-) create mode 100644 src-tauri/vendor/glib/.gitignore create mode 100644 src-tauri/vendor/glib/COPYRIGHT create mode 100644 src-tauri/vendor/glib/Cargo.lock create mode 100644 src-tauri/vendor/glib/Cargo.toml create mode 100644 src-tauri/vendor/glib/Cargo.toml.orig create mode 100644 src-tauri/vendor/glib/Gir.toml create mode 100644 src-tauri/vendor/glib/Gir_GObject.toml create mode 100644 src-tauri/vendor/glib/LICENSE create mode 100644 src-tauri/vendor/glib/README.md create mode 100644 src-tauri/vendor/glib/SECURITY-BACKPORT.md create mode 100644 src-tauri/vendor/glib/benches/gstring.rs create mode 100644 src-tauri/vendor/glib/src/auto/alias.rs create mode 100644 src-tauri/vendor/glib/src/auto/checksum.rs create mode 100644 src-tauri/vendor/glib/src/auto/constants.rs create mode 100644 src-tauri/vendor/glib/src/auto/date_time.rs create mode 100644 src-tauri/vendor/glib/src/auto/enums.rs create mode 100644 src-tauri/vendor/glib/src/auto/flags.rs create mode 100644 src-tauri/vendor/glib/src/auto/functions.rs create mode 100644 src-tauri/vendor/glib/src/auto/key_file.rs create mode 100644 src-tauri/vendor/glib/src/auto/main_context.rs create mode 100644 src-tauri/vendor/glib/src/auto/main_loop.rs create mode 100644 src-tauri/vendor/glib/src/auto/markup_parse_context.rs create mode 100644 src-tauri/vendor/glib/src/auto/mod.rs create mode 100644 src-tauri/vendor/glib/src/auto/source.rs create mode 100644 src-tauri/vendor/glib/src/auto/time_zone.rs create mode 100644 src-tauri/vendor/glib/src/auto/uri.rs create mode 100644 src-tauri/vendor/glib/src/auto/versions.txt create mode 100644 src-tauri/vendor/glib/src/boxed.rs create mode 100644 src-tauri/vendor/glib/src/boxed_any_object.rs create mode 100644 src-tauri/vendor/glib/src/boxed_inline.rs create mode 100644 src-tauri/vendor/glib/src/bridged_logging.rs create mode 100644 src-tauri/vendor/glib/src/byte_array.rs create mode 100644 src-tauri/vendor/glib/src/bytes.rs create mode 100644 src-tauri/vendor/glib/src/char.rs create mode 100644 src-tauri/vendor/glib/src/checksum.rs create mode 100644 src-tauri/vendor/glib/src/clone.rs create mode 100644 src-tauri/vendor/glib/src/closure.rs create mode 100644 src-tauri/vendor/glib/src/collections/list.rs create mode 100644 src-tauri/vendor/glib/src/collections/mod.rs create mode 100644 src-tauri/vendor/glib/src/collections/ptr_slice.rs create mode 100644 src-tauri/vendor/glib/src/collections/slice.rs create mode 100644 src-tauri/vendor/glib/src/collections/slist.rs create mode 100644 src-tauri/vendor/glib/src/collections/strv.rs create mode 100644 src-tauri/vendor/glib/src/control_flow.rs create mode 100644 src-tauri/vendor/glib/src/convert.rs create mode 100644 src-tauri/vendor/glib/src/date.rs create mode 100644 src-tauri/vendor/glib/src/date_time.rs create mode 100644 src-tauri/vendor/glib/src/enums.rs create mode 100644 src-tauri/vendor/glib/src/error.rs create mode 100644 src-tauri/vendor/glib/src/exit_code.rs create mode 100644 src-tauri/vendor/glib/src/future_with_timeout.rs create mode 100644 src-tauri/vendor/glib/src/gobject/auto/binding.rs create mode 100644 src-tauri/vendor/glib/src/gobject/auto/binding_group.rs create mode 100644 src-tauri/vendor/glib/src/gobject/auto/flags.rs create mode 100644 src-tauri/vendor/glib/src/gobject/auto/mod.rs create mode 100644 src-tauri/vendor/glib/src/gobject/auto/signal_group.rs create mode 100644 src-tauri/vendor/glib/src/gobject/binding.rs create mode 100644 src-tauri/vendor/glib/src/gobject/binding_group.rs create mode 100644 src-tauri/vendor/glib/src/gobject/flags.rs create mode 100644 src-tauri/vendor/glib/src/gobject/mod.rs create mode 100644 src-tauri/vendor/glib/src/gobject/signal_group.rs create mode 100644 src-tauri/vendor/glib/src/gstring.rs create mode 100644 src-tauri/vendor/glib/src/gstring_builder.rs create mode 100644 src-tauri/vendor/glib/src/key_file.rs create mode 100644 src-tauri/vendor/glib/src/lib.rs create mode 100644 src-tauri/vendor/glib/src/log.rs create mode 100644 src-tauri/vendor/glib/src/main_context.rs create mode 100644 src-tauri/vendor/glib/src/main_context_channel.rs create mode 100644 src-tauri/vendor/glib/src/main_context_futures.rs create mode 100644 src-tauri/vendor/glib/src/manual_functions.rs create mode 100644 src-tauri/vendor/glib/src/object.rs create mode 100644 src-tauri/vendor/glib/src/param_spec.rs create mode 100644 src-tauri/vendor/glib/src/prelude.rs create mode 100644 src-tauri/vendor/glib/src/property.rs create mode 100644 src-tauri/vendor/glib/src/quark.rs create mode 100644 src-tauri/vendor/glib/src/shared.rs create mode 100644 src-tauri/vendor/glib/src/signal.rs create mode 100644 src-tauri/vendor/glib/src/source.rs create mode 100644 src-tauri/vendor/glib/src/source_futures.rs create mode 100644 src-tauri/vendor/glib/src/subclass/basic.rs create mode 100644 src-tauri/vendor/glib/src/subclass/boxed.rs create mode 100644 src-tauri/vendor/glib/src/subclass/interface.rs create mode 100644 src-tauri/vendor/glib/src/subclass/mod.rs create mode 100644 src-tauri/vendor/glib/src/subclass/object.rs create mode 100644 src-tauri/vendor/glib/src/subclass/object_impl_ref.rs create mode 100644 src-tauri/vendor/glib/src/subclass/shared.rs create mode 100644 src-tauri/vendor/glib/src/subclass/signal.rs create mode 100644 src-tauri/vendor/glib/src/subclass/types.rs create mode 100644 src-tauri/vendor/glib/src/thread_guard.rs create mode 100644 src-tauri/vendor/glib/src/thread_pool.rs create mode 100644 src-tauri/vendor/glib/src/time_span.rs create mode 100644 src-tauri/vendor/glib/src/time_zone.rs create mode 100644 src-tauri/vendor/glib/src/translate.rs create mode 100644 src-tauri/vendor/glib/src/types.rs create mode 100644 src-tauri/vendor/glib/src/unichar.rs create mode 100644 src-tauri/vendor/glib/src/unicollate.rs create mode 100644 src-tauri/vendor/glib/src/utils.rs create mode 100644 src-tauri/vendor/glib/src/value.rs create mode 100644 src-tauri/vendor/glib/src/value_array.rs create mode 100644 src-tauri/vendor/glib/src/variant.rs create mode 100644 src-tauri/vendor/glib/src/variant_dict.rs create mode 100644 src-tauri/vendor/glib/src/variant_iter.rs create mode 100644 src-tauri/vendor/glib/src/variant_type.rs create mode 100644 src-tauri/vendor/glib/src/win32.rs create mode 100644 src-tauri/vendor/glib/src/wrapper.rs create mode 100644 src-tauri/vendor/glib/tests/check_gir.rs create mode 100644 src-tauri/vendor/glib/tests/clone.rs create mode 100644 src-tauri/vendor/glib/tests/derive.rs create mode 100644 src-tauri/vendor/glib/tests/log.rs create mode 100644 src-tauri/vendor/glib/tests/print.rs create mode 100644 src-tauri/vendor/glib/tests/structured_log.rs create mode 100644 src-tauri/vendor/glib/tests/subclass_compiletest.rs create mode 100644 src-tauri/vendor/glib/tests/subclass_compiletest/01-auto-send-sync.rs create mode 100644 src-tauri/vendor/glib/tests/subclass_compiletest/02-no-auto-send-sync.rs create mode 100644 src-tauri/vendor/glib/tests/subclass_compiletest/02-no-auto-send-sync.stderr create mode 100644 src-tauri/vendor/glib/tests/subclass_compiletest/03-object-no-auto-send-sync.rs create mode 100644 src-tauri/vendor/glib/tests/subclass_compiletest/03-object-no-auto-send-sync.stderr create mode 100644 src-tauri/vendor/glib/tests/subclass_compiletest/04-auto-send-sync-with-send-sync-parent.rs create mode 100644 src-tauri/vendor/glib/tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.rs create mode 100644 src-tauri/vendor/glib/tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.stderr create mode 100644 src-tauri/vendor/glib/tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.rs create mode 100644 src-tauri/vendor/glib/tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.stderr create mode 100644 src-tauri/vendor/glib/tests/value.rs create mode 100644 src-tauri/vendor/glib/tests/variant_str_iter_backport.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1c8c0fd..89f50d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,15 @@ on: branches: [main] jobs: + rust-security-backport: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - run: sudo apt-get update && sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev + - run: cargo test --manifest-path src-tauri/vendor/glib/Cargo.toml --locked --release --test variant_str_iter_backport + - run: cargo check --manifest-path src-tauri/Cargo.toml --locked + quality: name: Lint, Typecheck & Test runs-on: ubuntu-latest diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 90e84e3..fd2076b 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1339,8 +1339,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.2", "futures-channel", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 822d6d1..0390624 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -46,3 +46,6 @@ opt-level = "s" lto = "thin" codegen-units = 1 strip = true + +[patch.crates-io] +glib = { path = "vendor/glib" } diff --git a/src-tauri/vendor/glib/.gitignore b/src-tauri/vendor/glib/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/src-tauri/vendor/glib/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/src-tauri/vendor/glib/COPYRIGHT b/src-tauri/vendor/glib/COPYRIGHT new file mode 100644 index 0000000..aabc43f --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/Cargo.lock b/src-tauri/vendor/glib/Cargo.lock new file mode 100644 index 0000000..f7fb329 --- /dev/null +++ b/src-tauri/vendor/glib/Cargo.lock @@ -0,0 +1,1055 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +dependencies = [ + "memchr", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "basic-toml" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "2.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" + +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "either" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" + +[[package]] +name = "equivalent" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "futures-channel" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-executor" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-core", + "futures-macro", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi", +] + +[[package]] +name = "gio-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + +[[package]] +name = "gir-format-check" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a5da913a8586ce748f1164c890e1ebe75a7bbc472668f57b7f9fb893d7ac416" + +[[package]] +name = "glib" +version = "0.18.5" +dependencies = [ + "bitflags", + "criterion", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "gir-format-check", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "log", + "memchr", + "once_cell", + "smallvec", + "tempfile", + "thiserror", + "trybuild2", +] + +[[package]] +name = "glib-macros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" +dependencies = [ + "heck 0.4.1", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "glib-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "glob" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" + +[[package]] +name = "gobject-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is-terminal" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "js-sys" +version = "0.3.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.191" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "rustix" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b3dc8af474f516a851ff4bd12db780f948b9250ad37211e4eec0bccea54e01b" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck 0.5.0", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "toml" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "trybuild2" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd171cf86a53f6d603fc3348a5a56e63ca15cad5b95d5561d78fa21d330deb9b" +dependencies = [ + "basic-toml", + "glob", + "once_cell", + "serde", + "serde_derive", + "serde_json", + "termcolor", +] + +[[package]] +name = "unicode-ident" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" + +[[package]] +name = "version-compare" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 3.0.9", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88261b9deccee56594c11a3460c462c41f58d148598fe70ad77070126a68aba4" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "zerocopy" +version = "0.8.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5fe1f8f1b06191a00962174c61aa5005e0bb391a6d80d07e24d115c01a92ed8" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863ad3ac83293fb4d740aedbfdc9240dd8d1a50c1099acd76ce80ce7c7230c7f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/src-tauri/vendor/glib/Cargo.toml b/src-tauri/vendor/glib/Cargo.toml new file mode 100644 index 0000000..132e07d --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/Cargo.toml.orig b/src-tauri/vendor/glib/Cargo.toml.orig new file mode 100644 index 0000000..f6b791e --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/Gir.toml b/src-tauri/vendor/glib/Gir.toml new file mode 100644 index 0000000..8dfe2f7 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/Gir_GObject.toml b/src-tauri/vendor/glib/Gir_GObject.toml new file mode 100644 index 0000000..8b68456 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/LICENSE b/src-tauri/vendor/glib/LICENSE new file mode 100644 index 0000000..64a801a --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/README.md b/src-tauri/vendor/glib/README.md new file mode 100644 index 0000000..9cb2e8b --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/SECURITY-BACKPORT.md b/src-tauri/vendor/glib/SECURITY-BACKPORT.md new file mode 100644 index 0000000..9924dcb --- /dev/null +++ b/src-tauri/vendor/glib/SECURITY-BACKPORT.md @@ -0,0 +1,17 @@ +# GLib 0.18.5 security backport + +This is the crates.io glib 0.18.5 source with the two-line upstream fix from +https://github.com/gtk-rs/gtk-rs-core/pull/1343 applied to `src/variant_iter.rs`. +The C output pointer is mutable and passed as `&mut p`, preventing undefined +behavior in forward and reverse string-array iteration (RUSTSEC-2024-0429). + +The package version remains 0.18.5. This is a locally maintained backport, not +an upstream release. Tauri's GTK3 dependencies cannot accept glib 0.20. +Upstream declined a 0.18 patch release in +https://github.com/gtk-rs/gtk-rs-core/pull/1991#issuecomment-4786302302. + +Retain the original MIT license and source. Remove this patch when the desktop +stack supports an upstream fixed GLib release. Version-only security scanners +may still report the advisory; disappearance from a dependency graph alone +does not establish remediation. Validate the optimized iterator regression +test and Linux desktop compilation before changing this patch. diff --git a/src-tauri/vendor/glib/benches/gstring.rs b/src-tauri/vendor/glib/benches/gstring.rs new file mode 100644 index 0000000..a644ac0 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/auto/alias.rs b/src-tauri/vendor/glib/src/auto/alias.rs new file mode 100644 index 0000000..cd6abd2 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/auto/checksum.rs b/src-tauri/vendor/glib/src/auto/checksum.rs new file mode 100644 index 0000000..6e8dbeb --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/auto/constants.rs b/src-tauri/vendor/glib/src/auto/constants.rs new file mode 100644 index 0000000..02a07d1 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/auto/date_time.rs b/src-tauri/vendor/glib/src/auto/date_time.rs new file mode 100644 index 0000000..da0c3fc --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/auto/enums.rs b/src-tauri/vendor/glib/src/auto/enums.rs new file mode 100644 index 0000000..7b6706e --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/auto/flags.rs b/src-tauri/vendor/glib/src/auto/flags.rs new file mode 100644 index 0000000..0ff8baa --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/auto/functions.rs b/src-tauri/vendor/glib/src/auto/functions.rs new file mode 100644 index 0000000..7d569ad --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/auto/key_file.rs b/src-tauri/vendor/glib/src/auto/key_file.rs new file mode 100644 index 0000000..8c7986e --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/auto/main_context.rs b/src-tauri/vendor/glib/src/auto/main_context.rs new file mode 100644 index 0000000..cc4da92 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/auto/main_loop.rs b/src-tauri/vendor/glib/src/auto/main_loop.rs new file mode 100644 index 0000000..64a27a1 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/auto/markup_parse_context.rs b/src-tauri/vendor/glib/src/auto/markup_parse_context.rs new file mode 100644 index 0000000..f071797 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/auto/mod.rs b/src-tauri/vendor/glib/src/auto/mod.rs new file mode 100644 index 0000000..bbe89c8 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/auto/source.rs b/src-tauri/vendor/glib/src/auto/source.rs new file mode 100644 index 0000000..e1418ba --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/auto/time_zone.rs b/src-tauri/vendor/glib/src/auto/time_zone.rs new file mode 100644 index 0000000..23d3cef --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/auto/uri.rs b/src-tauri/vendor/glib/src/auto/uri.rs new file mode 100644 index 0000000..d1e2c37 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/auto/versions.txt b/src-tauri/vendor/glib/src/auto/versions.txt new file mode 100644 index 0000000..8871d4e --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/boxed.rs b/src-tauri/vendor/glib/src/boxed.rs new file mode 100644 index 0000000..70d6a23 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/boxed_any_object.rs b/src-tauri/vendor/glib/src/boxed_any_object.rs new file mode 100644 index 0000000..ef7db2d --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/boxed_inline.rs b/src-tauri/vendor/glib/src/boxed_inline.rs new file mode 100644 index 0000000..6cae416 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/bridged_logging.rs b/src-tauri/vendor/glib/src/bridged_logging.rs new file mode 100644 index 0000000..4573c83 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/byte_array.rs b/src-tauri/vendor/glib/src/byte_array.rs new file mode 100644 index 0000000..4c07547 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/bytes.rs b/src-tauri/vendor/glib/src/bytes.rs new file mode 100644 index 0000000..8f02125 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/char.rs b/src-tauri/vendor/glib/src/char.rs new file mode 100644 index 0000000..5bc46db --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/checksum.rs b/src-tauri/vendor/glib/src/checksum.rs new file mode 100644 index 0000000..02f681f --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/clone.rs b/src-tauri/vendor/glib/src/clone.rs new file mode 100644 index 0000000..598ca8b --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/closure.rs b/src-tauri/vendor/glib/src/closure.rs new file mode 100644 index 0000000..789cbd0 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/collections/list.rs b/src-tauri/vendor/glib/src/collections/list.rs new file mode 100644 index 0000000..71bf92b --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/collections/mod.rs b/src-tauri/vendor/glib/src/collections/mod.rs new file mode 100644 index 0000000..9f775cd --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/collections/ptr_slice.rs b/src-tauri/vendor/glib/src/collections/ptr_slice.rs new file mode 100644 index 0000000..e925d98 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/collections/slice.rs b/src-tauri/vendor/glib/src/collections/slice.rs new file mode 100644 index 0000000..82ef541 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/collections/slist.rs b/src-tauri/vendor/glib/src/collections/slist.rs new file mode 100644 index 0000000..70f013b --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/collections/strv.rs b/src-tauri/vendor/glib/src/collections/strv.rs new file mode 100644 index 0000000..85b288e --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/control_flow.rs b/src-tauri/vendor/glib/src/control_flow.rs new file mode 100644 index 0000000..6888d62 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/convert.rs b/src-tauri/vendor/glib/src/convert.rs new file mode 100644 index 0000000..94e769d --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/date.rs b/src-tauri/vendor/glib/src/date.rs new file mode 100644 index 0000000..60a90ef --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/date_time.rs b/src-tauri/vendor/glib/src/date_time.rs new file mode 100644 index 0000000..912c915 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/enums.rs b/src-tauri/vendor/glib/src/enums.rs new file mode 100644 index 0000000..2c59236 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/error.rs b/src-tauri/vendor/glib/src/error.rs new file mode 100644 index 0000000..255aa2e --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/exit_code.rs b/src-tauri/vendor/glib/src/exit_code.rs new file mode 100644 index 0000000..4a275c9 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/future_with_timeout.rs b/src-tauri/vendor/glib/src/future_with_timeout.rs new file mode 100644 index 0000000..92cf50f --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/gobject/auto/binding.rs b/src-tauri/vendor/glib/src/gobject/auto/binding.rs new file mode 100644 index 0000000..af6bcaf --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/gobject/auto/binding_group.rs b/src-tauri/vendor/glib/src/gobject/auto/binding_group.rs new file mode 100644 index 0000000..72137e5 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/gobject/auto/flags.rs b/src-tauri/vendor/glib/src/gobject/auto/flags.rs new file mode 100644 index 0000000..22ea9c1 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/gobject/auto/mod.rs b/src-tauri/vendor/glib/src/gobject/auto/mod.rs new file mode 100644 index 0000000..dbd122a --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/gobject/auto/signal_group.rs b/src-tauri/vendor/glib/src/gobject/auto/signal_group.rs new file mode 100644 index 0000000..1a8a370 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/gobject/binding.rs b/src-tauri/vendor/glib/src/gobject/binding.rs new file mode 100644 index 0000000..01c0b8f --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/gobject/binding_group.rs b/src-tauri/vendor/glib/src/gobject/binding_group.rs new file mode 100644 index 0000000..78cba7d --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/gobject/flags.rs b/src-tauri/vendor/glib/src/gobject/flags.rs new file mode 100644 index 0000000..a2f4c95 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/gobject/mod.rs b/src-tauri/vendor/glib/src/gobject/mod.rs new file mode 100644 index 0000000..274451c --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/gobject/signal_group.rs b/src-tauri/vendor/glib/src/gobject/signal_group.rs new file mode 100644 index 0000000..f9fb063 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/gstring.rs b/src-tauri/vendor/glib/src/gstring.rs new file mode 100644 index 0000000..1d1bc95 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/gstring_builder.rs b/src-tauri/vendor/glib/src/gstring_builder.rs new file mode 100644 index 0000000..e08618d --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/key_file.rs b/src-tauri/vendor/glib/src/key_file.rs new file mode 100644 index 0000000..54c9eb1 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/lib.rs b/src-tauri/vendor/glib/src/lib.rs new file mode 100644 index 0000000..af61bcb --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/log.rs b/src-tauri/vendor/glib/src/log.rs new file mode 100644 index 0000000..276d736 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/main_context.rs b/src-tauri/vendor/glib/src/main_context.rs new file mode 100644 index 0000000..3500099 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/main_context_channel.rs b/src-tauri/vendor/glib/src/main_context_channel.rs new file mode 100644 index 0000000..a3da242 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/main_context_futures.rs b/src-tauri/vendor/glib/src/main_context_futures.rs new file mode 100644 index 0000000..04d3e92 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/manual_functions.rs b/src-tauri/vendor/glib/src/manual_functions.rs new file mode 100644 index 0000000..7d81ba9 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/object.rs b/src-tauri/vendor/glib/src/object.rs new file mode 100644 index 0000000..bb799ba --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/param_spec.rs b/src-tauri/vendor/glib/src/param_spec.rs new file mode 100644 index 0000000..890b0b0 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/prelude.rs b/src-tauri/vendor/glib/src/prelude.rs new file mode 100644 index 0000000..596442b --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/property.rs b/src-tauri/vendor/glib/src/property.rs new file mode 100644 index 0000000..e6db701 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/quark.rs b/src-tauri/vendor/glib/src/quark.rs new file mode 100644 index 0000000..37dbae9 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/shared.rs b/src-tauri/vendor/glib/src/shared.rs new file mode 100644 index 0000000..f0d0046 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/signal.rs b/src-tauri/vendor/glib/src/signal.rs new file mode 100644 index 0000000..75d986e --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/source.rs b/src-tauri/vendor/glib/src/source.rs new file mode 100644 index 0000000..04704f8 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/source_futures.rs b/src-tauri/vendor/glib/src/source_futures.rs new file mode 100644 index 0000000..f483301 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/subclass/basic.rs b/src-tauri/vendor/glib/src/subclass/basic.rs new file mode 100644 index 0000000..7fee280 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/subclass/boxed.rs b/src-tauri/vendor/glib/src/subclass/boxed.rs new file mode 100644 index 0000000..2381362 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/subclass/interface.rs b/src-tauri/vendor/glib/src/subclass/interface.rs new file mode 100644 index 0000000..b87bfae --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/subclass/mod.rs b/src-tauri/vendor/glib/src/subclass/mod.rs new file mode 100644 index 0000000..8fd16ad --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/subclass/object.rs b/src-tauri/vendor/glib/src/subclass/object.rs new file mode 100644 index 0000000..ef84967 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/subclass/object_impl_ref.rs b/src-tauri/vendor/glib/src/subclass/object_impl_ref.rs new file mode 100644 index 0000000..6a75346 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/subclass/shared.rs b/src-tauri/vendor/glib/src/subclass/shared.rs new file mode 100644 index 0000000..acd459c --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/subclass/signal.rs b/src-tauri/vendor/glib/src/subclass/signal.rs new file mode 100644 index 0000000..2ea40cb --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/subclass/types.rs b/src-tauri/vendor/glib/src/subclass/types.rs new file mode 100644 index 0000000..7e1cdd5 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/thread_guard.rs b/src-tauri/vendor/glib/src/thread_guard.rs new file mode 100644 index 0000000..f3b4c61 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/thread_pool.rs b/src-tauri/vendor/glib/src/thread_pool.rs new file mode 100644 index 0000000..c309708 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/time_span.rs b/src-tauri/vendor/glib/src/time_span.rs new file mode 100644 index 0000000..082c63a --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/time_zone.rs b/src-tauri/vendor/glib/src/time_zone.rs new file mode 100644 index 0000000..ee0f10d --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/translate.rs b/src-tauri/vendor/glib/src/translate.rs new file mode 100644 index 0000000..11cfec0 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/types.rs b/src-tauri/vendor/glib/src/types.rs new file mode 100644 index 0000000..4cfa291 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/unichar.rs b/src-tauri/vendor/glib/src/unichar.rs new file mode 100644 index 0000000..435744e --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/unicollate.rs b/src-tauri/vendor/glib/src/unicollate.rs new file mode 100644 index 0000000..0f94554 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/utils.rs b/src-tauri/vendor/glib/src/utils.rs new file mode 100644 index 0000000..59e46be --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/value.rs b/src-tauri/vendor/glib/src/value.rs new file mode 100644 index 0000000..8886db1 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/value_array.rs b/src-tauri/vendor/glib/src/value_array.rs new file mode 100644 index 0000000..081985a --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/variant.rs b/src-tauri/vendor/glib/src/variant.rs new file mode 100644 index 0000000..7793e80 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/variant_dict.rs b/src-tauri/vendor/glib/src/variant_dict.rs new file mode 100644 index 0000000..a9dfd84 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/variant_iter.rs b/src-tauri/vendor/glib/src/variant_iter.rs new file mode 100644 index 0000000..e0997f6 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/variant_type.rs b/src-tauri/vendor/glib/src/variant_type.rs new file mode 100644 index 0000000..ebd53c2 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/win32.rs b/src-tauri/vendor/glib/src/win32.rs new file mode 100644 index 0000000..4e2984c --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/src/wrapper.rs b/src-tauri/vendor/glib/src/wrapper.rs new file mode 100644 index 0000000..1ad0610 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/tests/check_gir.rs b/src-tauri/vendor/glib/tests/check_gir.rs new file mode 100644 index 0000000..2ccf5ff --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/tests/clone.rs b/src-tauri/vendor/glib/tests/clone.rs new file mode 100644 index 0000000..ee6ccf2 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/tests/derive.rs b/src-tauri/vendor/glib/tests/derive.rs new file mode 100644 index 0000000..80a7a89 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/tests/log.rs b/src-tauri/vendor/glib/tests/log.rs new file mode 100644 index 0000000..194cba8 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/tests/print.rs b/src-tauri/vendor/glib/tests/print.rs new file mode 100644 index 0000000..0cbcee2 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/tests/structured_log.rs b/src-tauri/vendor/glib/tests/structured_log.rs new file mode 100644 index 0000000..0ffd5bf --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/tests/subclass_compiletest.rs b/src-tauri/vendor/glib/tests/subclass_compiletest.rs new file mode 100644 index 0000000..509933c --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/tests/subclass_compiletest/01-auto-send-sync.rs b/src-tauri/vendor/glib/tests/subclass_compiletest/01-auto-send-sync.rs new file mode 100644 index 0000000..a628864 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/tests/subclass_compiletest/02-no-auto-send-sync.rs b/src-tauri/vendor/glib/tests/subclass_compiletest/02-no-auto-send-sync.rs new file mode 100644 index 0000000..19e9779 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/tests/subclass_compiletest/02-no-auto-send-sync.stderr b/src-tauri/vendor/glib/tests/subclass_compiletest/02-no-auto-send-sync.stderr new file mode 100644 index 0000000..9dfe0ca --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/tests/subclass_compiletest/03-object-no-auto-send-sync.rs b/src-tauri/vendor/glib/tests/subclass_compiletest/03-object-no-auto-send-sync.rs new file mode 100644 index 0000000..901fb8d --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/tests/subclass_compiletest/03-object-no-auto-send-sync.stderr b/src-tauri/vendor/glib/tests/subclass_compiletest/03-object-no-auto-send-sync.stderr new file mode 100644 index 0000000..4fc7bdc --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/tests/subclass_compiletest/04-auto-send-sync-with-send-sync-parent.rs b/src-tauri/vendor/glib/tests/subclass_compiletest/04-auto-send-sync-with-send-sync-parent.rs new file mode 100644 index 0000000..f3c38ae --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.rs b/src-tauri/vendor/glib/tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.rs new file mode 100644 index 0000000..836f225 --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.stderr b/src-tauri/vendor/glib/tests/subclass_compiletest/05-no-auto-send-sync-with-non-send-sync-parent.stderr new file mode 100644 index 0000000..b64598f --- /dev/null +++ b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.rs b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/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/src-tauri/vendor/glib/tests/subclass_compiletest/06-no-auto-send-sync-with-non-send-sync-ffi-parent.stderr b/src-tauri/vendor/glib/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/src-tauri/vendor/glib/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/src-tauri/vendor/glib/tests/value.rs b/src-tauri/vendor/glib/tests/value.rs new file mode 100644 index 0000000..53a9eac --- /dev/null +++ b/src-tauri/vendor/glib/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() + ); +} diff --git a/src-tauri/vendor/glib/tests/variant_str_iter_backport.rs b/src-tauri/vendor/glib/tests/variant_str_iter_backport.rs new file mode 100644 index 0000000..4a1ebd2 --- /dev/null +++ b/src-tauri/vendor/glib/tests/variant_str_iter_backport.rs @@ -0,0 +1,13 @@ +use glib::prelude::*; + +#[test] +fn string_array_iteration_is_sound_in_both_directions() { + let variant = ["alpha", "βeta", "", "omega"].to_variant(); + let mut iter = variant.array_iter_str().unwrap(); + assert_eq!(iter.next(), Some("alpha")); + assert_eq!(iter.next_back(), Some("omega")); + assert_eq!(iter.next(), Some("βeta")); + assert_eq!(iter.next_back(), Some("")); + assert_eq!(iter.next(), None); + assert_eq!(iter.next_back(), None); +} From 54ee16a7ed377de45b07410a27a2597086cc373f Mon Sep 17 00:00:00 2001 From: Alex Cinovoj <135995822+Alexi5000@users.noreply.github.com> Date: Sun, 18 Oct 2026 20:41:09 -0400 Subject: [PATCH 5/7] Validate preview and Spotify redirects and protect device token keys (#5) * fix: validate preview and Spotify URLs and protect token-store keys * fix: use maps for externally keyed token updates --------- Co-authored-by: zocomputer --- __tests__/security-navigation.test.ts | 41 ++++++ components/split-preview-chat.tsx | 15 +- lib/device-auth.ts | 197 ++++++++++++-------------- lib/safe-navigation.ts | 25 ++++ lib/spotify-auth.ts | 9 +- 5 files changed, 170 insertions(+), 117 deletions(-) create mode 100644 __tests__/security-navigation.test.ts create mode 100644 lib/safe-navigation.ts diff --git a/__tests__/security-navigation.test.ts b/__tests__/security-navigation.test.ts new file mode 100644 index 0000000..4742e3a --- /dev/null +++ b/__tests__/security-navigation.test.ts @@ -0,0 +1,41 @@ +import { describe, it, expect, beforeEach } from 'vitest' +import { safePreviewUrl, safeSpotifyHandoff } from '../lib/safe-navigation' +import { storeDeviceToken, loadDeviceToken } from '../lib/device-auth' + +describe('untrusted navigation and token keys', () => { + beforeEach(() => localStorage.clear()) + it('permits HTTP development previews and rejects executable schemes', () => { + expect(safePreviewUrl('http://localhost:3000/page')).toBe('http://localhost:3000/page') + for (const value of [ + 'javascript:alert(1)', + 'data:text/html,', + 'file:///etc/passwd', + 'https://user:pass@example.com', + 'invalid', + ]) { + expect(safePreviewUrl(value)).toBeNull() + } + }) + it('limits handoffs to the Spotify authorization endpoint', () => { + expect(safeSpotifyHandoff('https://accounts.spotify.com/authorize?client_id=example')).toBe( + 'https://accounts.spotify.com/authorize?client_id=example', + ) + for (const value of [ + 'https://accounts.spotify.com.attacker.test/authorize', + 'https://attacker.test/accounts.spotify.com', + 'javascript:alert(1)', + 'https://accounts.spotify.com/other', + 'https://user@accounts.spotify.com/authorize', + ]) { + expect(safeSpotifyHandoff(value)).toBeNull() + } + }) + it('stores hostile property names as own data without modifying prototypes', () => { + storeDeviceToken('__proto__', 'role', 'example', []) + expect(loadDeviceToken('__proto__', 'role')).toBe('example') + expect(Object.hasOwn(Object.prototype, 'role')).toBe(false) + storeDeviceToken('device', '__proto__', 'second', []) + expect(loadDeviceToken('device', '__proto__')).toBe('second') + expect(loadDeviceToken('toString', 'role')).toBeNull() + }) +}) diff --git a/components/split-preview-chat.tsx b/components/split-preview-chat.tsx index ceaaec6..a7f8c9f 100644 --- a/components/split-preview-chat.tsx +++ b/components/split-preview-chat.tsx @@ -2,6 +2,7 @@ import { useState, useRef, useEffect, useCallback } from 'react' import dynamic from 'next/dynamic' +import { safePreviewUrl } from '@/lib/safe-navigation' import { Icon } from '@iconify/react' const AgentPanel = dynamic(() => import('@/components/agent-panel').then((m) => m.AgentPanel), { @@ -24,14 +25,14 @@ export function SplitPreviewChat({ } return 0.5 }) - const [url, setUrl] = useState(previewUrl) + const [url, setUrl] = useState(() => safePreviewUrl(previewUrl) ?? 'about:blank') const [inputUrl, setInputUrl] = useState(previewUrl) const [isDragging, setIsDragging] = useState(false) const containerRef = useRef(null) const iframeRef = useRef(null) useEffect(() => { - setUrl(previewUrl) + setUrl(safePreviewUrl(previewUrl) ?? 'about:blank') setInputUrl(previewUrl) }, [previewUrl]) @@ -74,20 +75,22 @@ export function SplitPreviewChat({ const handleRefresh = useCallback(() => { if (iframeRef.current?.contentWindow) { - iframeRef.current.contentWindow.location.reload() + iframeRef.current.src = url } - }, []) + }, [url]) const handleUrlSubmit = useCallback( (e: React.FormEvent) => { e.preventDefault() - setUrl(inputUrl) + const next = safePreviewUrl(inputUrl) + if (next) setUrl(next) }, [inputUrl], ) const handlePopOut = useCallback(() => { - window.open(url, '_blank', 'width=1200,height=800') + const target = safePreviewUrl(url) + if (target) window.open(target, '_blank', 'noopener,noreferrer,width=1200,height=800') }, [url]) const previewHeight = `calc(${splitRatio * 100}% - 4px)` diff --git a/lib/device-auth.ts b/lib/device-auth.ts index 9afb2d4..6432d1e 100644 --- a/lib/device-auth.ts +++ b/lib/device-auth.ts @@ -1,122 +1,113 @@ -const STORAGE_JWK = "claw-dash:device-jwk"; -const STORAGE_PUB = "claw-dash:device-pub"; -const STORAGE_ID = "claw-dash:device-id"; -const STORAGE_TOKENS = "claw-dash:device-tokens"; +const STORAGE_JWK = 'claw-dash:device-jwk' +const STORAGE_PUB = 'claw-dash:device-pub' +const STORAGE_ID = 'claw-dash:device-id' +const STORAGE_TOKENS = 'claw-dash:device-tokens' // ── Types ── export interface DeviceIdentity { - deviceId: string; - publicKeyBase64Url: string; - privateKey: CryptoKey; + deviceId: string + publicKeyBase64Url: string + privateKey: CryptoKey } export interface DeviceAuthPayloadParams { - deviceId: string; - clientId: string; - clientMode: string; - role: string; - scopes: string[]; - signedAtMs: number; - token?: string | null; - nonce?: string | null; - version?: "v1" | "v2"; + deviceId: string + clientId: string + clientMode: string + role: string + scopes: string[] + signedAtMs: number + token?: string | null + nonce?: string | null + version?: 'v1' | 'v2' } interface StoredTokenEntry { - token: string; - scopes: string[]; + token: string + scopes: string[] } // ── Helpers ── function toBase64Url(buf: ArrayBuffer): string { - const bytes = new Uint8Array(buf); - let binary = ""; - for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]); - return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/g, ""); + const bytes = new Uint8Array(buf) + let binary = '' + for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]) + return btoa(binary).replaceAll('+', '-').replaceAll('/', '_').replace(/=+$/g, '') } function fromBase64Url(str: string): Uint8Array { - const padded = str.replaceAll("-", "+").replaceAll("_", "/"); - const binary = atob(padded); - const bytes = new Uint8Array(binary.length); - for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i); - return bytes; + const padded = str.replaceAll('-', '+').replaceAll('_', '/') + const binary = atob(padded) + const bytes = new Uint8Array(binary.length) + for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i) + return bytes } async function sha256Hex(data: ArrayBuffer): Promise { - const hash = await crypto.subtle.digest("SHA-256", data); - const bytes = new Uint8Array(hash); + const hash = await crypto.subtle.digest('SHA-256', data) + const bytes = new Uint8Array(hash) return Array.from(bytes) - .map((b) => b.toString(16).padStart(2, "0")) - .join(""); + .map((b) => b.toString(16).padStart(2, '0')) + .join('') } /** * Ed25519 raw public key is 32 bytes. The SPKI encoding wraps it with a * 12-byte prefix. We strip that prefix to get the raw key bytes. */ -const ED25519_SPKI_PREFIX_LEN = 12; -const ED25519_RAW_KEY_LEN = 32; +const ED25519_SPKI_PREFIX_LEN = 12 +const ED25519_RAW_KEY_LEN = 32 async function exportRawPublicKey(key: CryptoKey): Promise { - const spki = await crypto.subtle.exportKey("spki", key); - const spkiBytes = new Uint8Array(spki); + const spki = await crypto.subtle.exportKey('spki', key) + const spkiBytes = new Uint8Array(spki) if (spkiBytes.length === ED25519_SPKI_PREFIX_LEN + ED25519_RAW_KEY_LEN) { - return spkiBytes.slice(ED25519_SPKI_PREFIX_LEN).buffer; + return spkiBytes.slice(ED25519_SPKI_PREFIX_LEN).buffer } - return spki; + return spki } // ── Key Generation & Persistence ── async function generateDeviceIdentity(): Promise { - const keyPair = await crypto.subtle.generateKey("Ed25519", true, [ - "sign", - "verify", - ]); + const keyPair = await crypto.subtle.generateKey('Ed25519', true, ['sign', 'verify']) - const rawPub = await exportRawPublicKey(keyPair.publicKey); - const publicKeyBase64Url = toBase64Url(rawPub); - const deviceId = await sha256Hex(rawPub); + const rawPub = await exportRawPublicKey(keyPair.publicKey) + const publicKeyBase64Url = toBase64Url(rawPub) + const deviceId = await sha256Hex(rawPub) - const jwk = await crypto.subtle.exportKey("jwk", keyPair.privateKey); + const jwk = await crypto.subtle.exportKey('jwk', keyPair.privateKey) try { - localStorage.setItem(STORAGE_JWK, JSON.stringify(jwk)); - localStorage.setItem(STORAGE_PUB, publicKeyBase64Url); - localStorage.setItem(STORAGE_ID, deviceId); + localStorage.setItem(STORAGE_JWK, JSON.stringify(jwk)) + localStorage.setItem(STORAGE_PUB, publicKeyBase64Url) + localStorage.setItem(STORAGE_ID, deviceId) } catch {} - return { deviceId, publicKeyBase64Url, privateKey: keyPair.privateKey }; + return { deviceId, publicKeyBase64Url, privateKey: keyPair.privateKey } } async function loadDeviceIdentity(): Promise { try { - const jwkStr = localStorage.getItem(STORAGE_JWK); - const pub = localStorage.getItem(STORAGE_PUB); - const id = localStorage.getItem(STORAGE_ID); - if (!jwkStr || !pub || !id) return null; - - const jwk = JSON.parse(jwkStr) as JsonWebKey; - const privateKey = await crypto.subtle.importKey( - "jwk", - jwk, - "Ed25519", - false, - ["sign"] - ); - return { deviceId: id, publicKeyBase64Url: pub, privateKey }; + const jwkStr = localStorage.getItem(STORAGE_JWK) + const pub = localStorage.getItem(STORAGE_PUB) + const id = localStorage.getItem(STORAGE_ID) + if (!jwkStr || !pub || !id) return null + + const jwk = JSON.parse(jwkStr) as JsonWebKey + const privateKey = await crypto.subtle.importKey('jwk', jwk, 'Ed25519', false, ['sign']) + return { deviceId: id, publicKeyBase64Url: pub, privateKey } } catch { - return null; + return null } } export async function getOrCreateDeviceIdentity(): Promise { - const existing = await loadDeviceIdentity(); - if (existing) return existing; - return generateDeviceIdentity(); + const existing = await loadDeviceIdentity() + if (existing) return existing + return generateDeviceIdentity() } // ── Signing ── @@ -126,9 +117,9 @@ export async function getOrCreateDeviceIdentity(): Promise { * Matches `buildDeviceAuthPayload` from the gateway SDK. */ export function buildDeviceAuthPayload(params: DeviceAuthPayloadParams): string { - const version = params.version ?? (params.nonce ? "v2" : "v1"); - const scopes = params.scopes.join(","); - const token = params.token ?? ""; + const version = params.version ?? (params.nonce ? 'v2' : 'v1') + const scopes = params.scopes.join(',') + const token = params.token ?? '' const base = [ version, params.deviceId, @@ -138,68 +129,60 @@ export function buildDeviceAuthPayload(params: DeviceAuthPayloadParams): string scopes, String(params.signedAtMs), token, - ]; - if (version === "v2") base.push(params.nonce ?? ""); - return base.join("|"); + ] + if (version === 'v2') base.push(params.nonce ?? '') + return base.join('|') } -export async function signPayload( - privateKey: CryptoKey, - payload: string -): Promise { - const data = new TextEncoder().encode(payload); - const sig = await crypto.subtle.sign("Ed25519", privateKey, data); - return toBase64Url(sig); +export async function signPayload(privateKey: CryptoKey, payload: string): Promise { + const data = new TextEncoder().encode(payload) + const sig = await crypto.subtle.sign('Ed25519', privateKey, data) + return toBase64Url(sig) } // ── Device Token Storage ── -function readTokenStore(): Record< - string, - Record -> { +function readTokenStore(): Record> { try { - const raw = localStorage.getItem(STORAGE_TOKENS); - if (!raw) return {}; - return JSON.parse(raw); + const raw = localStorage.getItem(STORAGE_TOKENS) + if (!raw) return {} + return JSON.parse(raw) } catch { - return {}; + return {} } } -function writeTokenStore( - store: Record> -): void { +function writeTokenStore(store: Record>): void { try { - localStorage.setItem(STORAGE_TOKENS, JSON.stringify(store)); + localStorage.setItem(STORAGE_TOKENS, JSON.stringify(store)) } catch {} } -export function loadDeviceToken( - deviceId: string, - role: string -): string | null { - const store = readTokenStore(); - return store[deviceId]?.[role]?.token ?? null; +export function loadDeviceToken(deviceId: string, role: string): string | null { + const store = readTokenStore() + if (!Object.hasOwn(store, deviceId) || !Object.hasOwn(store[deviceId], role)) return null + return store[deviceId][role]?.token ?? null } export function storeDeviceToken( deviceId: string, role: string, token: string, - scopes: string[] + scopes: string[], ): void { - const store = readTokenStore(); - if (!store[deviceId]) store[deviceId] = {}; - store[deviceId][role] = { token, scopes }; - writeTokenStore(store); + const store = readTokenStore() + const devices = new Map(Object.entries(store)) + const roles = new Map(Object.entries(devices.get(deviceId) ?? {})) + roles.set(role, { token, scopes }) + devices.set(deviceId, Object.fromEntries(roles)) + writeTokenStore(Object.fromEntries(devices)) } export function clearDeviceAuth(): void { try { - localStorage.removeItem(STORAGE_JWK); - localStorage.removeItem(STORAGE_PUB); - localStorage.removeItem(STORAGE_ID); - localStorage.removeItem(STORAGE_TOKENS); + localStorage.removeItem(STORAGE_JWK) + localStorage.removeItem(STORAGE_PUB) + localStorage.removeItem(STORAGE_ID) + localStorage.removeItem(STORAGE_TOKENS) } catch {} } diff --git a/lib/safe-navigation.ts b/lib/safe-navigation.ts new file mode 100644 index 0000000..f435abe --- /dev/null +++ b/lib/safe-navigation.ts @@ -0,0 +1,25 @@ +export function safePreviewUrl(value: string): string | null { + try { + const url = new URL(value) + if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password) return null + return url.href + } catch { + return null + } +} + +export function safeSpotifyHandoff(value: string): string | null { + try { + const url = new URL(value) + if ( + url.origin !== 'https://accounts.spotify.com' || + url.pathname !== '/authorize' || + url.username || + url.password + ) + return null + return url.href + } catch { + return null + } +} diff --git a/lib/spotify-auth.ts b/lib/spotify-auth.ts index e39d19d..176f316 100644 --- a/lib/spotify-auth.ts +++ b/lib/spotify-auth.ts @@ -1,3 +1,4 @@ +import { safeSpotifyHandoff } from '@/lib/safe-navigation' import { isTauri } from '@/lib/tauri' import { emit } from '@/lib/events' @@ -80,8 +81,8 @@ function getRedirectUri(): string { const origin = window.location.origin if ( origin.startsWith('tauri://') || - origin.includes('localhost') || - origin.includes('127.0.0.1') + window.location.hostname === 'localhost' || + window.location.hostname === '127.0.0.1' ) { const port = window.location.port || '3080' return `http://127.0.0.1:${port}/` @@ -135,9 +136,9 @@ export async function startSpotifyLogin(): Promise { */ export function handleSpotifyAuthHandoff(): boolean { const params = new URLSearchParams(window.location.search) - const authUrl = params.get('spotify_auth') + const authUrl = safeSpotifyHandoff(params.get('spotify_auth') ?? '') const verifier = params.get('spotify_verifier') - if (authUrl && verifier) { + if (authUrl && verifier && /^[A-Za-z0-9._~-]{43,128}$/.test(verifier)) { localStorage.setItem(VERIFIER_KEY, verifier) // Clean up URL then redirect to Spotify window.location.href = authUrl From 44007d65095f7f32185964803896c84853a3480c Mon Sep 17 00:00:00 2001 From: Alex Cinovoj <135995822+Alexi5000@users.noreply.github.com> Date: Mon, 19 Oct 2026 15:08:52 -0400 Subject: [PATCH 6/7] fix: use cryptographic identifiers for kanban records (#6) Co-authored-by: zocomputer --- components/views/kanban-view.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/views/kanban-view.tsx b/components/views/kanban-view.tsx index 38540be..02ef881 100644 --- a/components/views/kanban-view.tsx +++ b/components/views/kanban-view.tsx @@ -778,7 +778,7 @@ function saveKanbanData(data: KanbanData) { } function genId(prefix: string) { - return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}` + return `${prefix}-${Date.now()}-${crypto.randomUUID()}` } function getDueDateStatus(dueDate?: number): 'overdue' | 'soon' | 'ok' | null { From 9cf86598a35a540caaf28b6fc5c539c20861ebc4 Mon Sep 17 00:00:00 2001 From: zocomputer Date: Mon, 19 Oct 2026 19:12:58 +0000 Subject: [PATCH 7/7] fix: constrain rendered markdown link and image destinations --- __tests__/markdown-security.test.tsx | 33 ++++++++++++++++++++++++++++ components/markdown-preview.tsx | 3 ++- lib/markdown-security.ts | 28 +++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 __tests__/markdown-security.test.tsx create mode 100644 lib/markdown-security.ts diff --git a/__tests__/markdown-security.test.tsx b/__tests__/markdown-security.test.tsx new file mode 100644 index 0000000..63d9385 --- /dev/null +++ b/__tests__/markdown-security.test.tsx @@ -0,0 +1,33 @@ +import React from 'react' +import { describe, it, expect } from 'vitest' +import { renderToStaticMarkup } from 'react-dom/server' +import { parse } from 'create-markdown' +import { BlockRenderer } from 'create-markdown/react' +import { secureMarkdownBlocks } from '../lib/markdown-security' + +function render(markdown: string) { + const element = document.createElement('div') + element.innerHTML = renderToStaticMarkup() + return element +} + +describe('markdown renderer URL boundary', () => { + it.each(['data:text/html,payload', 'file:///etc/passwd', 'vbscript:alert', 'javascript:alert', 'https://user:password@example.com'])('removes active link destination %s while preserving text', (url) => { + const element = render(`[label](${url})`) + expect(element.querySelector('a')).toBeNull() + expect(element.textContent).toBe('label') + }) + it('filters links in nested lists and image sources', () => { + const element = render('- [outer](file:///etc/passwd)\n - [inner](data:text/html,payload)\n\n![image](file:///etc/passwd)') + expect(element.querySelector('a')).toBeNull() + expect(element.querySelector('img')?.getAttribute('src')).toBeNull() + }) + it('preserves ordinary navigation, formatting and code examples', () => { + const element = render('# Heading\n\n**bold** and [site](https://example.com/path) [local](./guide.md) [mail](mailto:a@example.com)\n\n```html\n\n```') + expect(element.querySelector('h1')?.textContent).toBe('Heading') + expect(element.querySelector('strong')?.textContent).toBe('bold') + expect(element.querySelectorAll('a')).toHaveLength(3) + expect(element.querySelector('pre code')?.textContent).toBe('') + expect(element.querySelector('[onerror]')).toBeNull() + }) +}) diff --git a/components/markdown-preview.tsx b/components/markdown-preview.tsx index aa1b336..084fd6b 100644 --- a/components/markdown-preview.tsx +++ b/components/markdown-preview.tsx @@ -4,6 +4,7 @@ import { useMemo, useState, useRef, useCallback, useEffect } from 'react' import { createPortal } from 'react-dom' import DOMPurify from 'dompurify' import { parse } from 'create-markdown' +import { secureMarkdownBlocks } from '@/lib/markdown-security' import { BlockRenderer } from 'create-markdown/react' import { copyToClipboard } from '@/lib/clipboard' import { installAbortErrorSuppression, isAbortError } from '@/lib/abort-error' @@ -227,7 +228,7 @@ export function MarkdownPreview({ ? DOMPurify.sanitize(content, { ALLOWED_TAGS: [], KEEP_CONTENT: true }) : content.replace(/]*>[\s\S]*?<\/script>/gi, '') const normalized = normalizeToMarkdown(clean) - const result = parse(normalized) + const result = secureMarkdownBlocks(parse(normalized)) lastParsedRef.current = content lastBlocksRef.current = result lastParseTimeRef.current = parseTickRef.current diff --git a/lib/markdown-security.ts b/lib/markdown-security.ts new file mode 100644 index 0000000..e8fac97 --- /dev/null +++ b/lib/markdown-security.ts @@ -0,0 +1,28 @@ +import type { Block, ImageBlock } from 'create-markdown' + +export function safeMarkdownUrl(value: string, image = false): boolean { + try { + const url = new URL(value, 'https://markdown.invalid/') + const protocols = image ? ['http:', 'https:'] : ['http:', 'https:', 'mailto:', 'tel:'] + return protocols.includes(url.protocol) && !url.username && !url.password + } catch { + return false + } +} + +export function secureMarkdownBlocks(blocks: Block[]): Block[] { + return blocks.map((block) => ({ + ...block, + props: + block.type === 'image' && !safeMarkdownUrl((block as ImageBlock).props.url, true) + ? { ...block.props, url: undefined } + : block.props, + content: block.content.map((span) => { + if (!span.styles.link || safeMarkdownUrl(span.styles.link.url)) return span + const styles = { ...span.styles } + delete styles.link + return { ...span, styles } + }), + children: secureMarkdownBlocks(block.children), + })) as Block[] +}