Compare commits

...

17 Commits

Author SHA1 Message Date
Tristan Ross 42d4188ebc Merge pull request #22 from DeterminateSystems/tristanross/dsp-204
Build / Build (map[runner:UbuntuLatest32Cores128GArm system:aarch64-linux]) (push) Has been cancelled
Build / Build (map[runner:namespace-profile-linuxamd32c64g-cache system:x86_64-linux]) (push) Has been cancelled
Build / Build (map[runner:namespace-profile-mac-m2-12c28g system:aarch64-darwin]) (push) Has been cancelled
Build / success (push) Has been cancelled
Add logger bindings, fix bindgen-gcc.sh
2026-05-07 09:28:21 -07:00
Tristan Ross 959616efbe nix-bindings-util: add logger 2026-05-07 09:12:25 -07:00
Tristan Ross d64bf49302 Fix bindgen-gcc.sh with zsh in direnv and JP locale 2026-05-07 09:12:25 -07:00
Tristan Ross 86599ff46d Update flake.lock 2026-05-07 08:39:35 -07:00
Tristan Ross 1d6503754a Merge pull request #21 from DeterminateSystems/fix/build-after-flake-update
Fix after updating nix
2026-05-07 08:09:16 -07:00
Tristan Ross b148d6645a Skip recoverable error tests 2026-05-06 11:05:38 -07:00
Tristan Ross 4799da4f41 Fix after updating nix 2026-04-28 13:51:09 -07:00
Naxdy 45a57d9b32 Merge pull request #20 from DeterminateSystems/feat/multithread-evalstate
[noupstream] Refactor `EvalState` & other types to account for DetNix' thread-safety
2026-04-20 16:25:20 +02:00
Naxdy 15b159b6f1 [noupstream] Refactor EvalState & other types to account for DetNix' thread-safety 2026-04-14 21:48:37 +02:00
Tristan Ross ce3142c1e4 Merge pull request #19 from DeterminateSystems/feat/sync-upstream-1
Sync with upstream (2026-04-07)
2026-04-09 11:40:38 -07:00
Naxdy 73c6cd51ca feat(primop): move RecoverableError to error enum 2026-04-08 12:32:38 +02:00
Tristan Ross c90a0345e7 Merge remote-tracking branch 'upstream/main' into feat/sync-upstream 2026-04-07 13:08:32 -07:00
hercules-ci[bot] 7de15fa260 Merge pull request #57 from nixops4/flake-update
`flake.lock`: Update
2026-03-02 22:58:51 +00:00
Robert Hensing fbf5fab083 feat(nix-bindings-expr): add RecoverableError for non-memoized primop errors
Nix 2.34 memoizes primop errors by default. RecoverableError uses
NIX_ERR_RECOVERABLE so transient errors allow the thunk to be retried.
2026-03-02 23:53:53 +01:00
Robert Hensing cf0e8fff6a test(nix-bindings-store): accept new Nix error format for invalid system builds
Nix changed "required system or feature not available" to "platform mismatch".
2026-03-02 23:22:08 +01:00
Hercules CI Effects 1e61578f35 dev/flake.lock: Update
Flake lock file updates:

• Updated input 'hercules-ci-effects':
    'github:hercules-ci/hercules-ci-effects/c19e263e6e22ec7379d972f19e6a322f943c73fb?narHash=sha256-V0YOJRum50gtKgwavsAfwXc9%2BXAsJCC7386YZx1sWGQ%3D' (2026-01-15)
  → 'github:hercules-ci/hercules-ci-effects/0b152e0f7c5cc265a529cd63374b80e2771b207b?narHash=sha256-HPBNYf7HiKtBVy7/69vKpLYHX6wTcUxndxmybzDlXP8%3D' (2026-02-15)
• Updated input 'hercules-ci-effects/flake-parts':
    'github:hercules-ci/flake-parts/80daad04eddbbf5a4d883996a73f3f542fa437ac?narHash=sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY%3D' (2026-01-11)
  → 'github:hercules-ci/flake-parts/57928607ea566b5db3ad13af0e57e921e6b12381?narHash=sha256-AnYjnFWgS49RlqX7LrC4uA%2BsCCDBj0Ry/WOJ5XWAsa0%3D' (2026-02-02)
• Updated input 'hercules-ci-effects/nixpkgs':
    'github:NixOS/nixpkgs/1412caf7bf9e660f2f962917c14b1ea1c3bc695e?narHash=sha256-AIdl6WAn9aymeaH/NvBj0H9qM%2BXuAuYbGMZaP0zcXAQ%3D' (2026-01-13)
  → 'github:NixOS/nixpkgs/a82ccc39b39b621151d6732718e3e250109076fa?narHash=sha256-gf2AmWVTs8lEq7z/3ZAsgnZDhWIckkb%2BZnAo5RzSxJg%3D' (2026-02-13)
• Updated input 'pre-commit-hooks-nix':
    'github:cachix/pre-commit-hooks.nix/a1ef738813b15cf8ec759bdff5761b027e3e1d23?narHash=sha256-Efs3VUPelRduf3PpfPP2ovEB4CXT7vHf8W%2Bxc49RL/U%3D' (2026-01-22)
  → 'github:cachix/pre-commit-hooks.nix/6e34e97ed9788b17796ee43ccdbaf871a5c2b476?narHash=sha256-%2BeXlIc4/7dE6EcPs9a2DaSY3fTA9AE526hGqkNID3Wg%3D' (2026-02-25)
• Updated input 'treefmt-nix':
    'github:numtide/treefmt-nix/28b19c5844cc6e2257801d43f2772a4b4c050a1b?narHash=sha256-8aAYwyVzSSwIhP2glDhw/G0i5%2BwOrren3v6WmxkVonM%3D' (2026-01-29)
  → 'github:numtide/treefmt-nix/337a4fe074be1042a35086f15481d763b8ddc0e7?narHash=sha256-wQ6NJSuFqAEmIg2VMnLdCnUc0b7vslUohqqGGD%2BFyxk%3D' (2026-02-04)
