feat(imaging): default to pure-Rust codecs
This commit is contained in:
54
README.md
54
README.md
@@ -49,20 +49,22 @@ python3 tools/check_test_parity.py
|
||||
python3 tools/audit_red_suite.py
|
||||
```
|
||||
|
||||
### Optional codec features
|
||||
### Image codec features
|
||||
|
||||
The default build needs no system image-codec library. It includes the
|
||||
project-owned TGA and DDS implementations; the default `dds-bc67` feature uses
|
||||
the pure-Rust `bcdec_rs` dependency for BC6H and BC7. Build without BC6H/BC7
|
||||
support with `cargo build -p libremetaverse --no-default-features`.
|
||||
project-owned TGA and DDS implementations, pure-Rust J2K/JP2 through
|
||||
`rust-j2k`, and pure-Rust common-raster decoding through the default
|
||||
`libremetaverse-imaging-skia` `rust-skia` feature. The default `dds-bc67`
|
||||
feature uses the pure-Rust `bcdec_rs` dependency for BC6H and BC7. Use
|
||||
`--no-default-features` only for a deliberately minimal codec-free build.
|
||||
|
||||
The currently available opt-in codec backends are:
|
||||
The available default and optional codec backends are:
|
||||
|
||||
| Capability | Feature | Build command | External prerequisite |
|
||||
| --- | --- | --- | --- |
|
||||
| Raw J2K and JP2 decoding/encoding through OpenJPEG | `libremetaverse/jpeg2000` | `cargo build -p libremetaverse --features jpeg2000` | OpenJPEG 2.5.4 or newer |
|
||||
| Raw J2K and JP2 decoding/encoding in pure Rust | `libremetaverse/rust-j2k` | `cargo build -p libremetaverse --no-default-features --features rust-j2k` | none |
|
||||
| BMP, GIF, ICO, JPEG, PNG, WBMP, and WebP decoding in pure Rust | `libremetaverse-imaging-skia/rust-skia` | `cargo build -p libremetaverse-imaging-skia --features rust-skia` | None |
|
||||
| Raw J2K and JP2 decoding/encoding in pure Rust (default) | `libremetaverse/rust-j2k` | `cargo build -p libremetaverse` | none |
|
||||
| BMP, GIF, ICO, JPEG, PNG, WBMP, and WebP decoding in pure Rust (default) | `libremetaverse-imaging-skia/rust-skia` | `cargo build -p libremetaverse-imaging-skia` | none |
|
||||
| Raw J2K and JP2 decoding/encoding through OpenJPEG (optional) | `libremetaverse/jpeg2000` | `cargo build -p libremetaverse --features jpeg2000` | OpenJPEG 2.5.4 or newer |
|
||||
| BMP, GIF, ICO, JPEG, PNG, WBMP, and WebP decoding through native Skia | `libremetaverse-imaging-skia/skia` | `cargo build -p libremetaverse-imaging-skia --features skia` | A matching rust-skia binary cache, or the documented native source-build tools |
|
||||
| PCM to Ogg Vorbis encoding | `libremetaverse/vorbis` | `cargo build -p libremetaverse --features vorbis` | `vorbis_rs` 0.5.6 and its native encoder build prerequisites |
|
||||
|
||||
@@ -70,9 +72,9 @@ Run their focused test suites with:
|
||||
|
||||
```sh
|
||||
cargo test -p libremetaverse-imaging --features jpeg2000
|
||||
cargo test -p libremetaverse-imaging --no-default-features --features rust-j2k
|
||||
cargo test -p libremetaverse-imaging
|
||||
cargo test -p libremetaverse-imaging-skia --features skia
|
||||
cargo test -p libremetaverse-imaging-skia --features rust-skia
|
||||
cargo test -p libremetaverse-imaging-skia
|
||||
cargo test -p libremetaverse --no-default-features --features vorbis
|
||||
```
|
||||
|
||||
@@ -95,10 +97,11 @@ Deterministic task, socket, file, subscription, cancellation, and allocation
|
||||
baselines are documented in the
|
||||
[concurrency hardening guide](docs/concurrency-hardening.md).
|
||||
|
||||
The independent `rust-j2k` backend is off by default and never enables the
|
||||
native OpenJPEG adapter. Its explicit `RustJ2kCodec` preserves the existing
|
||||
`J2kCodec` meaning when both features are enabled. Use the combined feature set
|
||||
to run backend-interoperability tests without changing application selection.
|
||||
The default `rust-j2k` backend never enables the native OpenJPEG adapter. Its
|
||||
explicit `RustJ2kCodec` preserves the existing `J2kCodec` meaning when both
|
||||
features are enabled. Likewise, default `RustSkiaTextureCodec` selection does
|
||||
not rename or enable native `SkiaTextureCodec`. The native features remain
|
||||
available for backend-interoperability testing or explicit application use.
|
||||
|
||||
`tests/upstream-tests.json` is the machine-readable NUnit parity catalog.
|
||||
Translated tests live in hand-written Rust files with the `parity-case` marker
|
||||
@@ -208,8 +211,14 @@ Legacy and DX10 BC1 through BC5 decoding is built in. The default `dds-bc67`
|
||||
feature adds BC6H/BC7 decoding through the safe, pure-Rust `bcdec_rs` crate;
|
||||
disabling default features removes that optional dependency and makes those
|
||||
two formats return a typed unsupported-format error.
|
||||
JPEG 2000 is available through the opt-in `jpeg2000` feature. It provides raw
|
||||
J2K and JP2 lossless/lossy encoding and decoding, preserves one through five
|
||||
The default `rust-j2k` feature provides raw J2K and JP2 lossless/lossy encoding
|
||||
and decoding through `RustJ2kCodec`, backed by the exact pure-Rust `j2k` 0.8.1
|
||||
release. It supports native component precision/signedness/order,
|
||||
reduced-resolution and progressive quality-layer decoding, and strict or
|
||||
explicitly permissive truncation handling. It has no C/C++ codec, CMake,
|
||||
pkg-config, vcpkg, CLR, or platform-specific API.
|
||||
The optional `jpeg2000` feature provides the native OpenJPEG alternative. It
|
||||
provides raw J2K and JP2 lossless/lossy encoding and decoding, preserves one through five
|
||||
component order, precision, signedness, and alpha metadata until explicit byte
|
||||
conversion, and bounds encoded input, output, dimensions, and decoded samples.
|
||||
The compatibility encoder reproduces CoreJ2K's four-plane RGB/alpha view,
|
||||
@@ -217,20 +226,15 @@ including its alpha-only and opaque-alpha substitutions. See
|
||||
[`crates/libremetaverse-openjpeg/README.md`](crates/libremetaverse-openjpeg/README.md)
|
||||
for OpenJPEG prerequisites, licensing, and deployment details. Default builds
|
||||
do not discover or link OpenJPEG.
|
||||
The independent opt-in `rust-j2k` feature provides the same bounded public
|
||||
options through `RustJ2kCodec`, backed by the exact pure-Rust `j2k` 0.8.1
|
||||
release. It supports J2K and JP2, reversible and irreversible encoding,
|
||||
native component precision/signedness/order, reduced-resolution and progressive
|
||||
quality-layer decoding, and strict or explicitly permissive truncation handling.
|
||||
It has no C/C++ codec, CMake, pkg-config, vcpkg, CLR, or platform-specific API.
|
||||
The optional Skia adapter decodes BMP, GIF, ICO, JPEG, PNG, WBMP, and WebP into
|
||||
the same checked planar representation. Its `skia` feature uses pinned
|
||||
The default pure-Rust raster adapter decodes BMP, GIF, ICO, JPEG, PNG, WBMP,
|
||||
and WebP into the same checked planar representation through
|
||||
`RustSkiaTextureCodec`. Its optional native `skia` feature uses pinned
|
||||
rust-skia binary-cache configurations on macOS, Linux, and Windows, normalizes
|
||||
premultiplied color at the imaging boundary, and keeps encoded input, decoded
|
||||
dimensions, strides, and allocations bounded. See
|
||||
[`crates/libremetaverse-imaging-skia/README.md`](crates/libremetaverse-imaging-skia/README.md)
|
||||
for native prerequisites, cache/source-build controls, licenses, and packaging
|
||||
details. Default workspace builds do not compile or link Skia.
|
||||
details. Default workspace builds compile neither OpenJPEG nor native Skia.
|
||||
Primitive profile and path meshing is implemented in native Rust from the
|
||||
pinned `PrimMesher.cs` reference. It covers checked linear, flexible, and
|
||||
circular extrusion; profile cuts and hollows; twist, taper, shear, skew,
|
||||
|
||||
@@ -46,7 +46,7 @@ The exact mapping, exported-marker, feature, and normalized Rust declaration has
|
||||
- .NET events become `subscribe_*` calls returning an owned `Subscription`; callbacks are `Send + Sync` and dispatch outside internal locks.
|
||||
- `IDisposable` becomes explicit idempotent shutdown plus `Drop`; cancellation remains a typed `Error::Cancelled`.
|
||||
- Closed C# enums retain fixed discriminants and are SemVer-breaking to extend; flags retain unknown bits, while public Rust error enums are `non_exhaustive`.
|
||||
- Optional native and pure-Rust backends remain feature-gated (`jpeg2000`, `rust-j2k`, `skia`, `rust-skia`, `vorbis`, `real-audio`); default and empty-default sets are part of the baseline.
|
||||
- Pure-Rust image backends are enabled by default (`rust-j2k`, `rust-skia`); native alternatives remain feature-gated (`jpeg2000`, `skia`, `vorbis`, `real-audio`), and empty-default sets remain part of the baseline.
|
||||
- Capability HTTP injection uses project-owned `HttpMessageHandler`, `CapsHttpLimits`, and `with_native_transport`; the internal `reqwest` client is not part of the public surface.
|
||||
- External C# signature types map to core/std, adopted cross-platform crates, or project-owned boundary types; no third-party crate path leaks through mapped signatures or public Rust declarations.
|
||||
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
"dep:bcdec_rs"
|
||||
],
|
||||
"default": [
|
||||
"dds-bc67"
|
||||
"dds-bc67",
|
||||
"rust-j2k"
|
||||
],
|
||||
"jpeg2000": [
|
||||
"libremetaverse-imaging/jpeg2000"
|
||||
@@ -69,7 +70,9 @@
|
||||
"name": "libremetaverse-imaging",
|
||||
"version": "0.0.1",
|
||||
"features": {
|
||||
"default": [],
|
||||
"default": [
|
||||
"rust-j2k"
|
||||
],
|
||||
"jpeg2000": [
|
||||
"dep:libremetaverse-openjpeg"
|
||||
],
|
||||
@@ -86,7 +89,9 @@
|
||||
"name": "libremetaverse-imaging-skia",
|
||||
"version": "0.0.1",
|
||||
"features": {
|
||||
"default": [],
|
||||
"default": [
|
||||
"rust-skia"
|
||||
],
|
||||
"rust-skia": [
|
||||
"dep:image-webp",
|
||||
"dep:skia-rs-codec",
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
{ "name": "getrandom", "versions": ["0.4.3"], "purpose": "Operating-system entropy for protocol identifiers", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`getrandom`" },
|
||||
{ "name": "goblin", "versions": ["0.10.5"], "purpose": "Cross-platform ELF, PE, and Mach-O release artifact inspection", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`goblin`" },
|
||||
{ "name": "hound", "versions": ["3.5.1"], "purpose": "Bounded PCM WAV parsing for WebRTC playback", "maintenance": "stable", "transitive_cost": "low", "native": false, "rewrite_anchor": "`hound`" },
|
||||
{ "name": "image-webp", "versions": ["0.2.4"], "purpose": "Opt-in pure-Rust bounded WebP image decoding", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`image-webp`" },
|
||||
{ "name": "j2k", "versions": ["0.8.1"], "purpose": "Opt-in pure-Rust bounded JPEG 2000 and JP2 encoding and decoding", "maintenance": "active", "transitive_cost": "medium", "native": false, "rewrite_anchor": "`j2k`" },
|
||||
{ "name": "image-webp", "versions": ["0.2.4"], "purpose": "Default pure-Rust bounded WebP image decoding", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`image-webp`" },
|
||||
{ "name": "j2k", "versions": ["0.8.1"], "purpose": "Default pure-Rust bounded JPEG 2000 and JP2 encoding and decoding", "maintenance": "active", "transitive_cost": "medium", "native": false, "rewrite_anchor": "`j2k`" },
|
||||
{ "name": "mac_address2", "versions": ["2.0.2"], "purpose": "Cross-platform machine identity compatibility input", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`mac_address2`" },
|
||||
{ "name": "md-5", "versions": ["0.10.6"], "purpose": "Legacy protocol checksum compatibility", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`md-5`" },
|
||||
{ "name": "os_info", "versions": ["3.15.0"], "purpose": "Cross-platform login platform reporting", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`os_info`" },
|
||||
@@ -30,7 +30,7 @@
|
||||
{ "name": "sha1", "versions": ["0.10.7"], "purpose": "Legacy protocol hash compatibility", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`sha1`" },
|
||||
{ "name": "sha2", "versions": ["0.11.0"], "purpose": "Manifest integrity and protocol hashing", "maintenance": "active", "transitive_cost": "low", "native": false, "rewrite_anchor": "`sha2`" },
|
||||
{ "name": "skia-safe", "versions": ["0.99.0"], "purpose": "Opt-in cross-platform Skia image decoding", "maintenance": "monitored-native", "transitive_cost": "high", "native": true, "rewrite_anchor": "`skia-safe`" },
|
||||
{ "name": "skia-rs-codec", "versions": ["0.3.0"], "purpose": "Opt-in pure-Rust BMP, GIF, ICO, JPEG, PNG, and WBMP image decoding", "maintenance": "active", "transitive_cost": "high", "native": false, "rewrite_anchor": "`skia-rs-codec`" },
|
||||
{ "name": "skia-rs-codec", "versions": ["0.3.0"], "purpose": "Default pure-Rust BMP, GIF, ICO, JPEG, PNG, and WBMP image decoding", "maintenance": "active", "transitive_cost": "high", "native": false, "rewrite_anchor": "`skia-rs-codec`" },
|
||||
{ "name": "stats_alloc", "versions": ["0.1.10"], "purpose": "Allocation-budget compatibility tests, concurrency leak audits, and reproducible performance evidence", "maintenance": "stable", "transitive_cost": "low", "native": false, "rewrite_anchor": "`stats_alloc`" },
|
||||
{ "name": "str0m", "versions": ["0.22.0"], "purpose": "Native Rust ICE, DTLS, SRTP, RTP, and SCTP WebRTC transport", "maintenance": "active", "transitive_cost": "high", "native": false, "rewrite_anchor": "`str0m`" },
|
||||
{ "name": "syn", "versions": ["2.0.119"], "purpose": "Syntax validation for generated Rust sources", "maintenance": "active", "transitive_cost": "medium", "native": false, "rewrite_anchor": "`syn`" },
|
||||
|
||||
@@ -8,12 +8,12 @@ repository.workspace = true
|
||||
description = "Optional Skia image decoder for the MetaCrate LibreMetaverse rewrite"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
default = ["rust-skia"]
|
||||
skia = ["dep:skia-safe"]
|
||||
rust-skia = ["dep:image-webp", "dep:skia-rs-codec", "skia-rs-codec/gif", "skia-rs-codec/jpeg", "skia-rs-codec/png"]
|
||||
|
||||
[dependencies]
|
||||
libremetaverse-imaging = { version = "0.0.1", path = "../libremetaverse-imaging" }
|
||||
libremetaverse-imaging = { version = "0.0.1", path = "../libremetaverse-imaging", default-features = false }
|
||||
libremetaverse-types = { version = "0.0.1", path = "../libremetaverse-types" }
|
||||
image-webp = { version = "=0.2.4", optional = true }
|
||||
skia-rs-codec = { version = "=0.3.0", default-features = false, optional = true }
|
||||
|
||||
@@ -6,7 +6,8 @@ exposes a `skia-safe` type and never discovers or links Skia.
|
||||
|
||||
## Features and formats
|
||||
|
||||
The default feature set has no Skia dependency. `SkiaTextureCodec::decode` and
|
||||
The default feature set enables the pure-Rust `rust-skia` backend and has no
|
||||
native Google Skia dependency. `SkiaTextureCodec::decode` and
|
||||
`RustSkiaTextureCodec::decode` return a typed `InvalidOperation` error when
|
||||
their respective feature is disabled, while conversion from the checked
|
||||
project-owned `backend::SKBitmap` remains available for tests and callers that
|
||||
@@ -15,7 +16,7 @@ already own decoded pixels.
|
||||
For a fully Rust implementation, enable:
|
||||
|
||||
```sh
|
||||
cargo test -p libremetaverse-imaging-skia --no-default-features --features rust-skia
|
||||
cargo test -p libremetaverse-imaging-skia
|
||||
```
|
||||
|
||||
`rust-skia` pins [`skia-rs-codec` 0.3.0](https://github.com/rust-skia/skia-rs)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//! Optional Skia imaging adapter corresponding to `LibreMetaverse.Imaging.Skia`.
|
||||
//!
|
||||
//! Enable `skia` or the fully native-Rust `rust-skia` alternative for bounded
|
||||
//! `BMP`, `GIF`, `ICO`, `JPEG`, `PNG`, `WBMP`, and `WebP` decoding.
|
||||
//! The default build remains inert. See the crate README for native cache,
|
||||
//! source-build, licensing, and cross-platform prerequisite details.
|
||||
//! The default `rust-skia` backend provides bounded pure-Rust `BMP`, `GIF`,
|
||||
//! `ICO`, `JPEG`, `PNG`, `WBMP`, and `WebP` decoding. Enable the optional
|
||||
//! `skia` feature when native Google Skia is specifically required. See the
|
||||
//! crate README for native cache, source-build, licensing, and deployment details.
|
||||
|
||||
extern crate self as libremetaverse_imaging_skia;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ repository.workspace = true
|
||||
description = "Texture codec abstractions for the MetaCrate LibreMetaverse rewrite"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
default = ["rust-j2k"]
|
||||
jpeg2000 = ["dep:libremetaverse-openjpeg"]
|
||||
rust-j2k = ["dep:j2k"]
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//! Image and texture abstractions corresponding to `LibreMetaverse.Imaging`.
|
||||
//!
|
||||
//! The default surface provides managed images plus native `TGA`/`DDS` handling.
|
||||
//! Enable `jpeg2000` for the audited system `OpenJPEG` adapter or `rust-j2k`
|
||||
//! for the independently selectable pure-Rust JPEG 2000 backend. Ordinary
|
||||
//! users can consume the traits without either codec dependency.
|
||||
//! The default surface provides managed images, native `TGA`/`DDS` handling,
|
||||
//! and the pure-Rust `rust-j2k` JPEG 2000 backend. Enable `jpeg2000` for the
|
||||
//! optional audited system `OpenJPEG` adapter. Consumers that only need the
|
||||
//! format-neutral image types can disable default features.
|
||||
|
||||
extern crate self as libremetaverse_imaging;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ repository.workspace = true
|
||||
description = "Primitive meshing shims for the MetaCrate LibreMetaverse rewrite"
|
||||
|
||||
[dependencies]
|
||||
libremetaverse-imaging = { version = "0.0.1", path = "../libremetaverse-imaging" }
|
||||
libremetaverse-imaging = { version = "0.0.1", path = "../libremetaverse-imaging", default-features = false }
|
||||
libremetaverse-types = { version = "0.0.1", path = "../libremetaverse-types" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -8,7 +8,7 @@ repository.workspace = true
|
||||
description = "Rust rewrite shell for the LibreMetaverse client library"
|
||||
|
||||
[features]
|
||||
default = ["dds-bc67"]
|
||||
default = ["dds-bc67", "rust-j2k"]
|
||||
dds-bc67 = ["dep:bcdec_rs"]
|
||||
jpeg2000 = ["libremetaverse-imaging/jpeg2000"]
|
||||
rust-j2k = ["libremetaverse-imaging/rust-j2k"]
|
||||
@@ -20,7 +20,7 @@ bcdec_rs = { version = "0.2.0", optional = true }
|
||||
flate2 = "1.1.2"
|
||||
futures-channel = "0.3.31"
|
||||
futures-util = "0.3.31"
|
||||
libremetaverse-imaging = { version = "0.0.1", path = "../libremetaverse-imaging" }
|
||||
libremetaverse-imaging = { version = "0.0.1", path = "../libremetaverse-imaging", default-features = false }
|
||||
libremetaverse-prim-mesher = { version = "0.0.1", path = "../libremetaverse-prim-mesher" }
|
||||
libremetaverse-structured-data = { version = "0.0.1", path = "../libremetaverse-structured-data" }
|
||||
libremetaverse-types = { version = "0.0.1", path = "../libremetaverse-types" }
|
||||
|
||||
@@ -15,11 +15,11 @@ they use those APIs directly.
|
||||
|
||||
| Crate | Choose it for | Features or system boundary |
|
||||
| --- | --- | --- |
|
||||
| `libremetaverse` | Grid client, login, network, agents, inventory, assets, appearance, world, and social APIs | Default pure-Rust BC6H/BC7; optional `jpeg2000`, `rust-j2k`, and `vorbis` |
|
||||
| `libremetaverse` | Grid client, login, network, agents, inventory, assets, appearance, world, and social APIs | Default pure-Rust BC6H/BC7 and J2K/JP2; optional native `jpeg2000` and `vorbis` |
|
||||
| `libremetaverse-types` | UUIDs, vectors, matrices, colors, cancellation, compatibility collections, and boundary types | Pure Rust |
|
||||
| `libremetaverse-structured-data` | LLSD/OSD XML, JSON, binary, and notation | Pure Rust |
|
||||
| `libremetaverse-imaging` | Managed images, TGA/DDS, codec traits | Optional `jpeg2000` or pure-Rust `rust-j2k` |
|
||||
| `libremetaverse-imaging-skia` | Common raster formats through native Skia or pure Rust | Optional `skia` native build/cache; optional `rust-skia` has no native prerequisites |
|
||||
| `libremetaverse-imaging` | Managed images, TGA/DDS, codec traits | Default pure-Rust `rust-j2k`; optional native `jpeg2000` |
|
||||
| `libremetaverse-imaging-skia` | Common raster formats through native Skia or pure Rust | Default pure-Rust `rust-skia`; optional `skia` native build/cache |
|
||||
| `libremetaverse-prim-mesher` | Legacy prim and sculpt geometry | Pure Rust |
|
||||
| `libremetaverse-rendering-simple` | Deterministic reference geometry | Pure Rust |
|
||||
| `libremetaverse-rendering-mesh-foundry` | Prim, terrain, sculpt, and mesh-asset rendering | Pure Rust |
|
||||
@@ -31,8 +31,8 @@ they use those APIs directly.
|
||||
| `libremetaverse-openjpeg` | Audited `OpenJPEG` adapter | System `OpenJPEG` 2.5.4 or newer |
|
||||
| `libremetaverse-opus` | Audited Opus encoder/decoder adapter | System libopus |
|
||||
|
||||
Features are additive. Keep defaults unless you need a codec, and enable one
|
||||
native adapter at a time while diagnosing installation problems. The
|
||||
Features are additive. Keep the pure-Rust defaults for normal applications,
|
||||
and enable a native adapter only when it is specifically needed. The
|
||||
[release CI matrix](https://git.rfc1437.de/hugo/MetaCrate/src/branch/main/docs/release-ci-matrix.md) records every validated combination.
|
||||
|
||||
## Naming and overload migration
|
||||
@@ -190,7 +190,7 @@ The default client build needs no image-codec system library. Optional native
|
||||
features require:
|
||||
|
||||
- `OpenJPEG` 2.5.4 or newer for `jpeg2000`;
|
||||
- no native prerequisite for the pure-Rust `rust-j2k` feature;
|
||||
- no native prerequisite for the default pure-Rust `rust-j2k` and `rust-skia` features;
|
||||
- the rust-skia prerequisites/cache for `skia`;
|
||||
- system libopus for WebRTC voice and the `libremetaverse-opus` adapter;
|
||||
- ALSA development headers on Linux, `CoreAudio` on macOS, or WASAPI on Windows
|
||||
|
||||
@@ -6,11 +6,11 @@ and mutable raw payload. Concrete animation, sound, script, calling-card,
|
||||
landmark, settings, mesh, texture, wearable, and notecard models enforce a 64 MiB
|
||||
input ceiling and reject malformed structured formats with typed errors. Mesh and
|
||||
settings parsing use StructuredData. Texture encode/decode uses the imaging
|
||||
crate's bounded `jpeg2000` adapter, while the opt-in `vorbis` feature streams
|
||||
PCM conversion through bounded planar Ogg Vorbis blocks; neither API exposes
|
||||
codec implementation types. With either native codec feature disabled, its
|
||||
public API remains present and returns a typed `InvalidOperation` for otherwise
|
||||
valid input instead of discovering or linking a system codec implicitly.
|
||||
crate's default bounded pure-Rust JPEG 2000 adapter, while the opt-in `vorbis`
|
||||
feature streams PCM conversion through bounded planar Ogg Vorbis blocks;
|
||||
neither API exposes codec implementation types. The optional native OpenJPEG
|
||||
path is selected only by its explicit feature and never discovered or linked
|
||||
by a default build.
|
||||
|
||||
`AssetManager` is client-owned and shares one `DownloadManager` and `AssetCache`.
|
||||
ViewerAsset, GetMesh, GetTexture, and server-bake requests check the cache before
|
||||
|
||||
@@ -49,7 +49,8 @@ All native boundaries have Linux, Windows, and macOS strategies:
|
||||
|---|---|---|---|
|
||||
| libopus 1.3+ | `pkg-config` package `opus` | vcpkg `opus` for MSVC; `pkg-config` for GNU | WebRTC voice crate |
|
||||
| OpenJPEG 2.5.4+ | `pkg-config` package `libopenjp2` | vcpkg `openjpeg` for MSVC; `pkg-config` for GNU | opt-in `jpeg2000` |
|
||||
| j2k 0.8.1 | pure Rust, no platform prerequisite | same pure-Rust graph | opt-in `rust-j2k` |
|
||||
| j2k 0.8.1 | pure Rust, no platform prerequisite | same pure-Rust graph | default `rust-j2k` |
|
||||
| skia-rs-codec 0.3.0 and image-webp 0.2.4 | pure Rust, no platform prerequisite | same pure-Rust graph | default `rust-skia` |
|
||||
| Skia 0.99.0 | target-specific official binary cache or source build | same target-specific strategy | opt-in `skia` |
|
||||
| Vorbis 0.5.6 stack | `vorbis_rs` builds its reviewed C codec stack | same crate strategy | opt-in `vorbis` |
|
||||
| Physical audio | ALSA development files on Linux; CoreAudio is system-provided on macOS | WASAPI is system-provided | opt-in `real-audio` |
|
||||
|
||||
@@ -17,18 +17,19 @@ and [`MeshFoundry` guide](../crates/libremetaverse-rendering-mesh-foundry/README
|
||||
| --- | --- | --- | --- |
|
||||
| Managed images and TGA | enabled | n/a | none |
|
||||
| JPEG 2000 | disabled | `libremetaverse-imaging/jpeg2000` | OpenJPEG 2.5.x |
|
||||
| JPEG 2000 (pure Rust) | disabled | `libremetaverse-imaging/rust-j2k` | none (`j2k` 0.8.1) |
|
||||
| BMP/GIF/ICO/JPEG/PNG/WBMP/WebP (pure Rust) | disabled | `libremetaverse-imaging-skia/rust-skia` | none (`skia-rs-codec` 0.3.0 plus `image-webp` 0.2.4) |
|
||||
| JPEG 2000 (pure Rust) | enabled | `libremetaverse-imaging/rust-j2k` | none (`j2k` 0.8.1) |
|
||||
| BMP/GIF/ICO/JPEG/PNG/WBMP/WebP (pure Rust) | enabled | `libremetaverse-imaging-skia/rust-skia` | none (`skia-rs-codec` 0.3.0 plus `image-webp` 0.2.4) |
|
||||
| BMP/GIF/ICO/JPEG/PNG/WBMP/WebP (native) | disabled | `libremetaverse-imaging-skia/skia` | Skia |
|
||||
| Prim and sculpt meshing, OBJ ingestion | enabled | n/a | none |
|
||||
|
||||
OpenJPEG is a non-default workspace member so release tooling can package the
|
||||
adapter explicitly, and imaging reaches it only through the optional
|
||||
dependency. The independent `rust-j2k` feature reaches only the audited
|
||||
pure-Rust `j2k` graph; enabling both features keeps both explicit codec types
|
||||
available for interoperability testing. Skia is likewise an optional,
|
||||
target-specific dependency. The consolidated required Gitea gate exercises the
|
||||
native feature, while a dedicated `ubuntu-latest` job tests `rust-skia`, audits
|
||||
dependency. The default `rust-j2k` feature reaches only the audited pure-Rust
|
||||
`j2k` graph; enabling both features keeps both explicit codec types available
|
||||
for interoperability testing. Native Skia is likewise an optional,
|
||||
target-specific dependency, while `rust-skia` is the raster crate default. The
|
||||
consolidated required Gitea gate exercises the native feature, while a dedicated
|
||||
`ubuntu-latest` job tests `rust-skia`, audits
|
||||
its normal/build graph without installing native codec tools, and compiles the
|
||||
same code for WASM. Minimal-feature checks still prove no codec is needed for
|
||||
the owned Rust and translated compatibility tests.
|
||||
|
||||
@@ -17,14 +17,14 @@ is evidence of remaining work, never permission to waive it.
|
||||
|
||||
## Features and prerequisites
|
||||
|
||||
The default `libremetaverse` build uses the pure-Rust `dds-bc67` image path.
|
||||
Optional boundaries are explicit:
|
||||
The default MetaCrate build uses the pure-Rust `dds-bc67`, `rust-j2k`, and
|
||||
`rust-skia` image paths. Native alternatives remain explicit opt-ins:
|
||||
|
||||
| Feature | Capability | Native/build prerequisite |
|
||||
| --- | --- | --- |
|
||||
| `jpeg2000` | J2K/JP2 through the safe OpenJPEG adapter | OpenJPEG 2.5.4 or newer |
|
||||
| `rust-j2k` | J2K/JP2 through `RustJ2kCodec` | none; exact pure-Rust `j2k` 0.8.1 |
|
||||
| `rust-skia` | BMP/GIF/ICO/JPEG/PNG/WBMP/WebP through `RustSkiaTextureCodec` | none; exact pure-Rust `skia-rs-codec` 0.3.0 and `image-webp` 0.2.4 |
|
||||
| `rust-j2k` (default) | J2K/JP2 through `RustJ2kCodec` | none; exact pure-Rust `j2k` 0.8.1 |
|
||||
| `rust-skia` (default) | BMP/GIF/ICO/JPEG/PNG/WBMP/WebP through `RustSkiaTextureCodec` | none; exact pure-Rust `skia-rs-codec` 0.3.0 and `image-webp` 0.2.4 |
|
||||
| `skia` | PNG/JPEG/WebP and other Skia formats | Skia 0.99 target cache or documented source tools |
|
||||
| `vorbis` | PCM to Ogg Vorbis | the locked `vorbis_rs` native build stack |
|
||||
| default WebRTC | native ICE/DTLS/SRTP/RTP/SCTP and Opus | system libopus 1.3 or newer |
|
||||
|
||||
@@ -15,11 +15,11 @@ they use those APIs directly.
|
||||
|
||||
| Crate | Choose it for | Features or system boundary |
|
||||
| --- | --- | --- |
|
||||
| `libremetaverse` | Grid client, login, network, agents, inventory, assets, appearance, world, and social APIs | Default pure-Rust BC6H/BC7; optional `jpeg2000`, `rust-j2k`, and `vorbis` |
|
||||
| `libremetaverse` | Grid client, login, network, agents, inventory, assets, appearance, world, and social APIs | Default pure-Rust BC6H/BC7 and J2K/JP2; optional native `jpeg2000` and `vorbis` |
|
||||
| `libremetaverse-types` | UUIDs, vectors, matrices, colors, cancellation, compatibility collections, and boundary types | Pure Rust |
|
||||
| `libremetaverse-structured-data` | LLSD/OSD XML, JSON, binary, and notation | Pure Rust |
|
||||
| `libremetaverse-imaging` | Managed images, TGA/DDS, codec traits | Optional `jpeg2000` or pure-Rust `rust-j2k` |
|
||||
| `libremetaverse-imaging-skia` | Common raster formats through native Skia or pure Rust | Optional `skia` native build/cache; optional `rust-skia` has no native prerequisites |
|
||||
| `libremetaverse-imaging` | Managed images, TGA/DDS, codec traits | Default pure-Rust `rust-j2k`; optional native `jpeg2000` |
|
||||
| `libremetaverse-imaging-skia` | Common raster formats through native Skia or pure Rust | Default pure-Rust `rust-skia`; optional `skia` native build/cache |
|
||||
| `libremetaverse-prim-mesher` | Legacy prim and sculpt geometry | Pure Rust |
|
||||
| `libremetaverse-rendering-simple` | Deterministic reference geometry | Pure Rust |
|
||||
| `libremetaverse-rendering-mesh-foundry` | Prim, terrain, sculpt, and mesh-asset rendering | Pure Rust |
|
||||
@@ -31,8 +31,8 @@ they use those APIs directly.
|
||||
| `libremetaverse-openjpeg` | Audited `OpenJPEG` adapter | System `OpenJPEG` 2.5.4 or newer |
|
||||
| `libremetaverse-opus` | Audited Opus encoder/decoder adapter | System libopus |
|
||||
|
||||
Features are additive. Keep defaults unless you need a codec, and enable one
|
||||
native adapter at a time while diagnosing installation problems. The
|
||||
Features are additive. Keep the pure-Rust defaults for normal applications,
|
||||
and enable a native adapter only when it is specifically needed. The
|
||||
[release CI matrix](release-ci-matrix.md) records every validated combination.
|
||||
|
||||
## Naming and overload migration
|
||||
@@ -190,7 +190,7 @@ The default client build needs no image-codec system library. Optional native
|
||||
features require:
|
||||
|
||||
- `OpenJPEG` 2.5.4 or newer for `jpeg2000`;
|
||||
- no native prerequisite for the pure-Rust `rust-j2k` feature;
|
||||
- no native prerequisite for the default pure-Rust `rust-j2k` and `rust-skia` features;
|
||||
- the rust-skia prerequisites/cache for `skia`;
|
||||
- system libopus for WebRTC voice and the `libremetaverse-opus` adapter;
|
||||
- ALSA development headers on Linux, `CoreAudio` on macOS, or WASAPI on Windows
|
||||
|
||||
@@ -10,9 +10,9 @@ publish = false
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5", features = ["derive"] }
|
||||
libremetaverse = { version = "0.0.1", path = "../crates/libremetaverse", default-features = false }
|
||||
libremetaverse-imaging = { version = "0.0.1", path = "../crates/libremetaverse-imaging", features = ["jpeg2000"] }
|
||||
libremetaverse-imaging-skia = { version = "0.0.1", path = "../crates/libremetaverse-imaging-skia", features = ["skia"] }
|
||||
libremetaverse = { version = "0.0.1", path = "../crates/libremetaverse" }
|
||||
libremetaverse-imaging = { version = "0.0.1", path = "../crates/libremetaverse-imaging" }
|
||||
libremetaverse-imaging-skia = { version = "0.0.1", path = "../crates/libremetaverse-imaging-skia" }
|
||||
libremetaverse-structured-data = { version = "0.0.1", path = "../crates/libremetaverse-structured-data" }
|
||||
libremetaverse-voice-vivox = { version = "0.0.1", path = "../crates/libremetaverse-voice-vivox" }
|
||||
libremetaverse-voice-webrtc = { version = "0.0.1", path = "../crates/libremetaverse-voice-webrtc" }
|
||||
|
||||
@@ -14,10 +14,10 @@ use libremetaverse::types::compat::CancellationToken;
|
||||
use libremetaverse::types::{AssetType, FolderType, InventoryType, UUID};
|
||||
use libremetaverse::{PermissionMask, Permissions};
|
||||
use libremetaverse_imaging::{
|
||||
J2kCodec, J2kCompression, J2kDecodeOptions, J2kEncodeOptions, ManagedImage,
|
||||
ManagedImageImageChannels,
|
||||
J2kCompression, J2kDecodeOptions, J2kEncodeOptions, ManagedImage, ManagedImageImageChannels,
|
||||
RustJ2kCodec,
|
||||
};
|
||||
use libremetaverse_imaging_skia::SkiaTextureCodec;
|
||||
use libremetaverse_imaging_skia::RustSkiaTextureCodec;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs::{self, File};
|
||||
use std::io::{Cursor, Read, Write};
|
||||
@@ -1465,14 +1465,14 @@ fn image_to_j2k(path: &Path) -> Result<Vec<u8>, String> {
|
||||
.unwrap_or("")
|
||||
.to_ascii_lowercase();
|
||||
if matches!(extension.as_str(), "jp2" | "j2c" | "j2k") {
|
||||
J2kCodec::decode_bytes(&bytes, J2kDecodeOptions::default())
|
||||
RustJ2kCodec::decode_bytes(&bytes, J2kDecodeOptions::default())
|
||||
.map_err(|_| "Invalid JPEG 2000 image".to_owned())?;
|
||||
return Ok(bytes);
|
||||
}
|
||||
let mut image = if matches!(extension.as_str(), "tga" | "targa") {
|
||||
decode_tga(&bytes)?
|
||||
} else {
|
||||
SkiaTextureCodec::new()
|
||||
RustSkiaTextureCodec::new()
|
||||
.map_err(|_| "Could not initialize the image decoder".to_owned())?
|
||||
.decode(Box::new(Cursor::new(bytes)))
|
||||
.map_err(|_| "Failed to decode image".to_owned())?
|
||||
@@ -1491,7 +1491,7 @@ fn image_to_j2k(path: &Path) -> Result<Vec<u8>, String> {
|
||||
.resize_bilinear(width.min(1024), height.min(1024))
|
||||
.map_err(|_| "Failed to limit image dimensions".to_owned())?;
|
||||
}
|
||||
J2kCodec::encode(
|
||||
RustJ2kCodec::encode(
|
||||
&image,
|
||||
J2kEncodeOptions::default().with_compression(J2kCompression::Lossy {
|
||||
compression_ratio: 10.0,
|
||||
@@ -1583,7 +1583,7 @@ async fn dump_outfit<B: Backend + ?Sized>(
|
||||
.await?;
|
||||
let jp2 = directory.join(format!("{texture_id}.jp2"));
|
||||
write_bounded(&jp2, &bytes)?;
|
||||
let image = J2kCodec::decode_bytes(&bytes, J2kDecodeOptions::default())
|
||||
let image = RustJ2kCodec::decode_bytes(&bytes, J2kDecodeOptions::default())
|
||||
.map_err(|_| format!("Failed to decode outfit texture {texture_id}"))?;
|
||||
let tga = directory.join(format!("{texture_id}.tga"));
|
||||
write_bounded(&tga, &encode_tga(&image)?)?;
|
||||
|
||||
@@ -1466,7 +1466,7 @@ async fn download_texture<B: Backend + ?Sized>(
|
||||
.as_str(),
|
||||
)?;
|
||||
write_bounded(&path, &data)?;
|
||||
let dimensions = libremetaverse_imaging::J2kCodec::decode_bytes(
|
||||
let dimensions = libremetaverse_imaging::RustJ2kCodec::decode_bytes(
|
||||
&data,
|
||||
libremetaverse_imaging::J2kDecodeOptions::default(),
|
||||
)
|
||||
@@ -1574,7 +1574,7 @@ async fn export<B: Backend + ?Sized>(
|
||||
.await?;
|
||||
let path = texture_directory.join(format!("{texture}.jp2"));
|
||||
write_bounded(&path, &data)?;
|
||||
let image = libremetaverse_imaging::J2kCodec::decode_bytes(
|
||||
let image = libremetaverse_imaging::RustJ2kCodec::decode_bytes(
|
||||
&data,
|
||||
libremetaverse_imaging::J2kDecodeOptions::default(),
|
||||
)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use libremetaverse_imaging::{J2kCodec, J2kEncodeOptions, ManagedImage, ManagedImageImageChannels};
|
||||
use libremetaverse_imaging::{
|
||||
J2kEncodeOptions, ManagedImage, ManagedImageImageChannels, RustJ2kCodec,
|
||||
};
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, Output, Stdio};
|
||||
@@ -111,7 +113,7 @@ fn one_pixel_jp2() -> Vec<u8> {
|
||||
image.red[0] = 10;
|
||||
image.green[0] = 20;
|
||||
image.blue[0] = 30;
|
||||
J2kCodec::encode(&image, J2kEncodeOptions::default()).expect("encode JPEG2000 fixture")
|
||||
RustJ2kCodec::encode(&image, J2kEncodeOptions::default()).expect("encode JPEG2000 fixture")
|
||||
}
|
||||
|
||||
fn one_pixel_tga() -> Vec<u8> {
|
||||
@@ -277,7 +279,7 @@ fn fake_grid_exercises_every_owned_inventory_appearance_and_asset_command() {
|
||||
b"default { state_entry() {} }"
|
||||
);
|
||||
assert_eq!(
|
||||
J2kCodec::decode_bytes(
|
||||
RustJ2kCodec::decode_bytes(
|
||||
&fs::read(outfit.join(format!("{UPLOADED_TEXTURE_ASSET}.jp2")))
|
||||
.expect("uploaded outfit jp2"),
|
||||
libremetaverse_imaging::J2kDecodeOptions::default(),
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use libremetaverse_imaging::{J2kCodec, J2kEncodeOptions, ManagedImage, ManagedImageImageChannels};
|
||||
use libremetaverse_imaging::{
|
||||
J2kEncodeOptions, ManagedImage, ManagedImageImageChannels, RustJ2kCodec,
|
||||
};
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, Output, Stdio};
|
||||
@@ -85,7 +87,7 @@ fn one_pixel_jp2() -> Vec<u8> {
|
||||
image.red[0] = 10;
|
||||
image.green[0] = 20;
|
||||
image.blue[0] = 30;
|
||||
J2kCodec::encode(&image, J2kEncodeOptions::default()).expect("encode JPEG2000")
|
||||
RustJ2kCodec::encode(&image, J2kEncodeOptions::default()).expect("encode JPEG2000")
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -40,8 +40,8 @@ def check_owned_rust() -> None:
|
||||
|
||||
def check_features() -> None:
|
||||
imaging = load_toml(OWNED_CRATES[0] / "Cargo.toml")
|
||||
if imaging["features"].get("default") != []:
|
||||
raise SystemExit("imaging default features must stay empty")
|
||||
if imaging["features"].get("default") != ["rust-j2k"]:
|
||||
raise SystemExit("imaging defaults must select only pure-Rust JPEG 2000")
|
||||
if imaging["features"].get("jpeg2000") != ["dep:libremetaverse-openjpeg"]:
|
||||
raise SystemExit("JPEG 2000 must stay isolated behind its optional feature")
|
||||
if imaging["features"].get("rust-j2k") != ["dep:j2k"]:
|
||||
@@ -50,8 +50,8 @@ def check_features() -> None:
|
||||
raise SystemExit("the OpenJPEG adapter dependency must stay optional")
|
||||
|
||||
skia = load_toml(OWNED_CRATES[1] / "Cargo.toml")
|
||||
if skia["features"].get("default") != []:
|
||||
raise SystemExit("Skia adapter default features must stay empty")
|
||||
if skia["features"].get("default") != ["rust-skia"]:
|
||||
raise SystemExit("raster adapter defaults must select only pure-Rust codecs")
|
||||
if skia["features"].get("skia") != ["dep:skia-safe"]:
|
||||
raise SystemExit("Skia must stay isolated behind its optional feature")
|
||||
targets = skia.get("target", {}).values()
|
||||
|
||||
@@ -911,7 +911,10 @@ fn validate_features(name: &str, actual: &BTreeMap<String, Vec<String>>) -> Resu
|
||||
let expected = match name {
|
||||
"libremetaverse" => BTreeMap::from([
|
||||
("dds-bc67".to_owned(), vec!["dep:bcdec_rs".to_owned()]),
|
||||
("default".to_owned(), vec!["dds-bc67".to_owned()]),
|
||||
(
|
||||
"default".to_owned(),
|
||||
vec!["dds-bc67".to_owned(), "rust-j2k".to_owned()],
|
||||
),
|
||||
(
|
||||
"jpeg2000".to_owned(),
|
||||
vec!["libremetaverse-imaging/jpeg2000".to_owned()],
|
||||
@@ -923,7 +926,7 @@ fn validate_features(name: &str, actual: &BTreeMap<String, Vec<String>>) -> Resu
|
||||
("vorbis".to_owned(), vec!["dep:vorbis_rs".to_owned()]),
|
||||
]),
|
||||
"libremetaverse-imaging" => BTreeMap::from([
|
||||
("default".to_owned(), Vec::new()),
|
||||
("default".to_owned(), vec!["rust-j2k".to_owned()]),
|
||||
(
|
||||
"jpeg2000".to_owned(),
|
||||
vec!["dep:libremetaverse-openjpeg".to_owned()],
|
||||
@@ -931,7 +934,7 @@ fn validate_features(name: &str, actual: &BTreeMap<String, Vec<String>>) -> Resu
|
||||
("rust-j2k".to_owned(), vec!["dep:j2k".to_owned()]),
|
||||
]),
|
||||
"libremetaverse-imaging-skia" => BTreeMap::from([
|
||||
("default".to_owned(), Vec::new()),
|
||||
("default".to_owned(), vec!["rust-skia".to_owned()]),
|
||||
(
|
||||
"rust-skia".to_owned(),
|
||||
vec![
|
||||
@@ -1242,7 +1245,7 @@ The exact mapping, exported-marker, feature, and normalized Rust declaration has
|
||||
- .NET events become `subscribe_*` calls returning an owned `Subscription`; callbacks are `Send + Sync` and dispatch outside internal locks.\n\
|
||||
- `IDisposable` becomes explicit idempotent shutdown plus `Drop`; cancellation remains a typed `Error::Cancelled`.\n\
|
||||
- Closed C# enums retain fixed discriminants and are SemVer-breaking to extend; flags retain unknown bits, while public Rust error enums are `non_exhaustive`.\n\
|
||||
- Optional native and pure-Rust backends remain feature-gated (`jpeg2000`, `rust-j2k`, `skia`, `rust-skia`, `vorbis`, `real-audio`); default and empty-default sets are part of the baseline.\n\
|
||||
- Pure-Rust image backends are enabled by default (`rust-j2k`, `rust-skia`); native alternatives remain feature-gated (`jpeg2000`, `skia`, `vorbis`, `real-audio`), and empty-default sets remain part of the baseline.\n\
|
||||
- Capability HTTP injection uses project-owned `HttpMessageHandler`, `CapsHttpLimits`, and `with_native_transport`; the internal `reqwest` client is not part of the public surface.\n\
|
||||
- External C# signature types map to core/std, adopted cross-platform crates, or project-owned boundary types; no third-party crate path leaks through mapped signatures or public Rust declarations.\n\n\
|
||||
## Compile consumers\n\n\
|
||||
|
||||
@@ -422,7 +422,7 @@ fn audit_cargo_features(root: &Path) -> Result<()> {
|
||||
if defaults.iter().any(|feature| {
|
||||
matches!(
|
||||
feature.as_str(),
|
||||
Some("jpeg2000" | "vorbis" | "dep:vorbis_rs")
|
||||
Some("jpeg2000" | "skia" | "vorbis" | "dep:vorbis_rs")
|
||||
)
|
||||
}) {
|
||||
return Err(MatrixError::new(
|
||||
@@ -450,6 +450,8 @@ fn audit_cargo_features(root: &Path) -> Result<()> {
|
||||
let default_tree = String::from_utf8_lossy(&default_tree.stdout);
|
||||
for forbidden in [
|
||||
"libremetaverse-openjpeg ",
|
||||
"skia-safe ",
|
||||
"skia-bindings ",
|
||||
"vorbis_rs ",
|
||||
"ogg_next_sys ",
|
||||
"aotuv_lancer_vorbis_sys ",
|
||||
|
||||
Reference in New Issue
Block a user