2026-03-01 02:33:12 +00:00
Hercules CI Effects 6ee502a4f9 flake.lock: Update
Flake lock file updates:

• Updated input 'flake-parts':
    'github:hercules-ci/flake-parts/80daad04eddbbf5a4d883996a73f3f542fa437ac?narHash=sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY%3D' (2026-01-11)
  → 'github:hercules-ci/flake-parts/57928607ea566b5db3ad13af0e57e921e6b12381?narHash=sha256-AnYjnFWgS49RlqX7LrC4uA%2BsCCDBj0Ry/WOJ5XWAsa0%3D' (2026-02-02)
• Updated input 'flake-parts/nixpkgs-lib':
    'github:nix-community/nixpkgs.lib/2075416fcb47225d9b68ac469a5c4801a9c4dd85?narHash=sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo%3D' (2025-12-14)
  → 'github:nix-community/nixpkgs.lib/72716169fe93074c333e8d0173151350670b824c?narHash=sha256-cBEymOf4/o3FD5AZnzC3J9hLbiZ%2BQDT/KDuyHXVJOpM%3D' (2026-02-01)
• Updated input 'nix':
    'github:NixOS/nix/77b6b01b727f0cd1324e431a32a8854768b957ef?narHash=sha256-vpI7XEfX5zeCVRANUzhMNsZfrMWuN0rwNenQ3z0rJNo%3D' (2026-01-30)
  → 'github:NixOS/nix/0acd0566e85e4597269482824711bcde7b518600?narHash=sha256-jJIlRLPPVYu860MVFx4gsRx3sskmLDSRWXXue5tYncw%3D' (2026-02-27)
• Updated input 'nix-cargo-integration':
    'github:90-008/nix-cargo-integration/6d583e2098fa3df490c2597df06386e3efcc39b6?narHash=sha256-bjtDp0NHjLjDOjklQVHCDCVM5q39zDzuwenNri0p4Ys%3D' (2026-01-31)
  → 'github:90-008/nix-cargo-integration/c783c5dff02c06f2af6226d4dd4d494542d0a4d2?narHash=sha256-NaUqM0i6XIGdgRNxxQ9sfgCAVeE2Ko9rz7e19RsNUKw%3D' (2026-02-28)
• Updated input 'nix-cargo-integration/parts':
    'github:hercules-ci/flake-parts/80daad04eddbbf5a4d883996a73f3f542fa437ac?narHash=sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY%3D' (2026-01-11)
  → 'github:hercules-ci/flake-parts/57928607ea566b5db3ad13af0e57e921e6b12381?narHash=sha256-AnYjnFWgS49RlqX7LrC4uA%2BsCCDBj0Ry/WOJ5XWAsa0%3D' (2026-02-02)
• Updated input 'nix-cargo-integration/rust-overlay':
    'github:oxalica/rust-overlay/a1d32c90c8a4ea43e9586b7e5894c179d5747425?narHash=sha256-zmnvRUm15QrlKH0V1BZoiT3U%2BQ%2Btr%2BP5Osi8qgtL9fY%3D' (2026-01-31)
  → 'github:oxalica/rust-overlay/a1ab5e89ab12e1a37c0b264af6386a7472d68a15?narHash=sha256-x6IFQ9bL7YYfW2m2z8D3Em2YtAA3HE8kiCFwai2fwrw%3D' (2026-02-28)
• Updated input 'nix-cargo-integration/treefmt':
    'github:numtide/treefmt-nix/28b19c5844cc6e2257801d43f2772a4b4c050a1b?narHash=sha256-8aAYwyVzSSwIhP2glDhw/G0i5%2BwOrren3v6WmxkVonM%3D' (2026-01-29)
  → 'github:numtide/treefmt-nix/337a4fe074be1042a35086f15481d763b8ddc0e7?narHash=sha256-wQ6NJSuFqAEmIg2VMnLdCnUc0b7vslUohqqGGD%2BFyxk%3D' (2026-02-04)
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/bfc1b8a4574108ceef22f02bafcf6611380c100d?narHash=sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI%3D' (2026-01-26)
  → 'github:NixOS/nixpkgs/dd9b079222d43e1943b6ebd802f04fd959dc8e61?narHash=sha256-I45esRSssFtJ8p/gLHUZ1OUaaTaVLluNkABkk6arQwE%3D' (2026-02-27)
2026-03-01 02:33:10 +00:00
14 changed files with 825 additions and 273 deletions
+4
View File
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- `primop::RecoverableError` for primop errors that should not be memoized in the thunk, allowing retry on next force. Required by Nix >= 2.34 ([release note](https://nix.dev/manual/nix/2.34/release-notes/rl-2.34.html#c-api-changes)) for recoverable errors to remain recoverable, as Nix 2.34 memoizes errors by default.
## [0.2.0] - 2026-01-13
### Added
+3 -5
View File
@@ -7,12 +7,10 @@ echo "Extending BINDGEN_EXTRA_CLANG_ARGS with system include paths..." 2>&1
BINDGEN_EXTRA_CLANG_ARGS="${BINDGEN_EXTRA_CLANG_ARGS:-}"
export BINDGEN_EXTRA_CLANG_ARGS
include_paths=$(
echo | $NIX_CC_UNWRAPPED -v -E -x c - 2>&1 \
LC_ALL=C $NIX_CC_UNWRAPPED -v -E -x c - </dev/null 2>&1 \
| awk '/#include <...> search starts here:/{flag=1;next} \
/End of search list./{flag=0} \
flag==1 {print $1}'
)
for path in $include_paths; do
echo " - $path" 2>&1
BINDGEN_EXTRA_CLANG_ARGS="$BINDGEN_EXTRA_CLANG_ARGS -I$path"
done
include_args=$(printf '%s\n' "$include_paths" | awk 'NF {printf " -I%s", $1; printf " - %s\n", $1 > "/dev/stderr"}')
BINDGEN_EXTRA_CLANG_ARGS="$BINDGEN_EXTRA_CLANG_ARGS$include_args"
+15 -15
View File
@@ -24,11 +24,11 @@
]
},
"locked": {
"lastModified": 1768135262,
"narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=",
"lastModified": 1769996383,
"narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac",
"rev": "57928607ea566b5db3ad13af0e57e921e6b12381",
"type": "github"
},
"original": {
@@ -63,11 +63,11 @@
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1768476106,
"narHash": "sha256-V0YOJRum50gtKgwavsAfwXc9+XAsJCC7386YZx1sWGQ=",
"lastModified": 1771131391,
"narHash": "sha256-HPBNYf7HiKtBVy7/69vKpLYHX6wTcUxndxmybzDlXP8=",
"owner": "hercules-ci",
"repo": "hercules-ci-effects",
"rev": "c19e263e6e22ec7379d972f19e6a322f943c73fb",
"rev": "0b152e0f7c5cc265a529cd63374b80e2771b207b",
"type": "github"
},
"original": {
@@ -78,11 +78,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1768305791,
"narHash": "sha256-AIdl6WAn9aymeaH/NvBj0H9qM+XuAuYbGMZaP0zcXAQ=",
"lastModified": 1771008912,
"narHash": "sha256-gf2AmWVTs8lEq7z/3ZAsgnZDhWIckkb+ZnAo5RzSxJg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1412caf7bf9e660f2f962917c14b1ea1c3bc695e",
"rev": "a82ccc39b39b621151d6732718e3e250109076fa",
"type": "github"
},
"original": {
@@ -99,11 +99,11 @@
"nixpkgs": []
},
"locked": {
"lastModified": 1769069492,
"narHash": "sha256-Efs3VUPelRduf3PpfPP2ovEB4CXT7vHf8W+xc49RL/U=",
"lastModified": 1772024342,
"narHash": "sha256-+eXlIc4/7dE6EcPs9a2DaSY3fTA9AE526hGqkNID3Wg=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "a1ef738813b15cf8ec759bdff5761b027e3e1d23",
"rev": "6e34e97ed9788b17796ee43ccdbaf871a5c2b476",
"type": "github"
},
"original": {
@@ -124,11 +124,11 @@
"nixpkgs": []
},
"locked": {
"lastModified": 1769691507,
"narHash": "sha256-8aAYwyVzSSwIhP2glDhw/G0i5+wOrren3v6WmxkVonM=",
"lastModified": 1770228511,
"narHash": "sha256-wQ6NJSuFqAEmIg2VMnLdCnUc0b7vslUohqqGGD+Fyxk=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "28b19c5844cc6e2257801d43f2772a4b4c050a1b",
"rev": "337a4fe074be1042a35086f15481d763b8ddc0e7",
"type": "github"
},
"original": {
Generated
+35 -35
View File
@@ -43,15 +43,15 @@
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1767039857,
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
"owner": "NixOS",
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "NixOS",
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
@@ -77,11 +77,11 @@
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1768135262,
"narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=",
"lastModified": 1777988971,
"narHash": "sha256-qIoWPDs+0/8JecyYgE3gpKQxW/4bLW/gp45vow9ioCQ=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac",
"rev": "0678d8986be1661af6bb555f3489f2fdfc31f6ff",
"type": "github"
},
"original": {
@@ -159,11 +159,11 @@
"nixpkgs-regression": "nixpkgs-regression"
},
"locked": {
"lastModified": 1769182158,
"narHash": "sha256-QE+cj0eHW8kzuEbzfxQXfweSbps8sJyzHUjfrQKfWYo=",
"lastModified": 1778096718,
"narHash": "sha256-RnGxdnwhrEpLIqkRnXeb9caVLsKOboOMjMifEz+RaOk=",
"owner": "DeterminateSystems",
"repo": "nix-src",
"rev": "731906053f4feba452c9bc782768263f9baf9ee4",
"rev": "8fb8ad7b69f5715c66720106c8b3a6dd8d0a51d8",
"type": "github"
},
"original": {
@@ -185,11 +185,11 @@
"treefmt": "treefmt"
},
"locked": {
"lastModified": 1769840916,
"narHash": "sha256-bjtDp0NHjLjDOjklQVHCDCVM5q39zDzuwenNri0p4Ys=",
"lastModified": 1778141945,
"narHash": "sha256-unLKBy8SaNxEXaqMmXDUZyZIzf3K1H46azxFJDMq1jU=",
"owner": "90-008",
"repo": "nix-cargo-integration",
"rev": "6d583e2098fa3df490c2597df06386e3efcc39b6",
"rev": "aceca529e10a880594b11c31a0e98d70d4a9c975",
"type": "github"
},
"original": {
@@ -200,16 +200,16 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1761597516,
"narHash": "sha256-wxX7u6D2rpkJLWkZ2E932SIvDJW8+ON/0Yy8+a5vsDU=",
"rev": "daf6dc47aa4b44791372d6139ab7b25269184d55",
"revCount": 811874,
"lastModified": 1773222311,
"narHash": "sha256-BHoB/XpbqoZkVYZCfXJXfkR+GXFqwb/4zbWnOr2cRcU=",
"rev": "0590cd39f728e129122770c029970378a79d076a",
"revCount": 909248,
"type": "tarball",
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.2505.811874%2Brev-daf6dc47aa4b44791372d6139ab7b25269184d55/019a3494-3498-707e-9086-1fb81badc7fe/source.tar.gz"
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.2511.909248%2Brev-0590cd39f728e129122770c029970378a79d076a/019ce32b-8ace-7339-b129-cceaa8dd10c6/source.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://flakehub.com/f/NixOS/nixpkgs/0.2505"
"url": "https://flakehub.com/f/NixOS/nixpkgs/0.2511"
}
},
"nixpkgs-23-11": {
@@ -230,11 +230,11 @@
},
"nixpkgs-lib": {
"locked": {
"lastModified": 1765674936,
"narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=",
"lastModified": 1777168982,
"narHash": "sha256-GOkGPcboWE9BmGCRMLX3worL4EMnsnG8MyKmXNeYuhQ=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85",
"rev": "f5901329dade4a6ea039af1433fb087bd9c1fe14",
"type": "github"
},
"original": {
@@ -261,11 +261,11 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1766902085,
"narHash": "sha256-coBu0ONtFzlwwVBzmjacUQwj3G+lybcZ1oeNSQkgC0M=",
"lastModified": 1777954456,
"narHash": "sha256-hGdgeU2Nk87RAuZyYjyDjFL6LK7dAZN5RE9+hrDTkDU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "c0b0e0fddf73fd517c3471e546c0df87a42d53f4",
"rev": "549bd84d6279f9852cae6225e372cc67fb91a4c1",
"type": "github"
},
"original": {
@@ -283,11 +283,11 @@
]
},
"locked": {
"lastModified": 1768135262,
"narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=",
"lastModified": 1777988971,
"narHash": "sha256-qIoWPDs+0/8JecyYgE3gpKQxW/4bLW/gp45vow9ioCQ=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac",
"rev": "0678d8986be1661af6bb555f3489f2fdfc31f6ff",
"type": "github"
},
"original": {
@@ -358,11 +358,11 @@
]
},
"locked": {
"lastModified": 1769828398,
"narHash": "sha256-zmnvRUm15QrlKH0V1BZoiT3U+Q+tr+P5Osi8qgtL9fY=",
"lastModified": 1778123869,
"narHash": "sha256-hV9D8ET33kXjdoMXBT2bwM/j8WQM1SP/dVKZtjQKhAQ=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "a1d32c90c8a4ea43e9586b7e5894c179d5747425",
"rev": "592e5dedf04f0eaff1ed0f01ce5db7407d9fc7be",
"type": "github"
},
"original": {
@@ -402,11 +402,11 @@
]
},
"locked": {
"lastModified": 1769691507,
"narHash": "sha256-8aAYwyVzSSwIhP2glDhw/G0i5+wOrren3v6WmxkVonM=",
"lastModified": 1775636079,
"narHash": "sha256-pc20NRoMdiar8oPQceQT47UUZMBTiMdUuWrYu2obUP0=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "28b19c5844cc6e2257801d43f2772a4b4c050a1b",
"rev": "790751ff7fd3801feeaf96d7dc416a8d581265ba",
"type": "github"
},
"original": {
+1 -1
View File
@@ -2,5 +2,5 @@ use nix_bindings_util::nix_version::emit_version_cfg;
fn main() {
let nix_version = pkg_config::probe_library("nix-expr-c").unwrap().version;
emit_version_cfg(&nix_version, &["2.26"]);
emit_version_cfg(&nix_version, &["2.26", "2.34.0pre"]);
}
File diff suppressed because it is too large Load Diff
+30 -4
View File
@@ -2,11 +2,15 @@ use crate::eval_state::{EvalState, EvalStateError};
use crate::value::Value;
use nix_bindings_expr_sys as raw;
use nix_bindings_util::check_call;
use nix_bindings_util::context::Context;
use nix_bindings_util_sys as raw_util;
use std::error::Error;
use std::ffi::{c_int, c_void, CStr, CString};
use std::ptr::{null, null_mut};
#[cfg(nix_at_least = "2.34.0pre")]
use nix_bindings_util::Error as NixError;
/// Metadata for a primop, used with `PrimOp::new`.
pub struct PrimOpMeta<'a, const N: usize> {
/// Name of the primop. Note that primops do not have to be registered as
@@ -28,6 +32,7 @@ pub struct PrimOp<'a> {
ptr: *mut raw::PrimOp,
eval_state: &'a mut EvalState,
}
impl Drop for PrimOp<'_> {
fn drop(&mut self) {
unsafe {
@@ -35,7 +40,13 @@ impl Drop for PrimOp<'_> {
}
}
}
impl<'a> PrimOp<'a> {
/// Create a new primop with the given metadata and implementation.
///
/// When `f` returns an `Err`, the error is propagated to the Nix evaluator.
/// To return a [recoverable error](RecoverableError), include it in the
/// error chain (e.g. `Err(RecoverableError::new("...").into())`).
pub fn new<const N: usize>(
eval_state: &'a mut EvalState,
meta: PrimOpMeta<N>,
@@ -61,9 +72,10 @@ impl<'a> PrimOp<'a> {
}));
user_data as *const PrimOpContext as *mut c_void
};
let mut ctx = Context::new();
let op = unsafe {
check_call!(raw::alloc_primop(
&mut eval_state.context,
&mut ctx,
FUNCTION_ADAPTER,
N as c_int,
meta.name.as_ptr(),
@@ -90,8 +102,9 @@ impl<'a> PrimOp<'a> {
pub fn new_value(mut self) -> Result<Value, EvalStateError> {
self.with_state_and_ptr(|ptr, this| {
let value = this.new_value_uninitialized()?;
let mut ctx = Context::new();
unsafe {
check_call!(raw::init_primop(&mut this.context, value.raw_ptr(), ptr))?;
check_call!(raw::init_primop(&mut ctx, value.raw_ptr(), ptr))?;
};
Ok(value)
})
@@ -134,13 +147,26 @@ unsafe extern "C" fn function_adapter(
raw::copy_value(context_out, ret, v.raw_ptr());
},
Err(e) => unsafe {
let cstr = CString::new(e.to_string()).unwrap_or_else(|_e| {
let err_str = e.to_string();
let err_code = error_code(e);
let cstr = CString::new(err_str).unwrap_or_else(|_e| {
CString::new("<rust nix-expr application error message contained null byte>")
.unwrap()
});
raw_util::set_err_msg(context_out, raw_util::err_NIX_ERR_UNKNOWN, cstr.as_ptr());
raw_util::set_err_msg(context_out, err_code, cstr.as_ptr());
},
}
}
#[cfg_attr(not(nix_at_least = "2.34.0pre"), allow(unused))]
fn error_code(e: Box<dyn Error>) -> raw_util::err {
#[cfg(nix_at_least = "2.34.0pre")]
if e.downcast_ref::<NixError>()
.is_some_and(|e| matches!(e, NixError::RecoverableError(_)))
{
return raw_util::err_NIX_ERR_RECOVERABLE;
}
raw_util::err_NIX_ERR_UNKNOWN
}
static FUNCTION_ADAPTER: raw::PrimOpFun = Some(function_adapter);
+4
View File
@@ -83,6 +83,10 @@ impl ValueType {
pub struct Value {
inner: NonNull<raw::Value>,
}
unsafe impl Send for Value {}
unsafe impl Sync for Value {}
impl Value {
/// Take ownership of a new [`Value`].
///
+12 -1
View File
@@ -13,6 +13,10 @@ use nix_bindings_util::{Error, Result};
pub struct FlakeSettings {
pub(crate) ptr: *mut raw::flake_settings,
}
unsafe impl Send for FlakeSettings {}
unsafe impl Sync for FlakeSettings {}
impl Drop for FlakeSettings {
fn drop(&mut self) {
unsafe {
@@ -20,6 +24,7 @@ impl Drop for FlakeSettings {
}
}
}
impl FlakeSettings {
pub fn new() -> Result<Self> {
let mut ctx = Context::new();
@@ -49,6 +54,7 @@ pub trait EvalStateBuilderExt {
settings: &FlakeSettings,
) -> Result<nix_bindings_expr::eval_state::EvalStateBuilder>;
}
impl EvalStateBuilderExt for nix_bindings_expr::eval_state::EvalStateBuilder {
/// Configures the eval state to provide flakes features such as `builtins.getFlake`.
fn flakes(
@@ -206,6 +212,10 @@ impl FlakeLockFlags {
pub struct LockedFlake {
pub(crate) ptr: NonNull<raw::locked_flake>,
}
unsafe impl Send for LockedFlake {}
unsafe impl Sync for LockedFlake {}
impl Drop for LockedFlake {
fn drop(&mut self) {
unsafe {
@@ -213,6 +223,7 @@ impl Drop for LockedFlake {
}
}
}
impl LockedFlake {
pub fn lock(
fetch_settings: &FetchersSettings,
@@ -295,7 +306,7 @@ mod tests {
init();
let gc_registration = gc_register_my_thread();
let store = Store::open(None, []).unwrap();
let mut eval_state = EvalStateBuilder::new(store)
let eval_state = EvalStateBuilder::new(store)
.unwrap()
.flakes(&FlakeSettings::new().unwrap())
.unwrap()
+3
View File
@@ -20,6 +20,9 @@ pub struct StorePath {
raw: NonNull<raw::StorePath>,
}
unsafe impl Send for StorePath {}
unsafe impl Sync for StorePath {}
impl StorePath {
/// Get the name of the store path.
///
+29 -22
View File
@@ -56,10 +56,7 @@ impl StoreWeak {
///
/// If no normal reference to the [Store] is around anymore elsewhere, this fails by returning `None`.
pub fn upgrade(&self) -> Option<Store> {
self.inner.upgrade().map(|inner| Store {
inner,
context: Context::new(),
})
self.inner.upgrade().map(|inner| Store { inner })
}
}
@@ -144,8 +141,6 @@ fn callback_make_drv_outputs_data(vec: &mut HashMap<String, String>) -> *mut std
#[clippy::has_significant_drop]
pub struct Store {
inner: Arc<StoreRef>,
/* An error context to reuse. This way we don't have to allocate them for each store operation. */
context: Context,
}
impl Store {
/// Open a store.
@@ -236,7 +231,6 @@ impl Store {
inner: Arc::new(StoreRef {
inner: NonNull::new(store).unwrap(),
}),
context,
};
Ok(store)
}
@@ -251,9 +245,10 @@ impl Store {
#[doc(alias = "nix_store_get_uri")]
pub fn get_uri(&mut self) -> Result<String> {
let mut r = Err(Error::StringInit);
let mut ctx = Context::new();
unsafe {
check_call!(raw::store_get_uri(
&mut self.context,
&mut ctx,
self.inner.ptr(),
Some(callback_get_result_string),
callback_get_result_string_data(&mut r)
@@ -266,9 +261,10 @@ impl Store {
#[doc(alias = "nix_store_get_storedir")]
pub fn get_storedir(&mut self) -> Result<String> {
let mut r = Err(Error::StringInit);
let mut ctx = Context::new();
unsafe {
check_call!(raw::store_get_storedir(
&mut self.context,
&mut ctx,
self.inner.ptr(),
Some(callback_get_result_string),
callback_get_result_string_data(&mut r)
@@ -280,9 +276,10 @@ impl Store {
#[doc(alias = "nix_store_get_version")]
pub fn get_version(&mut self) -> Result<String> {
let mut r = Err(Error::StringInit);
let mut ctx = Context::new();
unsafe {
check_call!(raw::store_get_version(
&mut self.context,
&mut ctx,
self.inner.ptr(),
Some(callback_get_result_string),
callback_get_result_string_data(&mut r)
@@ -294,9 +291,10 @@ impl Store {
#[doc(alias = "nix_store_parse_path")]
pub fn parse_store_path(&mut self, path: &str) -> Result<StorePath> {
let path = CString::new(path)?;
let mut ctx = Context::new();
unsafe {
let store_path = check_call!(raw::store_parse_path(
&mut self.context,
&mut ctx,
self.inner.ptr(),
path.as_ptr()
))?;
@@ -309,9 +307,10 @@ impl Store {
#[doc(alias = "nix_store_real_path")]
pub fn real_path(&mut self, path: &StorePath) -> Result<String> {
let mut r = Err(Error::StringInit);
let mut ctx = Context::new();
unsafe {
check_call!(raw::store_real_path(
&mut self.context,
&mut ctx,
self.inner.ptr(),
path.as_ptr(),
Some(callback_get_result_string),
@@ -339,9 +338,10 @@ impl Store {
#[doc(alias = "nix_derivation_from_json")]
pub fn derivation_from_json(&mut self, json: &str) -> Result<Derivation> {
let json_cstr = CString::new(json)?;
let mut ctx = Context::new();
unsafe {
let drv = check_call!(raw::derivation_from_json(
&mut self.context,
&mut ctx,
self.inner.ptr(),
json_cstr.as_ptr()
))?;
@@ -365,9 +365,10 @@ impl Store {
#[cfg(nix_at_least = "2.31")]
#[doc(alias = "nix_add_derivation")]
pub fn add_derivation(&mut self, drv: &Derivation) -> Result<StorePath> {
let mut ctx = Context::new();
unsafe {
let path = check_call!(raw::add_derivation(
&mut self.context,
&mut ctx,
self.inner.ptr(),
drv.inner.as_ptr()
))?;
@@ -380,9 +381,10 @@ impl Store {
pub fn make_drv_outputs(&mut self, json: &str) -> Result<HashMap<String, String>> {
let json = CString::new(json)?;
let mut r = HashMap::new();
let mut ctx = Context::new();
unsafe {
check_call!(raw::derivation_make_outputs(
&mut self.context,
&mut ctx,
self.inner.ptr(),
json.as_ptr(),
Some(callback_make_drv_outputs),
@@ -425,9 +427,10 @@ impl Store {
.map(|p| unsafe { p.as_ptr() as *const raw::StorePath })
.collect();
let mut ctx = Context::new();
unsafe {
check_call!(raw::store_build_paths(
&mut self.context,
&mut ctx,
self.inner.ptr(),
paths.as_mut_ptr(),
paths.len() as std::os::raw::c_uint,
@@ -479,9 +482,10 @@ impl Store {
outputs.insert(name, path);
}
let mut ctx = Context::new();
unsafe {
check_call!(raw::store_realise(
&mut self.context,
&mut ctx,
self.inner.ptr(),
path.as_ptr(),
userdata,
@@ -520,9 +524,10 @@ impl Store {
include_derivers: bool,
) -> Result<Vec<StorePath>> {
let mut r = Vec::new();
let mut ctx = Context::new();
unsafe {
check_call!(raw::store_get_fs_closure(
&mut self.context,
&mut ctx,
self.inner.ptr(),
store_path.as_ptr(),
flip_direction,
@@ -538,9 +543,10 @@ impl Store {
#[doc(alias = "nix_store_drv_from_path")]
pub fn drv_from_path(&mut self, path: &StorePath) -> Result<Derivation> {
let mut r = Err(Error::DerivationInit);
let mut ctx = Context::new();
unsafe {
check_call!(raw::store_drv_from_path(
&mut self.context,
&mut ctx,
self.inner.ptr(),
path.as_ptr(),
Some(callback_get_result_derivation),
@@ -553,9 +559,10 @@ impl Store {
#[doc(alias = "nix_store_query_path_info")]
pub fn query_path_info(&mut self, path: &StorePath) -> Result<String> {
let mut r = Err(Error::StringInit);
let mut ctx = Context::new();
unsafe {
check_call!(raw::store_query_path_info(
&mut self.context,
&mut ctx,
self.inner.ptr(),
path.as_ptr(),
callback_get_result_string_data(&mut r),
@@ -576,7 +583,6 @@ impl Clone for Store {
fn clone(&self) -> Self {
Store {
inner: self.inner.clone(),
context: Context::new(),
}
}
}
@@ -960,7 +966,8 @@ mod tests {
};
assert!(
err.contains("required system or feature not available"),
err.contains("required system or feature not available")
|| err.contains("platform mismatch"),
"Error should mention system not available, got: {}",
err
);
+2
View File
@@ -12,6 +12,8 @@ pub struct Context {
inner: NonNull<raw::c_context>,
}
unsafe impl Send for Context {}
impl Default for Context {
fn default() -> Self {
Self::new()
+16
View File
@@ -6,6 +6,7 @@ use std::{ffi::NulError, str::Utf8Error, string::FromUtf8Error};
use thiserror::Error;
pub mod context;
pub mod logger;
pub mod settings;
#[macro_use]
pub mod string_return;
@@ -91,6 +92,21 @@ pub enum Error {
/// A string that needed to be valid UTF-8 was not valid UTF-8.
#[error(transparent)]
StringUtf8Error(#[from] FromUtf8Error),
/// A primop error that is not memoized in the thunk that triggered it,
/// allowing the thunk to be forced again.
///
/// Since [Nix 2.34](https://nix.dev/manual/nix/2.34/release-notes/rl-2.34.html#c-api-changes),
/// primop errors are memoized by default: once a thunk fails, forcing it
/// again returns the same error. Use `RecoverableError` for errors that
/// are transient, so the caller can retry.
///
/// On Nix < 2.34, all errors are already recoverable, so this type has
/// no additional effect.
///
/// Available since nix-bindings-expr 0.2.1.
#[error("{0}")]
RecoverableError(String),
}
/// An error as returned from the Nix API.
+382
View File
@@ -0,0 +1,382 @@
//! Custom Nix logger.
//!
//! Replace Nix's global logger with a Rust callback-based one that
//! receives log messages, activities, and string-valued results from
//! anywhere in libnixutil, libnixstore, and libnixexpr.
//!
//! See the [`Logger`] trait and [`set_logger`].
use crate::raw_sys as raw;
use crate::{check_call, context, Result};
use std::ffi::{c_char, c_void, CStr};
use std::sync::Mutex;
/// Verbosity level of a log message.
///
/// Mirrors the C `nix_verbosity` enum.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Verbosity {
Error,
Warn,
Notice,
Info,
Talkative,
Chatty,
Debug,
Vomit,
/// A verbosity level not (yet) modelled by this crate.
Unknown(u32),
}
impl Verbosity {
fn from_raw(v: raw::verbosity) -> Self {
match v {
raw::verbosity_NIX_LVL_ERROR => Verbosity::Error,
raw::verbosity_NIX_LVL_WARN => Verbosity::Warn,
raw::verbosity_NIX_LVL_NOTICE => Verbosity::Notice,
raw::verbosity_NIX_LVL_INFO => Verbosity::Info,
raw::verbosity_NIX_LVL_TALKATIVE => Verbosity::Talkative,
raw::verbosity_NIX_LVL_CHATTY => Verbosity::Chatty,
raw::verbosity_NIX_LVL_DEBUG => Verbosity::Debug,
raw::verbosity_NIX_LVL_VOMIT => Verbosity::Vomit,
other => Verbosity::Unknown(other),
}
}
}
/// Identifier for a logger activity. `0` is the implicit root.
pub type ActivityId = u64;
/// Type of an activity.
///
/// Mirrors the C `nix_activity_type` enum.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ActivityType {
Unknown,
CopyPath,
FileTransfer,
Realise,
CopyPaths,
Builds,
Build,
OptimiseStore,
VerifyPaths,
Substitute,
QueryPathInfo,
PostBuildHook,
BuildWaiting,
FetchTree,
/// An activity type not (yet) modelled by this crate.
Other(u32),
}
impl ActivityType {
fn from_raw(t: raw::activity_type) -> Self {
match t {
raw::activity_type_NIX_ACTIVITY_TYPE_UNKNOWN => ActivityType::Unknown,
raw::activity_type_NIX_ACTIVITY_TYPE_COPY_PATH => ActivityType::CopyPath,
raw::activity_type_NIX_ACTIVITY_TYPE_FILE_TRANSFER => ActivityType::FileTransfer,
raw::activity_type_NIX_ACTIVITY_TYPE_REALISE => ActivityType::Realise,
raw::activity_type_NIX_ACTIVITY_TYPE_COPY_PATHS => ActivityType::CopyPaths,
raw::activity_type_NIX_ACTIVITY_TYPE_BUILDS => ActivityType::Builds,
raw::activity_type_NIX_ACTIVITY_TYPE_BUILD => ActivityType::Build,
raw::activity_type_NIX_ACTIVITY_TYPE_OPTIMISE_STORE => ActivityType::OptimiseStore,
raw::activity_type_NIX_ACTIVITY_TYPE_VERIFY_PATHS => ActivityType::VerifyPaths,
raw::activity_type_NIX_ACTIVITY_TYPE_SUBSTITUTE => ActivityType::Substitute,
raw::activity_type_NIX_ACTIVITY_TYPE_QUERY_PATH_INFO => ActivityType::QueryPathInfo,
raw::activity_type_NIX_ACTIVITY_TYPE_POST_BUILD_HOOK => ActivityType::PostBuildHook,
raw::activity_type_NIX_ACTIVITY_TYPE_BUILD_WAITING => ActivityType::BuildWaiting,
raw::activity_type_NIX_ACTIVITY_TYPE_FETCH_TREE => ActivityType::FetchTree,
other => ActivityType::Other(other),
}
}
}
/// Type of a result reported by an activity.
///
/// Only string-valued result types are delivered to
/// [`Logger::result_string`]; other variants exist for forward
/// compatibility.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ResultType {
FileLinked,
BuildLogLine,
UntrustedPath,
CorruptedPath,
SetPhase,
Progress,
SetExpected,
PostBuildLogLine,
FetchStatus,
HashMismatch,
BuildResult,
/// A result type not (yet) modelled by this crate.
Other(u32),
}
impl ResultType {
fn from_raw(t: raw::result_type) -> Self {
match t {
raw::result_type_NIX_RESULT_TYPE_FILE_LINKED => ResultType::FileLinked,
raw::result_type_NIX_RESULT_TYPE_BUILD_LOG_LINE => ResultType::BuildLogLine,
raw::result_type_NIX_RESULT_TYPE_UNTRUSTED_PATH => ResultType::UntrustedPath,
raw::result_type_NIX_RESULT_TYPE_CORRUPTED_PATH => ResultType::CorruptedPath,
raw::result_type_NIX_RESULT_TYPE_SET_PHASE => ResultType::SetPhase,
raw::result_type_NIX_RESULT_TYPE_PROGRESS => ResultType::Progress,
raw::result_type_NIX_RESULT_TYPE_SET_EXPECTED => ResultType::SetExpected,
raw::result_type_NIX_RESULT_TYPE_POST_BUILD_LOG_LINE => ResultType::PostBuildLogLine,
raw::result_type_NIX_RESULT_TYPE_FETCH_STATUS => ResultType::FetchStatus,
raw::result_type_NIX_RESULT_TYPE_HASH_MISMATCH => ResultType::HashMismatch,
raw::result_type_NIX_RESULT_TYPE_BUILD_RESULT => ResultType::BuildResult,
other => ResultType::Other(other),
}
}
}
/// A logger that receives messages from Nix.
///
/// Implementations must be [`Send`] and [`Sync`] because Nix may
/// invoke the callbacks from arbitrary threads (e.g. during parallel
/// builds).
///
/// All methods have empty default implementations, so an
/// implementation only needs to override the events it cares about.
///
/// # Panics
///
/// Callback methods must not unwind across the FFI boundary.
/// Panics from any of these methods are caught and silently
/// discarded; if your implementation may panic, prefer to handle
/// it yourself.
pub trait Logger: Send + Sync {
/// An ordinary log message.
///
/// Receives `builtins.trace` output, formatted warnings/errors,
/// and messages produced through the C++ `printError` /
/// `printInfo` / `debug` macros.
///
/// `msg` is decoded with [`String::from_utf8_lossy`] to keep the
/// signature ergonomic.
fn log(&self, _level: Verbosity, _msg: &str) {}
/// An activity (build, substitution, ...) has started.
///
/// `parent_id` is `0` for top-level activities.
fn start_activity(
&self,
_activity_id: ActivityId,
_level: Verbosity,
_type_: ActivityType,
_description: &str,
_parent_id: ActivityId,
) {
}
/// An activity has stopped.
fn stop_activity(&self, _activity_id: ActivityId) {}
/// An activity reported a string-valued result.
///
/// Result types that carry non-string fields (such as
/// [`ResultType::Progress`]) are not delivered through this
/// method.
fn result_string(&self, _activity_id: ActivityId, _type_: ResultType, _msg: &str) {}
}
/// Erased trait object passed across the FFI boundary as `userdata`.
type LoggerObj = Box<dyn Logger + Send + Sync>;
/// Serializes calls to [`set_logger`] from the Rust side.
///
/// Note this does *not* protect against C++ code (or other clients of
/// the C API) replacing the global logger concurrently — it only
/// avoids racing with ourselves.
static SET_LOGGER_MUTEX: Mutex<()> = Mutex::new(());
unsafe extern "C" fn thunk_log(userdata: *mut c_void, level: raw::verbosity, msg: *const c_char) {
assert!(!userdata.is_null());
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let logger = &*(userdata as *const LoggerObj);
let msg_str = if msg.is_null() {
std::borrow::Cow::Borrowed("")
} else {
CStr::from_ptr(msg).to_string_lossy()
};
logger.log(Verbosity::from_raw(level), msg_str.as_ref());
}));
}
unsafe extern "C" fn thunk_start_activity(
userdata: *mut c_void,
activity_id: raw::activity_id,
level: raw::verbosity,
type_: raw::activity_type,
s: *const c_char,
parent_id: raw::activity_id,
) {
assert!(!userdata.is_null());
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let logger = &*(userdata as *const LoggerObj);
let s_str = if s.is_null() {
std::borrow::Cow::Borrowed("")
} else {
CStr::from_ptr(s).to_string_lossy()
};
logger.start_activity(
activity_id,
Verbosity::from_raw(level),
ActivityType::from_raw(type_),
s_str.as_ref(),
parent_id,
);
}));
}
unsafe extern "C" fn thunk_stop_activity(userdata: *mut c_void, activity_id: raw::activity_id) {
assert!(!userdata.is_null());
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let logger = &*(userdata as *const LoggerObj);
logger.stop_activity(activity_id);
}));
}
unsafe extern "C" fn thunk_result_string(
userdata: *mut c_void,
activity_id: raw::activity_id,
type_: raw::result_type,
msg: *const c_char,
) {
assert!(!userdata.is_null());
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let logger = &*(userdata as *const LoggerObj);
let msg_str = if msg.is_null() {
std::borrow::Cow::Borrowed("")
} else {
CStr::from_ptr(msg).to_string_lossy()
};
logger.result_string(activity_id, ResultType::from_raw(type_), msg_str.as_ref());
}));
}
unsafe extern "C" fn thunk_destroy(userdata: *mut c_void) {
if userdata.is_null() {
return;
}
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
drop(Box::from_raw(userdata as *mut LoggerObj));
}));
}
static VTABLE: raw::logger = raw::logger {
log: Some(thunk_log),
start_activity: Some(thunk_start_activity),
stop_activity: Some(thunk_stop_activity),
result_string: Some(thunk_result_string),
destroy: Some(thunk_destroy),
};
/// Replace Nix's global logger with `logger`.
///
/// `logger` is moved into a heap allocation owned by Nix; it is
/// dropped when this function is called again (replacing the logger)
/// or at process shutdown.
///
/// # Thread safety
///
/// This function serializes concurrent Rust callers via an internal
/// mutex. It does **not** protect against C++ code mutating
/// `nix::logger` directly. Like [`crate::settings::set`], prefer to
/// install a logger during single-threaded initialization.
#[doc(alias = "nix_set_logger")]
pub fn set_logger<L: Logger + 'static>(logger: L) -> Result<()> {
let _guard = SET_LOGGER_MUTEX.lock().unwrap();
let boxed: Box<LoggerObj> = Box::new(Box::new(logger));
let userdata = Box::into_raw(boxed) as *mut c_void;
let mut ctx = context::Context::new();
let res = unsafe { check_call!(raw::set_logger(&mut ctx, &VTABLE, userdata)) };
if let Err(e) = res {
// The C side did not accept the logger, so it will not invoke
// the destroy callback. Reclaim the box ourselves to avoid
// leaking the user-supplied logger.
unsafe {
drop(Box::from_raw(userdata as *mut LoggerObj));
}
return Err(e);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
#[ctor::ctor]
fn setup() {
crate::init().unwrap();
}
/// Logger that records when it's dropped, so tests can observe the
/// destroy callback firing on replacement.
struct DropFlag {
dropped: Arc<AtomicBool>,
log_count: Arc<AtomicUsize>,
}
impl Logger for DropFlag {
fn log(&self, _level: Verbosity, _msg: &str) {
self.log_count.fetch_add(1, Ordering::SeqCst);
}
}
impl Drop for DropFlag {
fn drop(&mut self) {
self.dropped.store(true, Ordering::SeqCst);
}
}
#[test]
fn set_and_replace_calls_destroy() {
let dropped = Arc::new(AtomicBool::new(false));
let log_count = Arc::new(AtomicUsize::new(0));
set_logger(DropFlag {
dropped: dropped.clone(),
log_count: log_count.clone(),
})
.unwrap();
assert!(!dropped.load(Ordering::SeqCst));
// Replace with a fresh logger; this should drop the previous one.
set_logger(DropFlag {
dropped: Arc::new(AtomicBool::new(false)),
log_count: Arc::new(AtomicUsize::new(0)),
})
.unwrap();
assert!(
dropped.load(Ordering::SeqCst),
"previous logger should be dropped when the logger is replaced"
);
}
#[test]
fn verbosity_round_trips_known_values() {
assert_eq!(
Verbosity::from_raw(raw::verbosity_NIX_LVL_ERROR),
Verbosity::Error
);
assert_eq!(
Verbosity::from_raw(raw::verbosity_NIX_LVL_VOMIT),
Verbosity::Vomit
);
}
}