Repository: unum-cloud/usearch (language: rust)

Issue:
Bug: error: linking with `cc` failed: exit status: 1 in rust crate
### Describe the bug

It builds, but upon running it errors.

```
note: /usr/bin/ld: /workspaces/test/target/debug/deps/libusearch-82cbab353a3106f1.rlib(usearch-82cbab353a3106f1.usearch.8bd6f700c2917180-cgu.0.rcgu.o): in function `usearch::ffi::new_native_index':
          /usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/usearch-2.10.3/rust/lib.rs:55: undefined reference to `cxxbridge1$new_native_index'
          /usr/bin/ld: /workspaces/test/target/debug/deps/libusearch-82cbab353a3106f1.rlib(usearch-82cbab353a3106f1.usearch.8bd6f700c2917180-cgu.0.rcgu.o): in function `usearch::ffi::NativeIndex::load':
          /usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/usearch-2.10.3/rust/lib.rs:84: undefined reference to `cxxbridge1$NativeIndex$load'
          /usr/bin/ld: /workspaces/test/target/debug/deps/libusearch-82cbab353a3106f1.rlib(usearch-82cbab353a3106f1.usearch.8bd6f700c2917180-cgu.0.rcgu.o): in function `<usearch::ffi::NativeIndex as cxx::unique_ptr::UniquePtrTarget>::__raw':
          /usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/usearch-2.10.3/rust/lib.rs:55: undefined reference to `cxxbridge1$unique_ptr$NativeIndex$raw'
          /usr/bin/ld: /workspaces/test/target/debug/deps/libusearch-82cbab353a3106f1.rlib(usearch-82cbab353a3106f1.usearch.8bd6f700c2917180-cgu.0.rcgu.o): in function `<usearch::ffi::NativeIndex as cxx::unique_ptr::UniquePtrTarget>::__get':
          /usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/usearch-2.10.3/rust/lib.rs:55: undefined reference to `cxxbridge1$unique_ptr$NativeIndex$get'
          /usr/bin/ld: /workspaces/test/target/debug/deps/libusearch-82cbab353a3106f1.rlib(usearch-82cbab353a3106f1.usearch.8bd6f700c2917180-cgu.0.rcgu.o): in function `<usearch::ffi::NativeIndex as cxx::unique_ptr::UniquePtrTarget>::__drop':
          /usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/usearch-2.10.3/rust/lib.rs:55: undefined reference to `cxxbridge1$unique_ptr$NativeIndex$drop'
          collect2: error: ld returned 1 exit status
          
  = note: some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
  = note: use the `-l` flag to specify native libraries to link
  = note: use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-link-lib)
```

### Steps to reproduce

Running in a container.

```
    pub async fn new(opt: &ContentIndexSettings) -> Self {
        let db_path = db_check_path(&opt.context_index_name, "usearch")
            .await
            .unwrap();
        let usearch_filename = format!("{}/index.usearch", db_path);
        let options = IndexOptions {
            dimensions: 1024,
            metric: MetricKind::Cos,
            quantization: ScalarKind::F32,
            connectivity: 0,
            expansion_add: 0,
            expansion_search: 0,
            multi: false,
        };
        let index = new_index(&options);
        let index = match index {
            Ok(index) => index,
            Err(e) => panic!("Failed to create index: {}", e),
        };
        index.load(&usearch_filename).unwrap();
        Self {
            index,
            usearch_filename,
        }
    }
```

### Expected behavior

To run.

### USearch version

2.10.3

### Operating System

Ubuntu 22.04

### Hardware architecture

x86

### Which interface are you using?

Other bindings

### Contact Details

_No response_

### Is there an existing issue for this?

- [X] I have searched the existing issues

### Code of Conduct

- [X] I agree to follow this project's Code of Conduct


Discussion / hints:
Interesting, which compiler are you using, @ShelbyJenkins? If there is a minimal test case you can submit as a PR, that would really help prioritize this patch 🤗
from /workspaces/test/target/debug/build/usearch-d165d1039b6b3263/output
<details><summary>Details</summary>
<p>

cargo:CXXBRIDGE_PREFIX=usearch
cargo:CXXBRIDGE_DIR0=/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/include
cargo:CXXBRIDGE_DIR1=/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/crate
TARGET = Some("x86_64-unknown-linux-gnu")
OPT_LEVEL = Some("0")
HOST = Some("x86_64-unknown-linux-gnu")
cargo:rerun-if-env-changed=CXX_x86_64-unknown-linux-gnu
CXX_x86_64-unknown-linux-gnu = None
cargo:rerun-if-env-changed=CXX_x86_64_unknown_linux_gnu
CXX_x86_64_unknown_linux_gnu = None
cargo:rerun-if-env-changed=HOST_CXX
HOST_CXX = None
cargo:rerun-if-env-changed=CXX
CXX = Some("clang++")
cargo:rerun-if-env-changed=CRATE_CC_NO_DEFAULTS
CRATE_CC_NO_DEFAULTS = None
DEBUG = Some("true")
cargo:rerun-if-env-changed=CXXFLAGS_x86_64-unknown-linux-gnu
CXXFLAGS_x86_64-unknown-linux-gnu = None
cargo:rerun-if-env-changed=CXXFLAGS_x86_64_unknown_linux_gnu
CXXFLAGS_x86_64_unknown_linux_gnu = None
cargo:rerun-if-env-changed=HOST_CXXFLAGS
HOST_CXXFLAGS = None
cargo:rerun-if-env-changed=CXXFLAGS
CXXFLAGS = None
cargo:rerun-if-env-changed=CXX_x86_64-unknown-linux-gnu
CXX_x86_64-unknown-linux-gnu = None
cargo:rerun-if-env-changed=CXX_x86_64_unknown_linux_gnu
CXX_x86_64_unknown_linux_gnu = None
cargo:rerun-if-env-changed=HOST_CXX
HOST_CXX = None
cargo:rerun-if-env-changed=CXX
CXX = Some("clang++")
cargo:rerun-if-env-changed=CRATE_CC_NO_DEFAULTS
CRATE_CC_NO_DEFAULTS = None
cargo:rerun-if-env-changed=CXXFLAGS_x86_64-unknown-linux-gnu
CXXFLAGS_x86_64-unknown-linux-gnu = None
cargo:rerun-if-env-changed=CXXFLAGS_x86_64_unknown_linux_gnu
CXXFLAGS_x86_64_unknown_linux_gnu = None
cargo:rerun-if-env-changed=HOST_CXXFLAGS
HOST_CXXFLAGS = None
cargo:rerun-if-env-changed=CXXFLAGS
CXXFLAGS = None
cargo:rerun-if-env-changed=CXX_x86_64-unknown-linux-gnu
CXX_x86_64-unknown-linux-gnu = None
cargo:rerun-if-env-changed=CXX_x86_64_unknown_linux_gnu
CXX_x86_64_unknown_linux_gnu = None
cargo:rerun-if-env-changed=HOST_CXX
HOST_CXX = None
cargo:rerun-if-env-changed=CXX
CXX = Some("clang++")
cargo:rerun-if-env-changed=CRATE_CC_NO_DEFAULTS
CRATE_CC_NO_DEFAULTS = None
cargo:rerun-if-env-changed=CXXFLAGS_x86_64-unknown-linux-gnu
CXXFLAGS_x86_64-unknown-linux-gnu = None
cargo:rerun-if-env-changed=CXXFLAGS_x86_64_unknown_linux_gnu
CXXFLAGS_x86_64_unknown_linux_gnu = None
cargo:rerun-if-env-changed=HOST_CXXFLAGS
HOST_CXXFLAGS = None
cargo:rerun-if-env-changed=CXXFLAGS
CXXFLAGS = None
cargo:rerun-if-env-changed=CXX_x86_64-unknown-linux-gnu
CXX_x86_64-unknown-linux-gnu = None
cargo:rerun-if-env-changed=CXX_x86_64_unknown_linux_gnu
CXX_x86_64_unknown_linux_gnu = None
cargo:rerun-if-env-changed=HOST_CXX
HOST_CXX = None
cargo:rerun-if-env-changed=CXX
CXX = Some("clang++")
cargo:rerun-if-env-changed=CRATE_CC_NO_DEFAULTS
CRATE_CC_NO_DEFAULTS = None
cargo:rerun-if-env-changed=CXXFLAGS_x86_64-unknown-linux-gnu
CXXFLAGS_x86_64-unknown-linux-gnu = None
cargo:rerun-if-env-changed=CXXFLAGS_x86_64_unknown_linux_gnu
CXXFLAGS_x86_64_unknown_linux_gnu = None
cargo:rerun-if-env-changed=HOST_CXXFLAGS
HOST_CXXFLAGS = None
cargo:rerun-if-env-changed=CXXFLAGS
CXXFLAGS = None
cargo:rerun-if-env-changed=CXX_x86_64-unknown-linux-gnu
CXX_x86_64-unknown-linux-gnu = None
cargo:rerun-if-env-changed=CXX_x86_64_unknown_linux_gnu
CXX_x86_64_unknown_linux_gnu = None
cargo:rerun-if-env-changed=HOST_CXX
HOST_CXX = None
cargo:rerun-if-env-changed=CXX
CXX = Some("clang++")
cargo:rerun-if-env-changed=CRATE_CC_NO_DEFAULTS
CRATE_CC_NO_DEFAULTS = None
cargo:rerun-if-env-changed=CXXFLAGS_x86_64-unknown-linux-gnu
CXXFLAGS_x86_64-unknown-linux-gnu = None
cargo:rerun-if-env-changed=CXXFLAGS_x86_64_unknown_linux_gnu
CXXFLAGS_x86_64_unknown_linux_gnu = None
cargo:rerun-if-env-changed=HOST_CXXFLAGS
HOST_CXXFLAGS = None
cargo:rerun-if-env-changed=CXXFLAGS
CXXFLAGS = None
cargo:rerun-if-env-changed=CXX_x86_64-unknown-linux-gnu
CXX_x86_64-unknown-linux-gnu = None
cargo:rerun-if-env-changed=CXX_x86_64_unknown_linux_gnu
CXX_x86_64_unknown_linux_gnu = None
cargo:rerun-if-env-changed=HOST_CXX
HOST_CXX = None
cargo:rerun-if-env-changed=CXX
CXX = Some("clang++")
cargo:rerun-if-env-changed=CRATE_CC_NO_DEFAULTS
CRATE_CC_NO_DEFAULTS = None
cargo:rerun-if-env-changed=CXXFLAGS_x86_64-unknown-linux-gnu
CXXFLAGS_x86_64-unknown-linux-gnu = None
cargo:rerun-if-env-changed=CXXFLAGS_x86_64_unknown_linux_gnu
CXXFLAGS_x86_64_unknown_linux_gnu = None
cargo:rerun-if-env-changed=HOST_CXXFLAGS
HOST_CXXFLAGS = None
cargo:rerun-if-env-changed=CXXFLAGS
CXXFLAGS = None
cargo:rerun-if-env-changed=CXX_x86_64-unknown-linux-gnu
CXX_x86_64-unknown-linux-gnu = None
cargo:rerun-if-env-changed=CXX_x86_64_unknown_linux_gnu
CXX_x86_64_unknown_linux_gnu = None
cargo:rerun-if-env-changed=HOST_CXX
HOST_CXX = None
cargo:rerun-if-env-changed=CXX
CXX = Some("clang++")
cargo:rerun-if-env-changed=CRATE_CC_NO_DEFAULTS
CRATE_CC_NO_DEFAULTS = None
cargo:rerun-if-env-changed=CXXFLAGS_x86_64-unknown-linux-gnu
CXXFLAGS_x86_64-unknown-linux-gnu = None
cargo:rerun-if-env-changed=CXXFLAGS_x86_64_unknown_linux_gnu
CXXFLAGS_x86_64_unknown_linux_gnu = None
cargo:rerun-if-env-changed=HOST_CXXFLAGS
HOST_CXXFLAGS = None
cargo:rerun-if-env-changed=CXXFLAGS
CXXFLAGS = None
cargo:rerun-if-env-changed=CC_ENABLE_DEBUG_OUTPUT
cargo:warning=In file included from /workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/sources/usearch/rust/lib.rs.cc:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:50:9: [0m[0;1;35mwarning: [0m[1m'SIMSIMD_DYNAMIC_DISPATCH' macro redefined [-Wmacro-redefined][0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 0
cargo:warning=[0;1;32m        ^
cargo:warning=[0m[1m<command line>:2:9: [0m[0;1;30mnote: [0mprevious definition is here[0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 1
cargo:warning=[0;1;32m        ^
cargo:warning=[0mIn file included from /workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/sources/usearch/rust/lib.rs.cc:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:56:10: [0m[0;1;31mfatal error: [0m[1m'simsimd/simsimd.h' file not found[0m
cargo:warning=#include <simsimd/simsimd.h>
cargo:warning=[0;1;32m         ^~~~~~~~~~~~~~~~~~~
cargo:warning=[0m1 warning and 1 error generated.
exit status: 1
cargo:warning=ToolExecError: Command "clang++" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-gdwarf-4" "-fno-omit-frame-pointer" "-m64" "--target=x86_64-unknown-linux-gnu" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/include" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/crate" "-I" "include" "-I" "rust" "-I" "fp16/include" "-I" "simsimd/include" "-Wno-unknown-pragmas" "-std=c++17" "-O3" "-ffast-math" "-fdiagnostics-color=always" "-g1" "-DUSEARCH_USE_SIMSIMD=1" "-DSIMSIMD_DYNAMIC_DISPATCH=1" "-DUSEARCH_USE_OPENMP=0" "-DUSEARCH_USE_FP16LIB=0" "-o" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/9ee4cf43856de047-lib.rs.o" "-c" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/sources/usearch/rust/lib.rs.cc" with args "clang++" did not execute successfully (status code exit status: 1).cargo:warning=In file included from rust/lib.cpp:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:50:9: [0m[0;1;35mwarning: [0m[1m'SIMSIMD_DYNAMIC_DISPATCH' macro redefined [-Wmacro-redefined][0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 0
cargo:warning=[0;1;32m        ^
cargo:warning=[0m[1m<command line>:2:9: [0m[0;1;30mnote: [0mprevious definition is here[0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 1
cargo:warning=[0;1;32m        ^
cargo:warning=[0mIn file included from rust/lib.cpp:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:56:10: [0m[0;1;31mfatal error: [0m[1m'simsimd/simsimd.h' file not found[0m
cargo:warning=#include <simsimd/simsimd.h>
cargo:warning=[0;1;32m         ^~~~~~~~~~~~~~~~~~~
cargo:warning=[0m1 warning and 1 error generated.

exit status: 1
cargo:warning=ToolExecError: Command "clang++" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-gdwarf-4" "-fno-omit-frame-pointer" "-m64" "--target=x86_64-unknown-linux-gnu" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/include" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/crate" "-I" "include" "-I" "rust" "-I" "fp16/include" "-I" "simsimd/include" "-Wno-unknown-pragmas" "-std=c++17" "-O3" "-ffast-math" "-fdiagnostics-color=always" "-g1" "-DUSEARCH_USE_SIMSIMD=1" "-DSIMSIMD_DYNAMIC_DISPATCH=1" "-DUSEARCH_USE_OPENMP=0" "-DUSEARCH_USE_FP16LIB=0" "-o" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/7d686aece4a9d910-lib.o" "-c" "rust/lib.cpp" with args "clang++" did not execute successfully (status code exit status: 1).
cargo:warning=Failed to compile with all SIMD backends...cargo:warning=In file included from /workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/sources/usearch/rust/lib.rs.cc:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:50:9: [0m[0;1;35mwarning: [0m[1m'SIMSIMD_DYNAMIC_DISPATCH' macro redefined [-Wmacro-redefined][0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 0
cargo:warning=[0;1;32m        ^
cargo:warning=[0m[1m<command line>:2:9: [0m[0;1;30mnote: [0mprevious definition is here[0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 1
cargo:warning=[0;1;32m        ^
cargo:warning=[0mIn file included from /workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/sources/usearch/rust/lib.rs.cc:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:56:10: [0m[0;1;31mfatal error: [0m[1m'simsimd/simsimd.h' file not found[0m
cargo:warning=#include <simsimd/simsimd.h>
cargo:warning=[0;1;32m         ^~~~~~~~~~~~~~~~~~~
cargo:warning=[0m1 warning and 1 error generated.
exit status: 1
cargo:warning=ToolExecError: Command "clang++" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-gdwarf-4" "-fno-omit-frame-pointer" "-m64" "--target=x86_64-unknown-linux-gnu" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/include" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/crate" "-I" "include" "-I" "rust" "-I" "fp16/include" "-I" "simsimd/include" "-Wno-unknown-pragmas" "-std=c++17" "-O3" "-ffast-math" "-fdiagnostics-color=always" "-g1" "-DUSEARCH_USE_SIMSIMD=1" "-DSIMSIMD_DYNAMIC_DISPATCH=1" "-DUSEARCH_USE_OPENMP=0" "-DUSEARCH_USE_FP16LIB=0" "-DSIMSIMD_TARGET_SAPPHIRE=0" "-o" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/9ee4cf43856de047-lib.rs.o" "-c" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/sources/usearch/rust/lib.rs.cc" with args "clang++" did not execute successfully (status code exit status: 1).cargo:warning=In file included from rust/lib.cpp:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:50:9: [0m[0;1;35mwarning: [0m[1m'SIMSIMD_DYNAMIC_DISPATCH' macro redefined [-Wmacro-redefined][0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 0
cargo:warning=[0;1;32m        ^
cargo:warning=[0m[1m<command line>:2:9: [0m[0;1;30mnote: [0mprevious definition is here[0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 1
cargo:warning=[0;1;32m        ^
cargo:warning=[0mIn file included from rust/lib.cpp:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:56:10: [0m[0;1;31mfatal error: [0m[1m'simsimd/simsimd.h' file not found[0m
cargo:warning=#include <simsimd/simsimd.h>
cargo:warning=[0;1;32m         ^~~~~~~~~~~~~~~~~~~
cargo:warning=[0m1 warning and 1 error generated.

exit status: 1
cargo:warning=ToolExecError: Command "clang++" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-gdwarf-4" "-fno-omit-frame-pointer" "-m64" "--target=x86_64-unknown-linux-gnu" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/include" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/crate" "-I" "include" "-I" "rust" "-I" "fp16/include" "-I" "simsimd/include" "-Wno-unknown-pragmas" "-std=c++17" "-O3" "-ffast-math" "-fdiagnostics-color=always" "-g1" "-DUSEARCH_USE_SIMSIMD=1" "-DSIMSIMD_DYNAMIC_DISPATCH=1" "-DUSEARCH_USE_OPENMP=0" "-DUSEARCH_USE_FP16LIB=0" "-DSIMSIMD_TARGET_SAPPHIRE=0" "-o" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/7d686aece4a9d910-lib.o" "-c" "rust/lib.cpp" with args "clang++" did not execute successfully (status code exit status: 1).
cargo:warning=Failed to compile after disabling SIMSIMD_TARGET_SAPPHIRE, trying next configuration...
cargo:warning=In file included from /workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/sources/usearch/rust/lib.rs.cc:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:50:9: [0m[0;1;35mwarning: [0m[1m'SIMSIMD_DYNAMIC_DISPATCH' macro redefined [-Wmacro-redefined][0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 0
cargo:warning=[0;1;32m        ^
cargo:warning=[0m[1m<command line>:2:9: [0m[0;1;30mnote: [0mprevious definition is here[0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 1
cargo:warning=[0;1;32m        ^
cargo:warning=[0mIn file included from /workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/sources/usearch/rust/lib.rs.cc:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:56:10: [0m[0;1;31mfatal error: [0m[1m'simsimd/simsimd.h' file not found[0m
cargo:warning=#include <simsimd/simsimd.h>
cargo:warning=[0;1;32m         ^~~~~~~~~~~~~~~~~~~
cargo:warning=[0m1 warning and 1 error generated.
exit status: 1
cargo:warning=ToolExecError: Command "clang++" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-gdwarf-4" "-fno-omit-frame-pointer" "-m64" "--target=x86_64-unknown-linux-gnu" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/include" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/crate" "-I" "include" "-I" "rust" "-I" "fp16/include" "-I" "simsimd/include" "-Wno-unknown-pragmas" "-std=c++17" "-O3" "-ffast-math" "-fdiagnostics-color=always" "-g1" "-DUSEARCH_USE_SIMSIMD=1" "-DSIMSIMD_DYNAMIC_DISPATCH=1" "-DUSEARCH_USE_OPENMP=0" "-DUSEARCH_USE_FP16LIB=0" "-DSIMSIMD_TARGET_SAPPHIRE=0" "-DSIMSIMD_TARGET_ICE=0" "-o" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/9ee4cf43856de047-lib.rs.o" "-c" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/sources/usearch/rust/lib.rs.cc" with args "clang++" did not execute successfully (status code exit status: 1).cargo:warning=In file included from rust/lib.cpp:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:50:9: [0m[0;1;35mwarning: [0m[1m'SIMSIMD_DYNAMIC_DISPATCH' macro redefined [-Wmacro-redefined][0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 0
cargo:warning=[0;1;32m        ^
cargo:warning=[0m[1m<command line>:2:9: [0m[0;1;30mnote: [0mprevious definition is here[0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 1
cargo:warning=[0;1;32m        ^
cargo:warning=[0mIn file included from rust/lib.cpp:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:56:10: [0m[0;1;31mfatal error: [0m[1m'simsimd/simsimd.h' file not found[0m
cargo:warning=#include <simsimd/simsimd.h>
cargo:warning=[0;1;32m         ^~~~~~~~~~~~~~~~~~~
cargo:warning=[0m1 warning and 1 error generated.

exit status: 1
cargo:warning=ToolExecError: Command "clang++" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-gdwarf-4" "-fno-omit-frame-pointer" "-m64" "--target=x86_64-unknown-linux-gnu" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/include" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/crate" "-I" "include" "-I" "rust" "-I" "fp16/include" "-I" "simsimd/include" "-Wno-unknown-pragmas" "-std=c++17" "-O3" "-ffast-math" "-fdiagnostics-color=always" "-g1" "-DUSEARCH_USE_SIMSIMD=1" "-DSIMSIMD_DYNAMIC_DISPATCH=1" "-DUSEARCH_USE_OPENMP=0" "-DUSEARCH_USE_FP16LIB=0" "-DSIMSIMD_TARGET_SAPPHIRE=0" "-DSIMSIMD_TARGET_ICE=0" "-o" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/7d686aece4a9d910-lib.o" "-c" "rust/lib.cpp" with args "clang++" did not execute successfully (status code exit status: 1).
cargo:warning=Failed to compile after disabling SIMSIMD_TARGET_ICE, trying next configuration...
cargo:warning=In file included from /workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/sources/usearch/rust/lib.rs.cc:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:50:9: [0m[0;1;35mwarning: [0m[1m'SIMSIMD_DYNAMIC_DISPATCH' macro redefined [-Wmacro-redefined][0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 0
cargo:warning=[0;1;32m        ^
cargo:warning=[0m[1m<command line>:2:9: [0m[0;1;30mnote: [0mprevious definition is here[0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 1
cargo:warning=[0;1;32m        ^
cargo:warning=[0mIn file included from /workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/sources/usearch/rust/lib.rs.cc:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:56:10: [0m[0;1;31mfatal error: [0m[1m'simsimd/simsimd.h' file not found[0m
cargo:warning=#include <simsimd/simsimd.h>
cargo:warning=[0;1;32m         ^~~~~~~~~~~~~~~~~~~
cargo:warning=[0m1 warning and 1 error generated.
exit status: 1
cargo:warning=ToolExecError: Command "clang++" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-gdwarf-4" "-fno-omit-frame-pointer" "-m64" "--target=x86_64-unknown-linux-gnu" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/include" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/crate" "-I" "include" "-I" "rust" "-I" "fp16/include" "-I" "simsimd/include" "-Wno-unknown-pragmas" "-std=c++17" "-O3" "-ffast-math" "-fdiagnostics-color=always" "-g1" "-DUSEARCH_USE_SIMSIMD=1" "-DSIMSIMD_DYNAMIC_DISPATCH=1" "-DUSEARCH_USE_OPENMP=0" "-DUSEARCH_USE_FP16LIB=0" "-DSIMSIMD_TARGET_SAPPHIRE=0" "-DSIMSIMD_TARGET_ICE=0" "-DSIMSIMD_TARGET_SKYLAKE=0" "-o" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/9ee4cf43856de047-lib.rs.o" "-c" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/sources/usearch/rust/lib.rs.cc" with args "clang++" did not execute successfully (status code exit status: 1).cargo:warning=In file included from rust/lib.cpp:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:50:9: [0m[0;1;35mwarning: [0m[1m'SIMSIMD_DYNAMIC_DISPATCH' macro redefined [-Wmacro-redefined][0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 0
cargo:warning=[0;1;32m        ^
cargo:warning=[0m[1m<command line>:2:9: [0m[0;1;30mnote: [0mprevious definition is here[0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 1
cargo:warning=[0;1;32m        ^
cargo:warning=[0mIn file included from rust/lib.cpp:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:56:10: [0m[0;1;31mfatal error: [0m[1m'simsimd/simsimd.h' file not found[0m
cargo:warning=#include <simsimd/simsimd.h>
cargo:warning=[0;1;32m         ^~~~~~~~~~~~~~~~~~~
cargo:warning=[0m1 warning and 1 error generated.

exit status: 1
cargo:warning=ToolExecError: Command "clang++" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-gdwarf-4" "-fno-omit-frame-pointer" "-m64" "--target=x86_64-unknown-linux-gnu" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/include" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/crate" "-I" "include" "-I" "rust" "-I" "fp16/include" "-I" "simsimd/include" "-Wno-unknown-pragmas" "-std=c++17" "-O3" "-ffast-math" "-fdiagnostics-color=always" "-g1" "-DUSEARCH_USE_SIMSIMD=1" "-DSIMSIMD_DYNAMIC_DISPATCH=1" "-DUSEARCH_USE_OPENMP=0" "-DUSEARCH_USE_FP16LIB=0" "-DSIMSIMD_TARGET_SAPPHIRE=0" "-DSIMSIMD_TARGET_ICE=0" "-DSIMSIMD_TARGET_SKYLAKE=0" "-o" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/7d686aece4a9d910-lib.o" "-c" "rust/lib.cpp" with args "clang++" did not execute successfully (status code exit status: 1).
cargo:warning=Failed to compile after disabling SIMSIMD_TARGET_SKYLAKE, trying next configuration...
cargo:warning=In file included from /workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/sources/usearch/rust/lib.rs.cc:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:50:9: [0m[0;1;35mwarning: [0m[1m'SIMSIMD_DYNAMIC_DISPATCH' macro redefined [-Wmacro-redefined][0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 0
cargo:warning=[0;1;32m        ^
cargo:warning=[0m[1m<command line>:2:9: [0m[0;1;30mnote: [0mprevious definition is here[0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 1
cargo:warning=[0;1;32m        ^
cargo:warning=[0mIn file included from /workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/sources/usearch/rust/lib.rs.cc:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:56:10: [0m[0;1;31mfatal error: [0m[1m'simsimd/simsimd.h' file not found[0m
cargo:warning=#include <simsimd/simsimd.h>
cargo:warning=[0;1;32m         ^~~~~~~~~~~~~~~~~~~
cargo:warning=[0m1 warning and 1 error generated.
exit status: 1
cargo:warning=ToolExecError: Command "clang++" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-gdwarf-4" "-fno-omit-frame-pointer" "-m64" "--target=x86_64-unknown-linux-gnu" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/include" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/crate" "-I" "include" "-I" "rust" "-I" "fp16/include" "-I" "simsimd/include" "-Wno-unknown-pragmas" "-std=c++17" "-O3" "-ffast-math" "-fdiagnostics-color=always" "-g1" "-DUSEARCH_USE_SIMSIMD=1" "-DSIMSIMD_DYNAMIC_DISPATCH=1" "-DUSEARCH_USE_OPENMP=0" "-DUSEARCH_USE_FP16LIB=0" "-DSIMSIMD_TARGET_SAPPHIRE=0" "-DSIMSIMD_TARGET_ICE=0" "-DSIMSIMD_TARGET_SKYLAKE=0" "-DSIMSIMD_TARGET_HASWELL=0" "-o" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/9ee4cf43856de047-lib.rs.o" "-c" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/sources/usearch/rust/lib.rs.cc" with args "clang++" did not execute successfully (status code exit status: 1).cargo:warning=In file included from rust/lib.cpp:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:50:9: [0m[0;1;35mwarning: [0m[1m'SIMSIMD_DYNAMIC_DISPATCH' macro redefined [-Wmacro-redefined][0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 0
cargo:warning=[0;1;32m        ^
cargo:warning=[0m[1m<command line>:2:9: [0m[0;1;30mnote: [0mprevious definition is here[0m
cargo:warning=#define SIMSIMD_DYNAMIC_DISPATCH 1
cargo:warning=[0;1;32m        ^
cargo:warning=[0mIn file included from rust/lib.cpp:1:
cargo:warning=In file included from rust/lib.hpp:6:
cargo:warning=In file included from include/usearch/index_dense.hpp:10:
cargo:warning=[1minclude/usearch/index_plugins.hpp:56:10: [0m[0;1;31mfatal error: [0m[1m'simsimd/simsimd.h' file not found[0m
cargo:warning=#include <simsimd/simsimd.h>
cargo:warning=[0;1;32m         ^~~~~~~~~~~~~~~~~~~
cargo:warning=[0m1 warning and 1 error generated.

exit status: 1
cargo:warning=ToolExecError: Command "clang++" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-gdwarf-4" "-fno-omit-frame-pointer" "-m64" "--target=x86_64-unknown-linux-gnu" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/include" "-I" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/cxxbridge/crate" "-I" "include" "-I" "rust" "-I" "fp16/include" "-I" "simsimd/include" "-Wno-unknown-pragmas" "-std=c++17" "-O3" "-ffast-math" "-fdiagnostics-color=always" "-g1" "-DUSEARCH_USE_SIMSIMD=1" "-DSIMSIMD_DYNAMIC_DISPATCH=1" "-DUSEARCH_USE_OPENMP=0" "-DUSEARCH_USE_FP16LIB=0" "-DSIMSIMD_TARGET_SAPPHIRE=0" "-DSIMSIMD_TARGET_ICE=0" "-DSIMSIMD_TARGET_SKYLAKE=0" "-DSIMSIMD_TARGET_HASWELL=0" "-o" "/workspaces/test/target/debug/build/usearch-d165d1039b6b3263/out/7d686aece4a9d910-lib.o" "-c" "rust/lib.cpp" with args "clang++" did not execute successfully (status code exit status: 1).
cargo:warning=Failed to compile after disabling SIMSIMD_TARGET_HASWELL, trying next configuration...
cargo:rerun-if-changed=rust/lib.rs
cargo:rerun-if-changed=rust/lib.cpp
cargo:rerun-if-changed=rust/lib.hpp
cargo:rerun-if-changed=include/index_plugins.hpp
cargo:rerun-if-changed=include/index_dense.hpp
cargo:rerun-if-changed=include/usearch/index.hpp


</p>
</details> 

I also tried to clone the repo and compile it and that gave a ton of errors, but I didn't thinnk to save them. Usearch previously worked for me, so IDK what's going on. 
If you are trying to compile locally - you should pull dependencies:

```
cargo:warning=�[1minclude/usearch/index_plugins.hpp:56:10: �[0m�[0;1;31mfatal error: �[0m�[1m'simsimd/simsimd.h' file not found�[0m
```

See `CONTRIBUTING.md` for more details on how to compile. In past, the Rust builds were much simpler and didn't include advanced dynamic dispatch for SIMD kernels.

I'll look deeper into your logs and will try to reproduce. 
There seem to be two problems here:
1. The build script exits successfully even if it does not manage to build the library – there should be something like `exit(1)` in this case. This means that the linker fails with missing symbols later.
2. The `usearch` crate distributed via crates.io does not contain the `simsimd` directory, so the library build fails if `simsimd` library is not installed – this is unexpected.
That's actually why I was trying to compile locally - I noticed the sub module was not in the crate. 

So if you pull the submodules and try to build it resolves that issue of simsimd not being found, but it still doesn't build correctly. Sorry I forgot to mention that last night.
Gotcha! @ShelbyJenkins and @embe-pw if you have a PR to add files to the crate - I am ready to merge 🤗 

Can you please share the build errors as well? I suspect you are using an older compiler. Thanks!

Fix patch:
diff --git a/Cargo.toml b/Cargo.toml
index 12ddd136..24c6de01 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,6 +8,22 @@ license = "Apache-2.0"
 publish = true
 repository = "https://github.com/unum-cloud/usearch"
 
+# If no precompiled binaries are available, the build script will compile the
+# following files using the `build.rs` specification.
+include = [
+    "rust/*",
+    "include/*",
+    "fp16/include/*",
+    "simsimd/include/*",
+    "Cargo.toml",
+]
+
+[features]
+default = ["simsimd"] # SimSIMD is enabled by default
+simsimd = []          # No need to do anything to enable SimSIMD by default
+openmp = []           # Optional: Users can enable OpenMP
+fp16lib = []          # Optional: Users can enable FP16 support
+
 [lib]
 name = "usearch"
 path = "rust/lib.rs"
diff --git a/README.md b/README.md
index 0bc98ba8..05899372 100644
--- a/README.md
+++ b/README.md
@@ -194,21 +194,40 @@ When compared to FAISS's `IndexFlatL2` in Google Colab, __[USearch may offer up
 
 ## User-Defined Functions
 
-While most vector search packages concentrate on just a few metrics - "Inner Product distance" and "Euclidean distance," USearch extends this list to include any user-defined metrics.
-This flexibility allows you to customize your search for various applications, from computing geospatial coordinates with the rare [Haversine][haversine] distance to creating custom metrics for composite embeddings from multiple AI models.
+While most vector search packages concentrate on just two metrics, "Inner Product distance" and "Euclidean distance", USearch allows arbitrary user-defined metrics.
+This flexibility allows you to customize your search for various applications, from computing geospatial coordinates with the rare [Haversine][haversine] distance to creating custom metrics for composite embeddings from multiple AI models, like joint image-text embeddings.
+You can use [Numba][numba], [Cppyy][cppyy], or [PeachPy][peachpy] to define your [custom metric even in Python](https://unum-cloud.github.io/usearch/python#user-defined-metrics-and-jit-in-python):
 
-![USearch: Vector Search Approaches](https://github.com/unum-cloud/usearch/blob/main/assets/usearch-approaches-white.png?raw=true)
+```py
+from numba import cfunc, types, carray
+from usearch.index import Index, MetricKind, MetricSignature, CompiledMetric
+
+@cfunc(types.float32(types.CPointer(types.float32), types.CPointer(types.float32)))
+def python_inner_product(a, b):
+    a_array = carray(a, ndim)
+    b_array = carray(b, ndim)
+    c = 0.0
+    for i in range(ndim):
+        c += a_array[i] * b_array[i]
+    return 1 - c
+
+metric = CompiledMetric(pointer=python_inner_product.address, kind=MetricKind.IP, signature=MetricSignature.ArrayArray)
+index = Index(ndim=ndim, metric=metric, dtype=np.float32)
+```
 
-Unlike older approaches indexing high-dimensional spaces, like KD-Trees and Locality Sensitive Hashing, HNSW doesn't require vectors to be identical in length.
+Similar effect is even easier to achieve in C, C++, and Rust interfaces.
+Moreover, unlike older approaches indexing high-dimensional spaces, like KD-Trees and Locality Sensitive Hashing, HNSW doesn't require vectors to be identical in length.
 They only have to be comparable.
-So you can apply it in [obscure][obscure] applications, like searching for similar sets or fuzzy text matching, using [GZip][gzip-similarity] as a distance function.
-
-> Read more about [JIT and UDF in USearch Python SDK](https://unum-cloud.github.io/usearch/python#user-defined-metrics-and-jit-in-python).
+So you can apply it in [obscure][obscure] applications, like searching for similar sets or fuzzy text matching, using [GZip][gzip-similarity] compression-ratio as a distance function.
 
 [haversine]: https://ashvardanian.com/posts/abusing-vector-search#geo-spatial-indexing
 [obscure]: https://ashvardanian.com/posts/abusing-vector-search
 [gzip-similarity]: https://twitter.com/LukeGessler/status/1679211291292889100?s=20
 
+[numba]: https://numba.readthedocs.io/en/stable/reference/jit-compilation.html#c-callbacks
+[cppyy]: https://cppyy.readthedocs.io/en/latest/
+[peachpy]: https://github.com/Maratyszcza/PeachPy
+
 ## Memory Efficiency, Downcasting, and Quantization
 
 Training a quantization model and dimension-reduction is a common approach to accelerate vector search.
@@ -315,6 +334,7 @@ In some cases, like Batch operations, feature parity is meaningless, as the host
 | Save, load, view        |   ✅    |    ✅     |   ✅   |   ✅   |     ✅      |   ✅   |   ✅    |   ✅   |
 | User-defined metrics    |   ✅    |    ✅     |   ✅   |   ❌   |     ❌      |   ❌   |   ❌    |   ❌   |
 | Batch operations        |   ❌    |    ✅     |   ❌   |   ❌   |     ✅      |   ❌   |   ❌    |   ❌   |
+| Filter predicates       |   ✅    |    ❌     |   ✅   |   ❌   |     ❌      |   ✅   |   ❌    |   ❌   |
 | Joins                   |   ✅    |    ✅     |   ❌   |   ❌   |     ❌      |   ❌   |   ❌    |   ❌   |
 | Variable-length vectors |   ✅    |    ❌     |   ❌   |   ❌   |     ❌      |   ❌   |   ❌    |   ❌   |
 | 4B+ capacities          |   ✅    |    ❌     |   ❌   |   ❌   |     ❌      |   ❌   |   ❌    |   ❌   |
diff --git a/build.rs b/build.rs
index 0dd01b4a..5b6be2ce 100644
--- a/build.rs
+++ b/build.rs
@@ -10,11 +10,26 @@ fn main() {
         .include("fp16/include")
         .include("simsimd/include");
 
-    build
-        .define("USEARCH_USE_SIMSIMD", "1")
-        .define("SIMSIMD_DYNAMIC_DISPATCH", "1")
-        .define("USEARCH_USE_OPENMP", "0")
-        .define("USEARCH_USE_FP16LIB", "0");
+    // Check for optional features
+    if cfg!(feature = "openmp") {
+        build.define("USEARCH_USE_OPENMP", "1");
+    } else {
+        build.define("USEARCH_USE_OPENMP", "0");
+    }
+
+    if cfg!(feature = "fp16lib") {
+        build.define("USEARCH_USE_FP16LIB", "1");
+    } else {
+        build.define("USEARCH_USE_FP16LIB", "0");
+    }
+
+    if cfg!(feature = "simsimd") {
+        build
+            .define("USEARCH_USE_SIMSIMD", "1")
+            .define("SIMSIMD_DYNAMIC_DISPATCH", "1");
+    } else {
+        build.define("USEARCH_USE_SIMSIMD", "0");
+    }
 
     // Conditional compilation depending on the target operating system.
     if cfg!(target_os = "linux") {
diff --git a/c/README.md b/c/README.md
index 508b5203..37711bc8 100644
--- a/c/README.md
+++ b/c/README.md
@@ -2,33 +2,243 @@
 
 ## Installation
 
-The simplest form to integrate is to copy the contents of `usearch/c/` into your project.
-To build the library `libusearch_static_c` and `libusearch_c`, pass enable the `USEARCH_BUILD_LIB_C` CMake option:
+USearch vector-search engine can be integrated into your project using CMake.
+Alternatively, you can download one of the precompiled binaries from the [releases page](https://github.com/unum-cloud/usearch/releases).
 
-```bash
-cmake -DCMAKE_BUILD_TYPE=Release -DUSEARCH_BUILD_LIB_C=1 -DUSEARCH_BUILD_TEST_C=1 -DUSEARCH_BUILD_TEST_CPP=0 -DUSEARCH_BUILD_BENCH_CPP=0 -B ./build_release
-cmake --build ./build_release --config Release
-./build_release/test_c
+## Quickstart
+
+```c
+#include <stdio.h> // For printing.
+#include <assert.h> // For assertions!
+#include <usearch/usearch.h> // For the win 🚀
+
+int main() {
+
+    // Construct:
+    size_t dimensions = 128;
+    usearch_error_t error = NULL;
+    usearch_init_options_t opts = {
+        .metric_kind = usearch_metric_cos_k,
+        .scalar_kind = usearch_scalar_f16_k,
+        .dimensions = dimensions,
+        .expansion_add = 0, // for defaults
+        .expansion_search = 0 // for defaults
+    };
+    usearch_index_t index = usearch_init(&opts, &error);
+
+    size_t vectors_count = 1000;
+    usearch_reserve(index, vectors_count, &error);
+    if (error) goto cleanup;
+
+    // Populate:
+    float vector[dimensions]; // don't forget to fill the vector with data
+    usearch_add(index, 42, &vector[0], usearch_scalar_f32_k, &error);
+    if (error) goto cleanup;
+    
+    // Check up:
+    assert(usearch_size(index, &error) == vectors_count);
+    assert(usearch_capacity(index, &error) == vectors_count);
+    assert(usearch_contains(index, 42, &error));
+
+    // Search:
+    usearch_key_t found_keys[10];
+    float found_distances[10];
+    size_t found_count = usearch_search(
+        index, &vector[0], usearch_scalar_f32_k, 10, 
+        &found_keys[0], &found_distances[0], &error);
+
+    usearch_free(index, &error);
+
+  cleanup:
+    if (error) fprintf(stderr, "Error: %s\n", error);
+    if (index) usearch_free(index, &error);
+    return error ? 1 : 0;
+}
 ```
 
-## Quickstart
+## Serialization
+
+To save and load the index from disk, use the following methods:
+
+```c
+usearch_save(index, "index.usearch", &error);
+usearch_load(index, "index.usearch", &error);
+usearch_view(index, "index.usearch", &error);
+```
+
+Before saving them do disk, you can determine exactly how much disk space the index will take:
+
+```c
+size_t bytes = usearch_serialized_length(index, &error);
+```
+
+With a known size, you can serialize the index into an in-memory a buffer:
+
+```c
+void* buffer = malloc(bytes);
+usearch_save_buffer(index, buffer, bytes, &error);
+usearch_load_buffer(index, buffer, bytes, &error);
+usearch_view_buffer(index, buffer, bytes, &error);
+```
+
+One can also retrieve index metadata from the buffer or from disk:
+
+```c
+usearch_init_options_t opts;
+usearch_metadata("index.usearch", &opts, &error);
+usearch_metadata_buffer(buffer, bytes, &opts, &error);
+```
+
+## Metrics
+
+USearch comes pre-packaged with SimSIMD, bringing over 100 SIMD-accelerated distance kernels for x86 and ARM architectures.
+That includes:
+
+- `usearch_metric_cos_k` - Cosine Similarity metric, defined as `Cos = 1 - sum(a[i] * b[i]) / (sqrt(sum(a[i]^2) * sqrt(sum(b[i]^2)))`.
+- `usearch_metric_ip_k` - Inner Product metric, defined as `IP = 1 - sum(a[i] * b[i])`.
+- `usearch_metric_l2sq_k` - Squared Euclidean Distance metric, defined as `L2 = sum((a[i] - b[i])^2)`.
+- `usearch_metric_haversine_k` - Haversine (Great Circle) Distance metric.
+- `usearch_metric_divergence_k` - Jensen Shannon Divergence metric.
+- `usearch_metric_pearson_k` - Pearson Correlation metric.
+- `usearch_metric_hamming_k` - Bit-level Hamming Distance metric, defined as the number of differing bits.
+- `usearch_metric_tanimoto_k` - Bit-level Tanimoto (Jaccard) metric, defined as the number of intersecting bits divided by the number of union bits.
+- `usearch_metric_sorensen_k` - Bit-level Sorensen metric.
+
+### User-Defined Metrics
+
+You can also define your own metrics by implementing the `usearch_metric_t` interface:
+
+```c
+simsimd_distance_t callback(void const* a, void const* b, void* state) {
+    // Your custom metric implementation here
+}
+
+usearch_change_metric(index, callback, NULL, usearch_metric_unknown_k, &error);
+```
+
+You can always revert back to one of the native metrics by calling:
+
+```c
+usearch_change_metric_kind(index, usearch_metric_cos_k, &error);
+```
+
+## Filtering with Predicates
+
+Sometimes you may want to cross-reference search-results against some external database or filter them based on some criteria.
+In most engines, you'd have to manually perform paging requests, successively filtering the results.
+In USearch you can simply pass a predicate function to the search method, which will be applied directly during graph traversal.
+
+```c
+int is_odd(usearch_key_t key, void* state) {
+    return key % 2;
+}
+
+usearch_filtered_search(
+    index, &vector[0], usearch_scalar_f32_k, 10, 
+    &is_odd, NULL, // no state needed for this callback
+    &found_keys[0], &found_distances[0], &error);
+```
+
+## Extracting, Updating, and Removing Values
+
+It is generally not recommended to use HNSW indexes in case of frequent removals or major distribution shifts.
+For small updates, you can use the following methods:
+
+```c
+float recovered_vector[dimensions];
+size_t count_retrieved = usearch_get(index, 42, 1, 
+    &recovered_vector[0], usearch_scalar_f32_k, &error);
+assert(count_retrieved <= 1);
+
+size_t count_renamed = usearch_rename(index, 42, 43, &error);
+size_t count_removed = usearch_remove(index, 43, &error);
+assert(count_renamed == count_removed);
+```
+
+USearch can also be used for multi-indicies, where each key may map to multiple vectors.
+That's a common case when implementing semantic search for long documents, where the entire documents can't fit into one input sequence in a transformer-model, and you have to split them into chunks.
+
+```c
+float many_vectors[10][dimensions];
+size_t count_retrieved = usearch_get(index, 42, 10, 
+    &many_vectors[0][0], usearch_scalar_f32_k, &error);
+assert(count_retrieved <= 10);
+```
+
+## Exact Search
+
+USearch exposes its internal SIMD-accelerated distance functions for exact search.
+To invoke them for a pair of vectors, use the following methods:
+
+```c
+float vector_a[dimensions], vector_b[dimensions];
+usearch_distance_t distance = usearch_distance(
+    &vector_a[0], &vector_b[0], usearch_scalar_f32_k, dimensions, usearch_metric_cos_k, &error);
+```
+
+Alternatively, you can benefir from faster thread-pools and priority queues for parallel exact batch-search.
 
 ```c
-usearch_error_t error = NULL;
-usearch_init_options_t opts = create_options(dimensions);
-usearch_index_t index = usearch_init(&opts, &error);
-usearch_reserve(index, vectors_count, &error);
+size_t threads = 0;
+size_t top_k = 10;
+size_t dataset_count = 1000, queries_count = 10;
+simsimd_f16_t dataset[dataset_count][dimensions];
+simsimd_f16_t queries[queries_count][dimensions];
 
-float vector[dimensions] = {...};
-usearch_add(index, 42, &vector[0], usearch_scalar_f32_k, &error);
+usearch_key_t resulting_keys[queries_count][top_k];
+usearch_distance_t resulting_distances[queries_count][top_k];
 
-ASSERT(!error, error);
-ASSERT(usearch_size(index, &error) == vectors_count, error);
-ASSERT(usearch_capacity(index, &error) == vectors_count, error);
+usearch_exact_search(
+    &dataset[0][0], dataset_count, dimensions * sizeof(simsimd_f16_t),
+    &queries[0][0], queries_count, dimensions * sizeof(simsimd_f16_t),
+    usearch_scalar_f16_k, top_k, threads,
+    &resulting_keys[0][0], sizeof(usearch_key_t) * top_k,
+    &resulting_distances[0][0], sizeof(usearch_distance_t) * top_k,
+    &error);
+```
+
+## Concurrency and Parallelism
 
-usearch_key_t found_keys[10];
-float found_distances[10];
-size_t found_count = usearch_search(index, &vector[0], usearch_scalar_f32_k, 10, &found_keys[0], &found_distances[0], &error);
+USearch manages a pool of "thread local" data-structures to avoid contention and improve performance.
+By default, as many of these structures are created as there are logical cores on the machine.
+Then, one can construct the index in parallel using many cores using third-party thread-pools or tools like OpenACC and OpenMP.
 
-usearch_free(index, &error);
+```c
+#pragma omp parallel for
+for (size_t i = 0; i < 1000; i++) {
+    usearch_add(index, i, &vector[0], usearch_scalar_f32_k, &error);
+}
+
+#pragma omp parallel for
+for (size_t i = 0; i < 1000; i++) {
+    usearch_key_t found_keys[10];
+    usearch_distance_t found_distances[10];
+    size_t found_matches = usearch_search(index, 
+        &vector[0], usearch_scalar_f32_k, 10, 
+        &found_keys[0], &found_distances[0], &error);
+}
 ```
+
+## Performance Tuning
+
+To optimize the performance of the index, you can adjust the expansion values used during index creation and search operations.
+Higher expansion values will lead to better search accuracy at the cost of slightly increased memory usage, but potentially much higher search times.
+Following methods are available to adjust the expansion values:
+
+```c
+printf("Connectivity: %zu\n", usearch_connectivity(index, &error)); // can't change
+printf("Add expansion: %zu\n", usearch_expansion_add(index, &error)); // can change
+printf("Search expansion: %zu\n", usearch_expansion_search(index, &error)); // can change
+usearch_change_expansion_add(index, 32, &error);
+usearch_change_expansion_search(index, 32, &error);
+```
+
+Optimizing hardware utilization, you may want to check the SIMD hardware acceleration capabilities of the index and memory consumption.
+The first will print the codename of the most advanced SIMD instruction set supported by the CPU and used by the index.
+The second will print the memory usage of the index in bytes.
+
+```c
+printf("Hardware acceleration: %s\n", usearch_hardware_acceleration(index, &error));
+printf("Memory usage: %zu\n", usearch_memory_usage(index, &error));
+```
+
diff --git a/c/lib.cpp b/c/lib.cpp
index a35acaa6..06d75ead 100644
--- a/c/lib.cpp
+++ b/c/lib.cpp
@@ -6,6 +6,13 @@ extern "C" {
 #include "usearch.h"
 }
 
+// Check if NDEBUG is defined to determine if it's a release build
+#ifdef NDEBUG
+#define USEARCH_ASSERT(expression) (void)(expression)
+#else
+#define USEARCH_ASSERT(expression) assert(expression)
+#endif
+
 using namespace unum::usearch;
 using namespace unum;
 
@@ -91,22 +98,38 @@ std::size_t get_(index_dense_t* index, usearch_key_t key, size_t count, void* ve
     }
 }
 
-search_result_t search_(index_dense_t* index, void const* vector, scalar_kind_t kind, size_t n) {
+template <typename predicate_at = dummy_predicate_t>
+search_result_t search_(index_dense_t* index, void const* vector, scalar_kind_t kind, size_t n,
+                        predicate_at&& predicate = predicate_at{}) {
     switch (kind) {
-    case scalar_kind_t::f32_k: return index->search((f32_t const*)vector, n);
-    case scalar_kind_t::f64_k: return index->search((f64_t const*)vector, n);
-    case scalar_kind_t::f16_k: return index->search((f16_t const*)vector, n);
-    case scalar_kind_t::i8_k: return index->search((i8_t const*)vector, n);
-    case scalar_kind_t::b1x8_k: return index->search((b1x8_t const*)vector, n);
+    case scalar_kind_t::f32_k:
+        return index->filtered_search((f32_t const*)vector, n, std::forward<predicate_at>(predicate));
+    case scalar_kind_t::f64_k:
+        return index->filtered_search((f64_t const*)vector, n, std::forward<predicate_at>(predicate));
+    case scalar_kind_t::f16_k:
+        return index->filtered_search((f16_t const*)vector, n, std::forward<predicate_at>(predicate));
+    case scalar_kind_t::i8_k:
+        return index->filtered_search((i8_t const*)vector, n, std::forward<predicate_at>(predicate));
+    case scalar_kind_t::b1x8_k:
+        return index->filtered_search((b1x8_t const*)vector, n, std::forward<predicate_at>(predicate));
     default: return search_result_t().failed("Unknown scalar kind!");
     }
 }
 
 extern "C" {
 
+USEARCH_EXPORT char const* usearch_version(void) {
+    int major = USEARCH_VERSION_MAJOR;
+    int minor = USEARCH_VERSION_MINOR;
+    int patch = USEARCH_VERSION_PATCH;
+    static char version[32];
+    sprintf(version, "%d.%d.%d", major, minor, patch);
+    return version;
+}
+
 USEARCH_EXPORT usearch_index_t usearch_init(usearch_init_options_t* options, usearch_error_t* error) {
 
-    assert(options && error && "Missing arguments");
+    USEARCH_ASSERT(options && error && "Missing arguments");
 
     index_dense_config_t config(options->connectivity, options->expansion_add, options->expansion_search);
     config.multi = options->multi;
@@ -114,11 +137,11 @@ USEARCH_EXPORT usearch_index_t usearch_init(usearch_init_options_t* options, use
     scalar_kind_t scalar_kind = scalar_kind_to_cpp(options->quantization);
 
     metric_punned_t metric = //
-        !options->metric ? metric_punned_t(options->dimensions, metric_kind, scalar_kind)
-                         : metric_punned_t(options->dimensions,                               //
-                                           reinterpret_cast<std::uintptr_t>(options->metric), //
-                                           metric_punned_signature_t::array_array_k,          //
-                                           metric_kind, scalar_kind);
+        !options->metric ? metric_punned_t::builtin(options->dimensions, metric_kind, scalar_kind)
+                         : metric_punned_t::stateless(options->dimensions,                               //
+                                                      reinterpret_cast<std::uintptr_t>(options->metric), //
+                                                      metric_punned_signature_t::array_array_k,          //
+                                                      metric_kind, scalar_kind);
     if (metric.missing()) {
         *error = "Unknown metric kind!";
         return NULL;
@@ -136,13 +159,13 @@ USEARCH_EXPORT void usearch_free(usearch_index_t index, usearch_error_t*) {
 }
 
 USEARCH_EXPORT size_t usearch_serialized_length(usearch_index_t index, usearch_error_t*) {
-    assert(index && "Missing arguments");
+    USEARCH_ASSERT(index && "Missing arguments");
     return reinterpret_cast<index_dense_t*>(index)->serialized_length();
 }
 
 USEARCH_EXPORT void usearch_save(usearch_index_t index, char const* path, usearch_error_t* error) {
 
-    assert(index && path && error && "Missing arguments");
+    USEARCH_ASSERT(index && path && error && "Missing arguments");
     serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->save(path);
     if (!result)
         *error = result.error.release();
@@ -150,7 +173,7 @@ USEARCH_EXPORT void usearch_save(usearch_index_t index, char const* path, usearc
 
 USEARCH_EXPORT void usearch_load(usearch_index_t index, char const* path, usearch_error_t* error) {
 
-    assert(index && path && error && "Missing arguments");
+    USEARCH_ASSERT(index && path && error && "Missing arguments");
     serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->load(path);
     if (!result)
         *error = result.error.release();
@@ -158,7 +181,7 @@ USEARCH_EXPORT void usearch_load(usearch_index_t index, char const* path, usearc
 
 USEARCH_EXPORT void usearch_view(usearch_index_t index, char const* path, usearch_error_t* error) {
 
-    assert(index && path && error && "Missing arguments");
+    USEARCH_ASSERT(index && path && error && "Missing arguments");
     serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->view(path);
     if (!result)
         *error = result.error.release();
@@ -166,7 +189,7 @@ USEARCH_EXPORT void usearch_view(usearch_index_t index, char const* path, usearc
 
 USEARCH_EXPORT void usearch_metadata(char const* path, usearch_init_options_t* options, usearch_error_t* error) {
 
-    assert(path && options && error && "Missing arguments");
+    USEARCH_ASSERT(path && options && error && "Missing arguments");
     index_dense_metadata_result_t result = index_dense_metadata_from_path(path);
     if (!result)
         *error = result.error.release();
@@ -184,7 +207,7 @@ USEARCH_EXPORT void usearch_metadata(char const* path, usearch_init_options_t* o
 
 USEARCH_EXPORT void usearch_save_buffer(usearch_index_t index, void* buffer, size_t length, usearch_error_t* error) {
 
-    assert(index && buffer && length && error && "Missing arguments");
+    USEARCH_ASSERT(index && buffer && length && error && "Missing arguments");
     memory_mapped_file_t memory_map((byte_t*)buffer, length);
     serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->save(std::move(memory_map));
     if (!result)
@@ -194,7 +217,7 @@ USEARCH_EXPORT void usearch_save_buffer(usearch_index_t index, void* buffer, siz
 USEARCH_EXPORT void usearch_load_buffer(usearch_index_t index, void const* buffer, size_t length,
                                         usearch_error_t* error) {
 
-    assert(index && buffer && length && error && "Missing arguments");
+    USEARCH_ASSERT(index && buffer && length && error && "Missing arguments");
     memory_mapped_file_t memory_map((byte_t*)buffer, length);
     serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->load(std::move(memory_map));
     if (!result)
@@ -204,7 +227,7 @@ USEARCH_EXPORT void usearch_load_buffer(usearch_index_t index, void const* buffe
 USEARCH_EXPORT void usearch_view_buffer(usearch_index_t index, void const* buffer, size_t length,
                                         usearch_error_t* error) {
 
-    assert(index && buffer && length && error && "Missing arguments");
+    USEARCH_ASSERT(index && buffer && length && error && "Missing arguments");
     memory_mapped_file_t memory_map((byte_t*)buffer, length);
     serialization_result_t result = reinterpret_cast<index_dense_t*>(index)->view(std::move(memory_map));
     if (!result)
@@ -214,7 +237,7 @@ USEARCH_EXPORT void usearch_view_buffer(usearch_index_t index, void const* buffe
 USEARCH_EXPORT void usearch_metadata_buffer(void const* buffer, size_t length, usearch_init_options_t* options,
                                             usearch_error_t* error) {
 
-    assert(buffer && length && options && error && "Missing arguments");
+    USEARCH_ASSERT(buffer && length && options && error && "Missing arguments");
     index_dense_metadata_result_t result =
         index_dense_metadata_from_buffer(memory_mapped_file_t((byte_t*)(buffer), length));
     if (!result)
@@ -231,24 +254,80 @@ USEARCH_EXPORT void usearch_metadata_buffer(void const* buffer, size_t length, u
     options->metric = NULL;
 }
 
-USEARCH_EXPORT size_t usearch_size(usearch_index_t index, usearch_error_t*) { //
+USEARCH_EXPORT size_t usearch_size(usearch_index_t index, usearch_error_t* error) {
+    USEARCH_ASSERT(index && error && "Missing arguments");
     return reinterpret_cast<index_dense_t*>(index)->size();
 }
 
-USEARCH_EXPORT size_t usearch_capacity(usearch_index_t index, usearch_error_t*) {
+USEARCH_EXPORT size_t usearch_capacity(usearch_index_t index, usearch_error_t* error) {
+    USEARCH_ASSERT(index && error && "Missing arguments");
     return reinterpret_cast<index_dense_t*>(index)->capacity();
 }
 
-USEARCH_EXPORT size_t usearch_dimensions(usearch_index_t index, usearch_error_t*) {
+USEARCH_EXPORT size_t usearch_dimensions(usearch_index_t index, usearch_error_t* error) {
+    USEARCH_ASSERT(index && error && "Missing arguments");
     return reinterpret_cast<index_dense_t*>(index)->dimensions();
 }
 
-USEARCH_EXPORT size_t usearch_connectivity(usearch_index_t index, usearch_error_t*) {
+USEARCH_EXPORT size_t usearch_connectivity(usearch_index_t index, usearch_error_t* error) {
+    USEARCH_ASSERT(index && error && "Missing arguments");
     return reinterpret_cast<index_dense_t*>(index)->connectivity();
 }
 
+USEARCH_EXPORT size_t usearch_expansion_add(usearch_index_t index, usearch_error_t* error) {
+    USEARCH_ASSERT(index && error && "Missing arguments");
+    return reinterpret_cast<index_dense_t*>(index)->expansion_add();
+}
+
+USEARCH_EXPORT size_t usearch_expansion_search(usearch_index_t index, usearch_error_t* error) {
+    USEARCH_ASSERT(index && error && "Missing arguments");
+    return reinterpret_cast<index_dense_t*>(index)->expansion_search();
+}
+
+USEARCH_EXPORT size_t usearch_memory_usage(usearch_index_t index, usearch_error_t* error) {
+    USEARCH_ASSERT(index && error && "Missing arguments");
+    return reinterpret_cast<index_dense_t*>(index)->memory_usage();
+}
+
+USEARCH_EXPORT char const* usearch_hardware_acceleration(usearch_index_t index, usearch_error_t* error) {
+    USEARCH_ASSERT(index && error && "Missing arguments");
+    return reinterpret_cast<index_dense_t*>(index)->metric().isa_name();
+}
+
+USEARCH_EXPORT void usearch_change_expansion_add(usearch_index_t index, size_t expansion, usearch_error_t* error) {
+    USEARCH_ASSERT(index && error && "Missing arguments");
+    reinterpret_cast<index_dense_t*>(index)->change_expansion_add(expansion);
+}
+
+USEARCH_EXPORT void usearch_change_expansion_search(usearch_index_t index, size_t expansion, usearch_error_t* error) {
+    USEARCH_ASSERT(index && error && "Missing arguments");
+    reinterpret_cast<index_dense_t*>(index)->change_expansion_search(expansion);
+}
+
+USEARCH_EXPORT void usearch_change_metric_kind(usearch_index_t index, usearch_metric_kind_t kind,
+                                               usearch_error_t* error) {
+    USEARCH_ASSERT(index && error && "Missing arguments");
+    auto& index_dense = *reinterpret_cast<index_dense_t*>(index);
+    index_dense.change_metric(
+        metric_punned_t::builtin(index_dense.dimensions(), metric_kind_to_cpp(kind), index_dense.scalar_kind()));
+}
+
+USEARCH_EXPORT void usearch_change_metric(usearch_index_t index, usearch_metric_t metric, void* state,
+                                          usearch_metric_kind_t kind, usearch_error_t* error) {
+    USEARCH_ASSERT(index && error && "Missing arguments");
+    auto& index_dense = *reinterpret_cast<index_dense_t*>(index);
+    auto metric_punned =
+        state ? metric_punned_t::statefull(reinterpret_cast<std::uintptr_t>(metric),
+                                           reinterpret_cast<std::uintptr_t>(state), metric_kind_to_cpp(kind),
+                                           index_dense.scalar_kind())
+              : metric_punned_t::stateless(index_dense.dimensions(), reinterpret_cast<std::uintptr_t>(metric),
+                                           metric_punned_signature_t::array_array_k, metric_kind_to_cpp(kind),
+                                           index_dense.scalar_kind());
+    index_dense.change_metric(std::move(metric_punned));
+}
+
 USEARCH_EXPORT void usearch_reserve(usearch_index_t index, size_t capacity, usearch_error_t* error) {
-    assert(index && error && "Missing arguments");
+    USEARCH_ASSERT(index && error && "Missing arguments");
     if (!reinterpret_cast<index_dense_t*>(index)->reserve(capacity))
         *error = "Out of memory!";
 }
@@ -257,29 +336,47 @@ USEARCH_EXPORT void usearch_add(
     usearch_index_t index, usearch_key_t key, void const* vector, usearch_scalar_kind_t kind, //
     usearch_error_t* error) {
 
-    assert(index && vector && error && "Missing arguments");
+    USEARCH_ASSERT(index && vector && error && "Missing arguments");
     add_result_t result = add_(reinterpret_cast<index_dense_t*>(index), key, vector, scalar_kind_to_cpp(kind));
     if (!result)
         *error = result.error.release();
 }
 
 USEARCH_EXPORT bool usearch_contains(usearch_index_t index, usearch_key_t key, usearch_error_t*) {
-    assert(index && "Missing arguments");
+    USEARCH_ASSERT(index && "Missing arguments");
     return reinterpret_cast<index_dense_t*>(index)->contains(key);
 }
 
 USEARCH_EXPORT size_t usearch_count(usearch_index_t index, usearch_key_t key, usearch_error_t*) {
-    assert(index && "Missing arguments");
+    USEARCH_ASSERT(index && "Missing arguments");
     return reinterpret_cast<index_dense_t*>(index)->count(key);
 }
 
-USEARCH_EXPORT size_t usearch_search(                                                            //
-    usearch_index_t index, void const* vector, usearch_scalar_kind_t kind, size_t results_limit, //
+USEARCH_EXPORT size_t usearch_search(                                                                 //
+    usearch_index_t index, void const* query, usearch_scalar_kind_t query_kind, size_t results_limit, //
+    usearch_key_t* found_keys, usearch_distance_t* found_distances, usearch_error_t* error) {
+
+    USEARCH_ASSERT(index && query && error && "Missing arguments");
+    search_result_t result =
+        search_(reinterpret_cast<index_dense_t*>(index), query, scalar_kind_to_cpp(query_kind), results_limit);
+    if (!result) {
+        *error = result.error.release();
+        return 0;
+    }
+
+    return result.dump_to(found_keys, found_distances);
+}
+
+USEARCH_EXPORT size_t usearch_filtered_search(                                 //
+    usearch_index_t index,                                                     //
+    void const* query, usearch_scalar_kind_t query_kind, size_t results_limit, //
+    int (*filter)(usearch_key_t key, void* filter_state), void* filter_state,  //
     usearch_key_t* found_keys, usearch_distance_t* found_distances, usearch_error_t* error) {
 
-    assert(index && vector && error && "Missing arguments");
+    USEARCH_ASSERT(index && query && filter && error && "Missing arguments");
     search_result_t result =
-        search_(reinterpret_cast<index_dense_t*>(index), vector, scalar_kind_to_cpp(kind), results_limit);
+        search_(reinterpret_cast<index_dense_t*>(index), query, scalar_kind_to_cpp(query_kind), results_limit,
+                [=](usearch_key_t key) noexcept { return filter(key, filter_state); });
     if (!result) {
         *error = result.error.release();
         return 0;
@@ -292,13 +389,13 @@ USEARCH_EXPORT size_t usearch_get(                          //
     usearch_index_t index, usearch_key_t key, size_t count, //
     void* vectors, usearch_scalar_kind_t kind, usearch_error_t*) {
 
-    assert(index && vectors);
+    USEARCH_ASSERT(index && vectors);
     return get_(reinterpret_cast<index_dense_t*>(index), key, count, vectors, scalar_kind_to_cpp(kind));
 }
 
 USEARCH_EXPORT size_t usearch_remove(usearch_index_t index, usearch_key_t key, usearch_error_t* error) {
 
-    assert(index && error && "Missing arguments");
+    USEARCH_ASSERT(index && error && "Missing arguments");
     labeling_result_t result = reinterpret_cast<index_dense_t*>(index)->remove(key);
     if (!result)
         *error = result.error.release();
@@ -308,7 +405,7 @@ USEARCH_EXPORT size_t usearch_remove(usearch_index_t index, usearch_key_t key, u
 USEARCH_EXPORT size_t usearch_rename( //
     usearch_index_t index, usearch_key_t from, usearch_key_t to, usearch_error_t* error) {
 
-    assert(index && error && "Missing arguments");
+    USEARCH_ASSERT(index && error && "Missing arguments");
     labeling_result_t result = reinterpret_cast<index_dense_t*>(index)->rename(from, to);
     if (!result)
         *error = result.error.release();
@@ -334,7 +431,7 @@ USEARCH_EXPORT void usearch_exact_search(                             //
     usearch_distance_t* distances, size_t distances_stride,           //
     usearch_error_t* error) {
 
-    assert(dataset && queries && keys && distances && error && "Missing arguments");
+    USEARCH_ASSERT(dataset && queries && keys && distances && error && "Missing arguments");
 
     metric_punned_t metric(dimensions, metric_kind_to_cpp(metric_kind), scalar_kind_to_cpp(scalar_kind));
     executor_default_t executor(threads);
diff --git a/c/usearch.h b/c/usearch.h
index e5f9f2ba..5632aa44 100644
--- a/c/usearch.h
+++ b/c/usearch.h
@@ -97,6 +97,12 @@ USEARCH_EXPORT typedef struct usearch_init_options_t {
     bool multi;
 } usearch_init_options_t;
 
+/**
+ *  @brief Retrieves the version of the library.
+ *  @return The version of the library.
+ */
+USEARCH_EXPORT char const* usearch_version(void);
+
 /**
  *  @brief Initializes a new instance of the index.
  *  @param options Pointer to the `usearch_init_options_t` structure containing initialization options.
@@ -112,6 +118,22 @@ USEARCH_EXPORT usearch_index_t usearch_init(usearch_init_options_t* options, use
  */
 USEARCH_EXPORT void usearch_free(usearch_index_t index, usearch_error_t* error);
 
+/**
+ *  @brief Reports the memory usage of the index.
+ *  @param[in] index The handle to the USearch index to be queried.
+ *  @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
+ *  @return Number of bytes used by the index.
+ */
+USEARCH_EXPORT size_t usearch_memory_usage(usearch_index_t index, usearch_error_t* error);
+
+/**
+ *  @brief Reports the SIMD capabilities used by the index on the current CPU.
+ *  @param[in] index The handle to the USearch index to be queried.
+ *  @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
+ *  @return The codename of the SIMD instruction set used by the index.
+ */
+USEARCH_EXPORT char const* usearch_hardware_acceleration(usearch_index_t index, usearch_error_t* error);
+
 /**
  *  @brief Reports expected file size after serialization.
  *  @param[in] index The handle to the USearch index to be serialized.
@@ -227,6 +249,58 @@ USEARCH_EXPORT size_t usearch_connectivity(usearch_index_t index, usearch_error_
  */
 USEARCH_EXPORT void usearch_reserve(usearch_index_t index, size_t capacity, usearch_error_t* error);
 
+/**
+ *  @brief Retrieves the expansion value used during index creation.
+ *  @param[in] index The handle to the USearch index to be queried.
+ *  @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
+ *  @return The expansion value used during index creation.
+ */
+USEARCH_EXPORT size_t usearch_expansion_add(usearch_index_t index, usearch_error_t* error);
+
+/**
+ *  @brief Retrieves the expansion value used during search.
+ *  @param[in] index The handle to the USearch index to be queried.
+ *  @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
+ *  @return The expansion value used during search.
+ */
+USEARCH_EXPORT size_t usearch_expansion_search(usearch_index_t index, usearch_error_t* error);
+
+/**
+ *  @brief Updates the expansion value used during index creation. Rarely used.
+ *  @param[in] index The handle to the USearch index to be queried.
+ *  @param[in] expansion The new expansion value.
+ *  @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
+ */
+USEARCH_EXPORT void usearch_change_expansion_add(usearch_index_t index, size_t expansion, usearch_error_t* error);
+
+/**
+ *  @brief Updates the expansion value used during search. Rarely used.
+ *  @param[in] index The handle to the USearch index to be queried.
+ *  @param[in] expansion The new expansion value.
+ *  @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
+ */
+USEARCH_EXPORT void usearch_change_expansion_search(usearch_index_t index, size_t expansion, usearch_error_t* error);
+
+/**
+ *  @brief Updates the metric kind used for distance calculation between vectors.
+ *  @param[in] index The handle to the USearch index to be queried.
+ *  @param[in] kind The metric kind used for distance calculation between vectors.
+ *  @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
+ */
+USEARCH_EXPORT void usearch_change_metric_kind(usearch_index_t index, usearch_metric_kind_t kind,
+                                               usearch_error_t* error);
+
+/**
+ *  @brief Updates the custom metric function used for distance calculation between vectors.
+ *  @param[in] index The handle to the USearch index to be queried.
+ *  @param[in] metric The custom metric function used for distance calculation between vectors.
+ *  @param[in] state The @b optional state pointer to be passed to the custom metric function.
+ *  @param[in] kind The metric kind used for distance calculation between vectors. Needed for serialization.
+ *  @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
+ */
+USEARCH_EXPORT void usearch_change_metric(usearch_index_t index, usearch_metric_t metric, void* state,
+                                          usearch_metric_kind_t kind, usearch_error_t* error);
+
 /**
  *  @brief Adds a vector with a key to the index.
  *  @param[inout] index The handle to the USearch index to be populated.
@@ -268,10 +342,31 @@ USEARCH_EXPORT size_t usearch_count(usearch_index_t index, usearch_key_t, usearc
  *  @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
  *  @return Number of found matches.
  */
-USEARCH_EXPORT size_t usearch_search(                           //
-    usearch_index_t index,                                      //
-    void const* query_vector, usearch_scalar_kind_t query_kind, //
-    size_t count, usearch_key_t* keys, usearch_distance_t* distances, usearch_error_t* error);
+USEARCH_EXPORT size_t usearch_search(                                         //
+    usearch_index_t index,                                                    //
+    void const* query_vector, usearch_scalar_kind_t query_kind, size_t count, //
+    usearch_key_t* keys, usearch_distance_t* distances, usearch_error_t* error);
+
+/**
+ *  @brief  Performs k-Approximate Nearest Neighbors (kANN) Search for closest vectors to query,
+ *          predicated on a custom function that returns `true` for vectors to be included.
+ *
+ *  @param[in] index The handle to the USearch index to be queried.
+ *  @param[in] query_vector Pointer to the query vector data.
+ *  @param[in] query_kind The scalar type used in the query vector data.
+ *  @param[in] count Upper bound on the number of neighbors to search, the "k" in "kANN".
+ *  @param[in] filter The custom filter function that returns `true` for vectors to be included.
+ *  @param[in] filter_state The @b optional state pointer to be passed to the custom filter function.
+ *  @param[out] keys Output buffer for up to `count` nearest neighbors keys.
+ *  @param[out] distances Output buffer for up to `count` distances to nearest neighbors.
+ *  @param[out] error Pointer to a string where the error message will be stored, if an error occurs.
+ *  @return Number of found matches.
+ */
+USEARCH_EXPORT size_t usearch_filtered_search(                                //
+    usearch_index_t index,                                                    //
+    void const* query_vector, usearch_scalar_kind_t query_kind, size_t count, //
+    int (*filter)(usearch_key_t key, void* filter_state), void* filter_state, //
+    usearch_key_t* keys, usearch_distance_t* distances, usearch_error_t* error);
 
 /**
  *  @brief Retrieves the vector associated with the given key from the index.
diff --git a/include/usearch/index.hpp b/include/usearch/index.hpp
index 746dc131..dd939d98 100644
--- a/include/usearch/index.hpp
+++ b/include/usearch/index.hpp
@@ -3497,9 +3497,12 @@ class index_gt {
 
         distance_t radius = context.measure(query, citerator_at(start_slot), metric);
         next.insert_reserved({-radius, static_cast<compressed_slot_t>(start_slot)});
-        top.insert_reserved({radius, static_cast<compressed_slot_t>(start_slot)});
         visits.set(static_cast<compressed_slot_t>(start_slot));
 
+        // Don't populate the top list if the predicate is not satisfied
+        if (is_dummy<predicate_at>() || predicate(member_cref_t{node_at_(start_slot).ckey(), start_slot}))
+            top.insert_reserved({radius, static_cast<compressed_slot_t>(start_slot)});
+
         while (!next.empty()) {
 
             candidate_t candidate = next.top();
@@ -3529,12 +3532,9 @@ class index_gt {
                 if (top.size() < top_limit || successor_dist < radius) {
                     // This can substantially grow our priority queue:
                     next.insert({-successor_dist, successor_slot});
-                    if (!is_dummy<predicate_at>())
-                        if (!predicate(member_cref_t{node_at_(successor_slot).ckey(), successor_slot}))
-                            continue;
-
-                    // This will automatically evict poor matches:
-                    top.insert({successor_dist, successor_slot}, top_limit);
+                    if (is_dummy<predicate_at>() ||
+                        predicate(member_cref_t{node_at_(successor_slot).ckey(), successor_slot}))
+                        top.insert({successor_dist, successor_slot}, top_limit);
                     radius = top.top().distance;
                 }
             }
diff --git a/include/usearch/index_dense.hpp b/include/usearch/index_dense.hpp
index 95dbb68e..58851829 100644
--- a/include/usearch/index_dense.hpp
+++ b/include/usearch/index_dense.hpp
@@ -604,11 +604,17 @@ class index_dense_gt {
     add_result_t add(vector_key_t key, f32_t const* vector, std::size_t thread = any_thread(), bool force_vector_copy = true) { return add_(key, vector, thread, force_vector_copy, casts_.from_f32); }
     add_result_t add(vector_key_t key, f64_t const* vector, std::size_t thread = any_thread(), bool force_vector_copy = true) { return add_(key, vector, thread, force_vector_copy, casts_.from_f64); }
 
-    search_result_t search(b1x8_t const* vector, std::size_t wanted, std::size_t thread = any_thread(), bool exact = false) const { return search_(vector, wanted, thread, exact, casts_.from_b1x8); }
-    search_result_t search(i8_t const* vector, std::size_t wanted, std::size_t thread = any_thread(), bool exact = false) const { return search_(vector, wanted, thread, exact, casts_.from_i8); }
-    search_result_t search(f16_t const* vector, std::size_t wanted, std::size_t thread = any_thread(), bool exact = false) const { return search_(vector, wanted, thread, exact, casts_.from_f16); }
-    search_result_t search(f32_t const* vector, std::size_t wanted, std::size_t thread = any_thread(), bool exact = false) const { return search_(vector, wanted, thread, exact, casts_.from_f32); }
-    search_result_t search(f64_t const* vector, std::size_t wanted, std::size_t thread = any_thread(), bool exact = false) const { return search_(vector, wanted, thread, exact, casts_.from_f64); }
+    search_result_t search(b1x8_t const* vector, std::size_t wanted, std::size_t thread = any_thread(), bool exact = false) const { return search_(vector, wanted, dummy_predicate_t {}, thread, exact, casts_.from_b1x8); }
+    search_result_t search(i8_t const* vector, std::size_t wanted, std::size_t thread = any_thread(), bool exact = false) const { return search_(vector, wanted, dummy_predicate_t {}, thread, exact, casts_.from_i8); }
+    search_result_t search(f16_t const* vector, std::size_t wanted, std::size_t thread = any_thread(), bool exact = false) const { return search_(vector, wanted, dummy_predicate_t {}, thread, exact, casts_.from_f16); }
+    search_result_t search(f32_t const* vector, std::size_t wanted, std::size_t thread = any_thread(), bool exact = false) const { return search_(vector, wanted, dummy_predicate_t {}, thread, exact, casts_.from_f32); }
+    search_result_t search(f64_t const* vector, std::size_t wanted, std::size_t thread = any_thread(), bool exact = false) const { return search_(vector, wanted, dummy_predicate_t {}, thread, exact, casts_.from_f64); }
+
+    template <typename predicate_at> search_result_t filtered_search(b1x8_t const* vector, std::size_t wanted, predicate_at&& predicate, std::size_t thread = any_thread(), bool exact = false) const { return search_(vector, wanted, std::forward<predicate_at>(predicate), thread, exact, casts_.from_b1x8); }
+    template <typename predicate_at> search_result_t filtered_search(i8_t const* vector, std::size_t wanted, predicate_at&& predicate, std::size_t thread = any_thread(), bool exact = false) const { return search_(vector, wanted, std::forward<predicate_at>(predicate), thread, exact, casts_.from_i8); }
+    template <typename predicate_at> search_result_t filtered_search(f16_t const* vector, std::size_t wanted, predicate_at&& predicate, std::size_t thread = any_thread(), bool exact = false) const { return search_(vector, wanted, std::forward<predicate_at>(predicate), thread, exact, casts_.from_f16); }
+    template <typename predicate_at> search_result_t filtered_search(f32_t const* vector, std::size_t wanted, predicate_at&& predicate, std::size_t thread = any_thread(), bool exact = false) const { return search_(vector, wanted, std::forward<predicate_at>(predicate), thread, exact, casts_.from_f32); }
+    template <typename predicate_at> search_result_t filtered_search(f64_t const* vector, std::size_t wanted, predicate_at&& predicate, std::size_t thread = any_thread(), bool exact = false) const { return search_(vector, wanted, std::forward<predicate_at>(predicate), thread, exact, casts_.from_f64); }
 
     std::size_t get(vector_key_t key, b1x8_t* vector, std::size_t vectors_count = 1) const { return get_(key, vector, vectors_count, casts_.to_b1x8); }
     std::size_t get(vector_key_t key, i8_t* vector, std::size_t vectors_count = 1) const { return get_(key, vector, vectors_count, casts_.to_i8); }
@@ -708,7 +714,9 @@ class index_dense_gt {
         cluster_config.thread = lock.thread_id;
         cluster_config.expansion = config_.expansion_search;
         metric_proxy_t metric{*this};
-        auto allow = [=](member_cref_t const& member) noexcept { return member.key != free_key_; };
+        auto allow = [free_key_ = this->free_key_](member_cref_t const& member) noexcept {
+            return member.key != free_key_;
+        };
 
         // Find the closest cluster for any vector under that key.
         while (key_range.first != key_range.second) {
@@ -930,7 +938,7 @@ class index_dense_gt {
                 return result.failed("Slot type doesn't match, consider rebuilding");
 
             config_.multi = head.multi;
-            metric_ = metric_t(head.dimensions, head.kind_metric, head.kind_scalar);
+            metric_ = metric_t::builtin(head.dimensions, head.kind_metric, head.kind_scalar);
             cast_buffer_.resize(available_threads_.size() * metric_.bytes_per_vector());
             casts_ = make_casts_(head.kind_scalar);
         }
@@ -1016,7 +1024,7 @@ class index_dense_gt {
                 return result.failed("Slot type doesn't match, consider rebuilding");
 
             config_.multi = head.multi;
-            metric_ = metric_t(head.dimensions, head.kind_metric, head.kind_scalar);
+            metric_ = metric_t::builtin(head.dimensions, head.kind_metric, head.kind_scalar);
             cast_buffer_.resize(available_threads_.size() * metric_.bytes_per_vector());
             casts_ = make_casts_(head.kind_scalar);
             offset += sizeof(buffer);
@@ -1767,10 +1775,9 @@ class index_dense_gt {
                    : typed_->add(key, vector_data, metric, update_config, on_success);
     }
 
-    template <typename scalar_at>
-    search_result_t search_(                         //
-        scalar_at const* vector, std::size_t wanted, //
-        std::size_t thread, bool exact, cast_t const& cast) const {
+    template <typename scalar_at, typename predicate_at>
+    search_result_t search_(scalar_at const* vector, std::size_t wanted, predicate_at&& predicate, std::size_t thread,
+                            bool exact, cast_t const& cast) const {
 
         // Cast the vector, if needed for compatibility with `metric_`
         thread_lock_t lock = thread_lock_(thread);
@@ -1787,8 +1794,17 @@ class index_dense_gt {
         search_config.expansion = config_.expansion_search;
         search_config.exact = exact;
 
-        auto allow = [=](member_cref_t const& member) noexcept { return member.key != free_key_; };
-        return typed_->search(vector_data, wanted, metric_proxy_t{*this}, search_config, allow);
+        if (std::is_same<typename std::decay<predicate_at>::type, dummy_predicate_t>::value) {
+            auto allow = [free_key_ = this->free_key_](member_cref_t const& member) noexcept {
+                return member.key != free_key_;
+            };
+            return typed_->search(vector_data, wanted, metric_proxy_t{*this}, search_config, allow);
+        } else {
+            auto allow = [free_key_ = this->free_key_, &predicate](member_cref_t const& member) noexcept {
+                return member.key != free_key_ && predicate(member.key);
+            };
+            return typed_->search(vector_data, wanted, metric_proxy_t{*this}, search_config, allow);
+        }
     }
 
     template <typename scalar_at>
@@ -1810,7 +1826,9 @@ class index_dense_gt {
         cluster_config.thread = lock.thread_id;
         cluster_config.expansion = config_.expansion_search;
 
-        auto allow = [=](member_cref_t const& member) noexcept { return member.key != free_key_; };
+        auto allow = [free_key_ = this->free_key_](member_cref_t const& member) noexcept {
+            return member.key != free_key_;
+        };
         return typed_->cluster(vector_data, level, metric_proxy_t{*this}, cluster_config, allow);
     }
 
diff --git a/include/usearch/index_plugins.hpp b/include/usearch/index_plugins.hpp
index b3ad5edf..a5539a3a 100644
--- a/include/usearch/index_plugins.hpp
+++ b/include/usearch/index_plugins.hpp
@@ -1320,6 +1320,7 @@ using span_punned_t = span_gt<byte_t const>;
 enum class metric_punned_signature_t {
     array_array_k = 0,
     array_array_size_k,
+    array_array_state_k,
 };
 
 /**
@@ -1339,12 +1340,14 @@ class metric_punned_t {
     using metric_array_array_t = result_t (*)(uptr_t, uptr_t);
     /// Distance function that takes two arrays and their length and returns a scalar.
     using metric_array_array_size_t = result_t (*)(uptr_t, uptr_t, uptr_t);
+    /// Distance function that takes two arrays and some callback state and returns a scalar.
+    using metric_array_array_state_t = result_t (*)(uptr_t, uptr_t, uptr_t);
     /// Distance function callback, like `metric_array_array_size_t`, but depends on member variables.
     using metric_rounted_t = result_t (metric_punned_t::*)(uptr_t, uptr_t) const;
 
     metric_rounted_t metric_routed_ = nullptr;
     uptr_t metric_ptr_ = 0;
-    uptr_t metric_size_arg_ = 0;
+    uptr_t metric_third_arg_ = 0;
 
     std::size_t dimensions_ = 0;
     metric_kind_t metric_kind_ = metric_kind_t::unknown_k;
@@ -1367,37 +1370,95 @@ class metric_punned_t {
     inline metric_punned_t() noexcept = default;
     inline metric_punned_t(metric_punned_t const&) noexcept = default;
     inline metric_punned_t& operator=(metric_punned_t const&) noexcept = default;
-    inline metric_punned_t(                                //
-        std::size_t dimensions,                            //
-        metric_kind_t metric_kind = metric_kind_t::l2sq_k, //
-        scalar_kind_t scalar_kind = scalar_kind_t::f32_k) noexcept
-        : metric_routed_(&metric_punned_t::invoke_array_array_size), metric_size_arg_(dimensions),
-          dimensions_(dimensions), metric_kind_(metric_kind), scalar_kind_(scalar_kind) {
+
+    inline metric_punned_t(std::size_t dimensions, metric_kind_t metric_kind = metric_kind_t::l2sq_k,
+                           scalar_kind_t scalar_kind = scalar_kind_t::f32_k) noexcept
+        : metric_punned_t(builtin(dimensions, metric_kind, scalar_kind)) {}
+
+    inline metric_punned_t(std::size_t dimensions, std::uintptr_t metric_uintptr, metric_punned_signature_t signature,
+                           metric_kind_t metric_kind, scalar_kind_t scalar_kind) noexcept
+        : metric_punned_t(stateless(dimensions, metric_uintptr, signature, metric_kind, scalar_kind)) {}
+
+    /**
+     *  @brief  Creates a metric of a natively supported kind, choosing the best
+     *          available backend internally or from SimSIMD.
+     *
+     *  @param  dimensions      The number of elements in the input arrays.
+     *  @param  metric_kind     The kind of metric to use.
+     *  @param  scalar_kind     The kind of scalar to use.
+     *  @return                 A metric object that can be used to compute distances between vectors.
+     */
+    inline static metric_punned_t builtin(std::size_t dimensions, metric_kind_t metric_kind = metric_kind_t::l2sq_k,
+                                          scalar_kind_t scalar_kind = scalar_kind_t::f32_k) noexcept {
+        metric_punned_t metric;
+        metric.metric_routed_ = &metric_punned_t::invoke_array_array_third;
+        metric.metric_ptr_ = 0;
+        metric.metric_third_arg_ =
+            scalar_kind == scalar_kind_t::b1x8_k ? divide_round_up<CHAR_BIT>(dimensions) : dimensions;
+        metric.dimensions_ = dimensions;
+        metric.metric_kind_ = metric_kind;
+        metric.scalar_kind_ = scalar_kind;
 
 #if USEARCH_USE_SIMSIMD
-        if (!configure_with_simsimd())
-            configure_with_autovec();
+        if (!metric.configure_with_simsimd())
+            metric.configure_with_autovec();
 #else
-        configure_with_autovec();
+        metric.configure_with_autovec();
 #endif
 
-        if (scalar_kind == scalar_kind_t::b1x8_k)
-            metric_size_arg_ = divide_round_up<CHAR_BIT>(dimensions_);
+        return metric;
     }
 
-    inline metric_punned_t(                                                 //
-        std::size_t dimensions,                                             //
-        std::uintptr_t metric_uintptr, metric_punned_signature_t signature, //
-        metric_kind_t metric_kind,                                          //
-        scalar_kind_t scalar_kind) noexcept
-        : metric_routed_(signature == metric_punned_signature_t::array_array_k
-                             ? &metric_punned_t::invoke_array_array
-                             : &metric_punned_t::invoke_array_array_size),
-          metric_ptr_(metric_uintptr), metric_size_arg_(dimensions), dimensions_(dimensions), metric_kind_(metric_kind),
-          scalar_kind_(scalar_kind) {
+    /**
+     *  @brief  Creates a metric using the provided function pointer for a stateless metric.
+     *          So the provided ::metric_uintptr is a pointer to a function that takes two arrays
+     *          and returns a scalar. If the ::signature is metric_punned_signature_t::array_array_size_k,
+     *          then the third argument is the number of scalar words in the input vectors.
+     *
+     *  @param  dimensions      The number of elements in the input arrays.
+     *  @param  metric_uintptr  The function pointer to the metric function.
+     *  @param  signature       The signature of the metric function.
+     *  @param  metric_kind     The kind of metric to use.
+     *  @param  scalar_kind     The kind of scalar to use.
+     *  @return                 A metric object that can be used to compute distances between vectors.
+     */
+    inline static metric_punned_t stateless(std::size_t dimensions, std::uintptr_t metric_uintptr,
+                                            metric_punned_signature_t signature, metric_kind_t metric_kind,
+                                            scalar_kind_t scalar_kind) noexcept {
+        metric_punned_t metric;
+        metric.metric_routed_ = signature == metric_punned_signature_t::array_array_k
+                                    ? &metric_punned_t::invoke_array_array
+                                    : &metric_punned_t::invoke_array_array_third;
+        metric.metric_ptr_ = metric_uintptr;
+        metric.metric_third_arg_ =
+            scalar_kind == scalar_kind_t::b1x8_k ? divide_round_up<CHAR_BIT>(dimensions) : dimensions;
+        metric.dimensions_ = dimensions;
+        metric.metric_kind_ = metric_kind;
+        metric.scalar_kind_ = scalar_kind;
+        return metric;
+    }
 
-        if (scalar_kind == scalar_kind_t::b1x8_k)
-            metric_size_arg_ = divide_round_up<CHAR_BIT>(dimensions_);
+    /**
+     *  @brief  Creates a metric using the provided function pointer for a statefull metric.
+     *          The third argument is the state that will be passed to the metric function.
+     *
+     *  @param  metric_uintptr  The function pointer to the metric function.
+     *  @param  metric_state    The state to pass to the metric function.
+     *  @param  metric_kind     The kind of metric to use.
+     *  @param  scalar_kind     The kind of scalar to use.
+     *  @return                 A metric object that can be used to compute distances between vectors.
+     */
+    inline static metric_punned_t statefull(std::uintptr_t metric_uintptr, std::uintptr_t metric_state,
+                                            metric_kind_t metric_kind = metric_kind_t::unknown_k,
+                                            scalar_kind_t scalar_kind = scalar_kind_t::unknown_k) noexcept {
+        metric_punned_t metric;
+        metric.metric_routed_ = &metric_punned_t::invoke_array_array_third;
+        metric.metric_ptr_ = metric_uintptr;
+        metric.metric_third_arg_ = metric_state;
+        metric.dimensions_ = 0;
+        metric.metric_kind_ = metric_kind;
+        metric.scalar_kind_ = scalar_kind;
+        return metric;
     }
 
     inline std::size_t dimensions() const noexcept { return dimensions_; }
@@ -1485,16 +1546,17 @@ class metric_punned_t {
         simsimd_distance_t result;
         // Here `reinterpret_cast` raises warning... we know what we are doing!
         auto function_pointer = (simsimd_metric_punned_t)(metric_ptr_);
-        function_pointer(reinterpret_cast<void const*>(a), reinterpret_cast<void const*>(b), metric_size_arg_, &result);
+        function_pointer(reinterpret_cast<void const*>(a), reinterpret_cast<void const*>(b), metric_third_arg_,
+                         &result);
         return (result_t)result;
     }
     result_t invoke_simsimd_reverse(uptr_t a, uptr_t b) const noexcept { return 1 - invoke_simsimd(a, b); }
 #else
     bool configure_with_simsimd() noexcept { return false; }
 #endif
-    result_t invoke_array_array_size(uptr_t a, uptr_t b) const noexcept {
+    result_t invoke_array_array_third(uptr_t a, uptr_t b) const noexcept {
         auto function_pointer = (metric_array_array_size_t)(metric_ptr_);
-        result_t result = function_pointer(a, b, metric_size_arg_);
+        result_t result = function_pointer(a, b, metric_third_arg_);
         return result;
     }
     result_t invoke_array_array(uptr_t a, uptr_t b) const noexcept {
diff --git a/javascript/usearch.ts b/javascript/usearch.ts
index 33f9f638..2e7ee1e7 100644
--- a/javascript/usearch.ts
+++ b/javascript/usearch.ts
@@ -1,6 +1,6 @@
 import build from "node-gyp-build";
-import * as path from "node:path";
-import { existsSync } from "node:fs";
+import * as path from "path";
+import { existsSync } from "fs";
 import { getFileName, getRoot } from "bindings";
 
 const compiled: Compiled = build(getBuildDir(getDirName()));
diff --git a/package-lock.json b/package-lock.json
index 3a95d8cc..43681b21 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,25 +1,25 @@
 {
     "name": "usearch",
-    "version": "2.9.2",
+    "version": "2.10.5",
     "lockfileVersion": 3,
     "requires": true,
     "packages": {
         "": {
             "name": "usearch",
-            "version": "2.9.2",
+            "version": "2.10.5",
             "hasInstallScript": true,
             "license": "Apache 2.0",
             "dependencies": {
                 "bindings": "^1.5.0",
-                "node-addon-api": "^3.0.0",
+                "node-addon-api": "^8.0.0",
                 "node-gyp-build": "^4.8.0"
             },
             "devDependencies": {
                 "@types/bindings": "^1.5.5",
-                "@types/node": "^20.11.0",
-                "node-gyp": "^10.0.1",
+                "@types/node": "^20.12.4",
+                "node-gyp": "^10.1.0",
                 "prebuildify": "^6.0.0",
-                "typescript": "^5.3.3"
+                "typescript": "^5.4.4"
             },
             "engines": {
                 "node": "~10 >=10.20 || >=12.17"
@@ -99,9 +99,9 @@
             }
         },
         "node_modules/@types/node": {
-            "version": "20.11.0",
-            "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.0.tgz",
-            "integrity": "sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==",
+            "version": "20.12.4",
+            "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.4.tgz",
+            "integrity": "sha512-E+Fa9z3wSQpzgYQdYmme5X3OTuejnnTx88A6p6vkkJosR3KBz+HpE3kqNm98VE6cfLFcISx7zW7MsJkH6KwbTw==",
             "dev": true,
             "dependencies": {
                 "undici-types": "~5.26.4"
@@ -864,14 +864,17 @@
             }
         },
         "node_modules/node-addon-api": {
-            "version": "3.2.1",
-            "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
-            "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A=="
+            "version": "8.0.0",
+            "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.0.0.tgz",
+            "integrity": "sha512-ipO7rsHEBqa9STO5C5T10fj732ml+5kLN1cAG8/jdHd56ldQeGj3Q7+scUS+VHK/qy1zLEwC4wMK5+yM0btPvw==",
+            "engines": {
+                "node": "^18 || ^20 || >= 21"
+            }
         },
         "node_modules/node-gyp": {
-            "version": "10.0.1",
-            "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz",
-            "integrity": "sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==",
+            "version": "10.1.0",
+            "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.1.0.tgz",
+            "integrity": "sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==",
             "dev": true,
             "dependencies": {
                 "env-paths": "^2.2.0",
@@ -1378,9 +1381,9 @@
             }
         },
         "node_modules/typescript": {
-            "version": "5.3.3",
-            "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
-            "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
+            "version": "5.4.4",
+            "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz",
+            "integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==",
             "dev": true,
             "bin": {
                 "tsc": "bin/tsc",
diff --git a/package.json b/package.json
index f74b488a..9434db4e 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,7 @@
     ],
     "dependencies": {
         "bindings": "^1.5.0",
-        "node-addon-api": "^3.0.0",
+        "node-addon-api": "^8.0.0",
         "node-gyp-build": "^4.8.0"
     },
     "scripts": {
@@ -42,10 +42,10 @@
     },
     "devDependencies": {
         "@types/bindings": "^1.5.5",
-        "@types/node": "^20.11.0",
-        "node-gyp": "^10.0.1",
+        "@types/node": "^20.12.4",
+        "node-gyp": "^10.1.0",
         "prebuildify": "^6.0.0",
-        "typescript": "^5.3.3"
+        "typescript": "^5.4.4"
     },
     "main": "javascript/dist/cjs/usearch.js",
     "module": "javascript/dist/esm/usearch.js",
diff --git a/python/lib.cpp b/python/lib.cpp
index 17413cff..66756a51 100644
--- a/python/lib.cpp
+++ b/python/lib.cpp
@@ -120,8 +120,8 @@ static dense_index_py_t make_index(             //
 
     metric_t metric =  //
         metric_uintptr //
-            ? metric_t(dimensions, metric_uintptr, metric_signature, metric_kind, scalar_kind)
-            : metric_t(dimensions, metric_kind, scalar_kind);
+            ? metric_t::stateless(dimensions, metric_uintptr, metric_signature, metric_kind, scalar_kind)
+            : metric_t::builtin(dimensions, metric_kind, scalar_kind);
     if (metric.missing())
         throw std::invalid_argument("Unsupported metric!");
 
@@ -486,8 +486,8 @@ static py::tuple search_many_brute_force(       //
     std::size_t dimensions = static_cast<std::size_t>(queries_dimensions);
     metric_t metric =  //
         metric_uintptr //
-            ? metric_t(dimensions, metric_uintptr, metric_signature, metric_kind, queries_kind)
-            : metric_t(dimensions, metric_kind, queries_kind);
+            ? metric_t::stateless(dimensions, metric_uintptr, metric_signature, metric_kind, queries_kind)
+            : metric_t::builtin(dimensions, metric_kind, queries_kind);
     if (!metric)
         throw std::invalid_argument("Unsupported metric!");
 
@@ -940,7 +940,7 @@ PYBIND11_MODULE(compiled, m) {
     m.def(
         "hardware_acceleration",
         [](scalar_kind_t scalar_kind, std::size_t dimensions, metric_kind_t metric_kind) -> py::str {
-            return metric_t(dimensions, metric_kind, scalar_kind).isa_name();
+            return metric_t::builtin(dimensions, metric_kind, scalar_kind).isa_name();
         },
         py::kw_only(),                                //
         py::arg("dtype") = scalar_kind_t::f32_k,      //
@@ -1101,8 +1101,8 @@ PYBIND11_MODULE(compiled, m) {
             std::size_t dimensions = index.dimensions();
             metric_t metric =  //
                 metric_uintptr //
-                    ? metric_t(dimensions, metric_uintptr, metric_signature, metric_kind, scalar_kind)
-                    : metric_t(dimensions, metric_kind, scalar_kind);
+                    ? metric_t::stateless(dimensions, metric_uintptr, metric_signature, metric_kind, scalar_kind)
+                    : metric_t::builtin(dimensions, metric_kind, scalar_kind);
             if (!metric)
                 throw std::invalid_argument("Unsupported metric kind!");
             index.change_metric(std::move(metric));
diff --git a/rust/README.md b/rust/README.md
index 330bc47f..4b4d9f1a 100644
--- a/rust/README.md
+++ b/rust/README.md
@@ -1,27 +1,55 @@
 # USearch for Rust
 
+Detailed symbol list and documentation for USearch Rust SDK can be found on [docs.rs](https://docs.rs/usearch/latest/usearch/struct.Index.html).
+
 ## Installation
 
 ```sh
 cargo add usearch
 ```
 
-You can find [interface documentation on docs.rs](https://docs.rs/usearch/2.3.0/usearch/ffi/struct.Index.html).
+This will add a USearch dependency to your `Cargo.toml` file.
+
+```toml
+[dependencies]
+usearch = "..."
+```
+
+By default, [SimSIMD](https://github.com/ashvardanian/simsimd) is used to provide dynamic dispatch for SIMD operations.
+You can, however, override that by specifying custom features in your `Cargo.toml` file.
+To disable all features, use the following configuration:
+
+```toml
+[dependencies]
+usearch = { version = "...", default-features = false }
+```
+
+To enable specific features, use the following configuration:
+
+```toml
+[dependencies]
+usearch = { version = "...", features = ["simsimd", "openmp", "fp16lib"] }
+```
+
+OpenMP (`openmp`) will use the OpenMP runtime for parallelism.
+It may not be available on all platforms, but on Linux it will lead to better performance and lower latency of small-batch operations on multi-core CPUs.
+The `fp16lib` flag will bring in the C-layer `fp16` library to emulate half-precision floating point operations on older CPUs, where it may not be natively supported.
 
 ## Quickstart
 
 ```rust
+use usearch::{Index, IndexOptions, MetricKind, ScalarKind, new_index};
 
 let options = IndexOptions {
-    dimensions: 3,
-    metric: MetricKind::IP,
-    quantization: ScalarKind::F16,
-    connectivity: 0,
-    expansion_add: 0,
-    expansion_search: 0
+    dimensions: 3, // necessary for most metric kinds
+    metric: MetricKind::IP, // or MetricKind::L2sq, MetricKind::Cos ...
+    quantization: ScalarKind::F16, // or ScalarKind::F32, ScalarKind::I8, ScalarKind::B1x8 ...
+    connectivity: 0, // zero for auto
+    expansion_add: 0, // zero for auto
+    expansion_search: 0, // zero for auto
 };
 
-let index = new_index(&options).unwrap();
+let index: Index = new_index(&options).unwrap();
 
 assert!(index.reserve(10).is_ok());
 assert!(index.capacity() >= 10);
@@ -43,13 +71,17 @@ assert_eq!(results.keys.len(), 2);
 
 ## Serialization
 
+To save and load the index from disk, use the following methods:
+
 ```rust
 assert!(index.save("index.usearch").is_ok());
 assert!(index.load("index.usearch").is_ok());
 assert!(index.view("index.usearch").is_ok());
 ```
 
-Similarly, serializing to/from buffers is supported.
+Viewing the index does not load the data into memory, but allows you to inspect and traverse the index structure from external memory using memory-mapping.
+Similarly, serializing to/from in-memory buffers is supported.
+So you can memory-map the index file manually, and later call `view_from_buffer` or one of its siblings.
 
 ```rust
 assert!(index.save_to_buffer(&mut serialization_buffer).is_ok());
@@ -59,8 +91,145 @@ assert!(index.view_from_buffer(&serialization_buffer).is_ok());
 
 ## Metrics
 
+USearch comes pre-packaged with SimSIMD, bringing over 100 SIMD-accelerated distance kernels for x86 and ARM architectures.
+That includes:
+
+- `MetricKind::IP` - Inner Product metric, defined as `IP = 1 - sum(a[i] * b[i])`.
+- `MetricKind::L2sq` - Squared Euclidean Distance metric, defined as `L2 = sum((a[i] - b[i])^2)`.
+- `MetricKind::Cos` - Cosine Similarity metric, defined as `Cos = 1 - sum(a[i] * b[i]) / (sqrt(sum(a[i]^2) * sqrt(sum(b[i]^2)))`.
+- `MetricKind::Pearson` - Pearson Correlation metric.
+- `MetricKind::Haversine` - Haversine (Great Circle) Distance metric.
+- `MetricKind::Divergence` - Jensen Shannon Divergence metric.
+- `MetricKind::Hamming` - Bit-level Hamming Distance metric, defined as the number of differing bits.
+- `MetricKind::Tanimoto` - Bit-level Tanimoto (Jaccard) metric, defined as the number of intersecting bits divided by the number of union bits.
+- `MetricKind::Sorensen` - Bit-level Sorensen metric.
+
+### User-Defined Metrics
+
+Custom metrics allow for the implementation of specific algorithms to measure the distance or similarity between vectors in the index.
+To use a custom metric with USearch, define a function that matches the expected signature and pass it to your index on creation, or later with `change_metric`.
+Let's say you are implementing a weighted distance function to search through joint embeddings of images and textual descriptions of some products in a catalog, taking some [UForm](https://github.com/unum-cloud/uform) or CLIP-like models.
+
+```rust
+use simsimd::SpatialSimilarity;
+
+let image_dimensions: usize = 768;
+let text_dimensions: usize = 512;
+let image_weights: f32 = 0.7;
+let text_weights: f32 = 0.9;
+
+let weighted_distance = Box::new(move |a: *const f32, b: *const f32| unsafe {
+    let a_slice = std::slice::from_raw_parts(a, image_dimensions + text_dimensions);
+    let b_slice = std::slice::from_raw_parts(b, image_dimensions + text_dimensions);
+
+    let image_similarity = f32::cosine(a_slice[0..image_dimensions], b_slice[0..image_dimensions]);
+    let text_similarity = f32::cosine(a_slice[image_dimensions..], b_slice[image_dimensions..]);
+    
+    (1.0 - image_similarity) * image_weights + (1.0 - text_similarity) * text_weights
+});
+index.change_metric(weighted_distance);
+```
+
+You can always revert back to one of the native metrics by calling:
+    
+```rust
+index.change_metric_kind(MetricKind::Cos);
+```
+
+## Filtering with Predicates
+
+Sometimes you may want to cross-reference search-results against some external database or filter them based on some criteria.
+In most engines, you'd have to manually perform paging requests, successively filtering the results.
+In USearch you can simply pass a predicate function to the search method, which will be applied directly during graph traversal.
+
 ```rust
-assert!(new_l2sq(3, &quant, 0, 0, 0).is_ok());
-assert!(new_cos(3, &quant, 0, 0, 0).is_ok());
-assert!(new_haversine(&quant, 0, 0, 0).is_ok());
+let is_odd = |key: Key| key % 2 == 1;
+let query = vec![0.2, 0.1, 0.2, 0.1, 0.3];
+let results = index.filtered_search(&query, 10, is_odd).unwrap();
+assert!(
+    results.keys.iter().all(|&key| key % 2 == 1),
+    "All keys must be odd"
+);
+```
+
+## Quantization and Custom Scalar Types
+
+USearch supports the Rust-native `f32` and `f64` scalar types, as well as the `i8` for quantized 8-bit scalars.
+Goign beyond that, USearch supports non-native `f16` and `b1x8` for half-precision floating point and binary vectors, respectively.
+
+### Half Precision Floating Point
+
+Rust has no native support for half-precision floating-point numbers, but USearch provides a `f16` type.
+It has no advanced functionality - it is a transparent wrapper around `i16` and can be used with `half` or any other half-precision library.
+Assuming USearch uses the IEEE 754 no conversion is needed, you can `unsafe`-cast the outputs of other IEEE-compliant libraries to `usearch::f16`.
+
+```rust
+use usearch::f16 as USearchF16;
+use half::f16 as HalfF16;
+
+let vector_a: Vec<HalfF16> = ...
+let vector_b: Vec<HalfF16> = ...
+
+let buffer_a: &[USearchF16] = unsafe { std::slice::from_raw_parts(a_half.as_ptr() as *const SimF16, a_half.len()) };
+let buffer_b: &[USearchF16] = unsafe { std::slice::from_raw_parts(b_half.as_ptr() as *const SimF16, b_half.len()) };
+
+index.add(42, buffer_a);
+index.add(43, buffer_b);
+```
+
+### Binary Vectors
+
+USearch also implement binary distance functions and natively supports bit-vectors.
+If you initialize the index with `quantization: ScalarKind::B1`, you can add floating-point vectors and they will be quantized mapping positive values to `1` and negative and zero values to `0`.
+Alternatively, you can use the `b1x8` type to represent packed binary vectors directly.
+
+```rs
+let index = Index::new(&IndexOptions {
+    dimensions: 8,
+    metric: MetricKind::Hamming,
+    quantization: ScalarKind::B1,
+    ..Default::default()
+})
+.unwrap();
+
+// Binary vectors represented as `b1x8` slices
+let vector42: Vec<b1x8> = vec![b1x8(0b00001111)];
+let vector43: Vec<b1x8> = vec![b1x8(0b11110000)];
+let query: Vec<b1x8> = vec![b1x8(0b01111000)];
+
+// Adding binary vectors to the index
+index.reserve(10).unwrap();
+index.add(42, &vector42).unwrap();
+index.add(43, &vector43).unwrap();
+
+let results = index.search(&query, 5).unwrap();
+
+// Validate the search results based on Hamming distance
+assert_eq!(results.keys.len(), 2);
+assert_eq!(results.keys[0], 43);
+assert_eq!(results.distances[0], 2.0); // 2 bits differ between query and vector43
+assert_eq!(results.keys[1], 42);
+assert_eq!(results.distances[1], 6.0); // 6 bits differ between query and vector42
+```
+
+## Performance Tuning
+
+To optimize the performance of the index, you can adjust the expansion values used during index creation and search operations.
+Higher expansion values will lead to better search accuracy at the cost of slightly increased memory usage, but potentially much higher search times.
+Following methods are available to adjust the expansion values:
+
+```rs
+println!("Add expansion: {}", index.expansion_add());
+println!("Search expansion: {}", index.expansion_search());
+index.change_expansion_add(32);
+index.change_expansion_search(32);
+```
+
+Optimizing hardware utilization, you may want to check the SIMD hardware acceleration capabilities of the index and memory consumption.
+The first will print the codename of the most advanced SIMD instruction set supported by the CPU and used by the index.
+The second will print the memory usage of the index in bytes.
+
+```rs
+println!("Hardware acceleration: {}", index.hardware_acceleration());
+println!("Memory usage: {}", index.memory_usage());
 ```
diff --git a/rust/lib.cpp b/rust/lib.cpp
index f43477f7..268c6d73 100644
--- a/rust/lib.cpp
+++ b/rust/lib.cpp
@@ -10,13 +10,40 @@ using search_result_t = typename index_t::search_result_t;
 using labeling_result_t = typename index_t::labeling_result_t;
 using vector_key_t = typename index_dense_t::vector_key_t;
 
-template <typename scalar_at> Matches search_(index_dense_t& index, scalar_at const* vec, size_t count) {
+metric_kind_t rust_to_cpp_metric(MetricKind value) {
+    switch (value) {
+    case MetricKind::IP: return metric_kind_t::ip_k;
+    case MetricKind::L2sq: return metric_kind_t::l2sq_k;
+    case MetricKind::Cos: return metric_kind_t::cos_k;
+    case MetricKind::Pearson: return metric_kind_t::pearson_k;
+    case MetricKind::Haversine: return metric_kind_t::haversine_k;
+    case MetricKind::Divergence: return metric_kind_t::divergence_k;
+    case MetricKind::Hamming: return metric_kind_t::hamming_k;
+    case MetricKind::Tanimoto: return metric_kind_t::tanimoto_k;
+    case MetricKind::Sorensen: return metric_kind_t::sorensen_k;
+    default: return metric_kind_t::unknown_k;
+    }
+}
+
+scalar_kind_t rust_to_cpp_scalar(ScalarKind value) {
+    switch (value) {
+    case ScalarKind::I8: return scalar_kind_t::i8_k;
+    case ScalarKind::F16: return scalar_kind_t::f16_k;
+    case ScalarKind::F32: return scalar_kind_t::f32_k;
+    case ScalarKind::F64: return scalar_kind_t::f64_k;
+    case ScalarKind::B1: return scalar_kind_t::b1x8_k;
+    default: return scalar_kind_t::unknown_k;
+    }
+}
+
+template <typename scalar_at, typename predicate_at = dummy_predicate_t>
+Matches search_(index_dense_t& index, scalar_at const* vec, size_t count, predicate_at&& predicate = predicate_at{}) {
     Matches matches;
     matches.keys.reserve(count);
     matches.distances.reserve(count);
     for (size_t i = 0; i != count; ++i)
         matches.keys.push_back(0), matches.distances.push_back(0);
-    search_result_t result = index.search(vec, count);
+    search_result_t result = index.filtered_search(vec, count, std::forward<predicate_at>(predicate));
     result.error.raise();
     count = result.dump_to(matches.keys.data(), matches.distances.data());
     matches.keys.truncate(count);
@@ -26,19 +53,36 @@ template <typename scalar_at> Matches search_(index_dense_t& index, scalar_at co
 
 NativeIndex::NativeIndex(std::unique_ptr<index_t> index) : index_(std::move(index)) {}
 
+auto make_predicate(uptr_t metric, uptr_t metric_state) {
+    return [=](vector_key_t key) {
+        auto func = reinterpret_cast<bool (*)(uptr_t, vector_key_t)>(metric);
+        auto state = reinterpret_cast<uptr_t>(metric_state);
+        return func(key, state);
+    };
+}
+
 // clang-format off
+void NativeIndex::add_b1x8(vector_key_t key, rust::Slice<uint8_t const> vec) const { index_->add(key, (b1x8_t const*)vec.data()).error.raise(); }
 void NativeIndex::add_i8(vector_key_t key, rust::Slice<int8_t const> vec) const { index_->add(key, vec.data()).error.raise(); }
-void NativeIndex::add_f16(vector_key_t key, rust::Slice<uint16_t const> vec) const { index_->add(key, (f16_t const*)vec.data()).error.raise(); }
+void NativeIndex::add_f16(vector_key_t key, rust::Slice<int16_t const> vec) const { index_->add(key, (f16_t const*)vec.data()).error.raise(); }
 void NativeIndex::add_f32(vector_key_t key, rust::Slice<float const> vec) const { index_->add(key, vec.data()).error.raise(); }
 void NativeIndex::add_f64(vector_key_t key, rust::Slice<double const> vec) const { index_->add(key, vec.data()).error.raise(); }
 
+Matches NativeIndex::search_b1x8(rust::Slice<uint8_t const> vec, size_t count) const { return search_(*index_, (b1x8_t const*)vec.data(), count); }
 Matches NativeIndex::search_i8(rust::Slice<int8_t const> vec, size_t count) const { return search_(*index_, vec.data(), count); }
-Matches NativeIndex::search_f16(rust::Slice<uint16_t const> vec, size_t count) const { return search_(*index_, (f16_t const*)vec.data(), count); }
+Matches NativeIndex::search_f16(rust::Slice<int16_t const> vec, size_t count) const { return search_(*index_, (f16_t const*)vec.data(), count); }
 Matches NativeIndex::search_f32(rust::Slice<float const> vec, size_t count) const { return search_(*index_, vec.data(), count); }
 Matches NativeIndex::search_f64(rust::Slice<double const> vec, size_t count) const { return search_(*index_, vec.data(), count); }
 
+Matches NativeIndex::filtered_search_b1x8(rust::Slice<uint8_t const> vec, size_t count, uptr_t metric, uptr_t metric_state) const { return search_(*index_, (b1x8_t const*)vec.data(), count, make_predicate(metric, metric_state)); }
+Matches NativeIndex::filtered_search_i8(rust::Slice<int8_t const> vec, size_t count, uptr_t metric, uptr_t metric_state) const { return search_(*index_, vec.data(), count, make_predicate(metric, metric_state)); }
+Matches NativeIndex::filtered_search_f16(rust::Slice<int16_t const> vec, size_t count, uptr_t metric, uptr_t metric_state) const { return search_(*index_, (f16_t const*)vec.data(), count, make_predicate(metric, metric_state)); }
+Matches NativeIndex::filtered_search_f32(rust::Slice<float const> vec, size_t count, uptr_t metric, uptr_t metric_state) const { return search_(*index_, vec.data(), count, make_predicate(metric, metric_state)); }
+Matches NativeIndex::filtered_search_f64(rust::Slice<double const> vec, size_t count, uptr_t metric, uptr_t metric_state) const { return search_(*index_, vec.data(), count, make_predicate(metric, metric_state)); }
+
+size_t NativeIndex::get_b1x8(vector_key_t key, rust::Slice<uint8_t> vec) const { if (vec.size() % dimensions()) throw std::invalid_argument("Vector length must be a multiple of index dimensionality"); return index_->get(key, (b1x8_t*)vec.data(), vec.size() / dimensions()); }
 size_t NativeIndex::get_i8(vector_key_t key, rust::Slice<int8_t> vec) const { if (vec.size() % dimensions()) throw std::invalid_argument("Vector length must be a multiple of index dimensionality"); return index_->get(key, vec.data(), vec.size() / dimensions()); }
-size_t NativeIndex::get_f16(vector_key_t key, rust::Slice<uint16_t> vec) const { if (vec.size() % dimensions()) throw std::invalid_argument("Vector length must be a multiple of index dimensionality"); return index_->get(key, (f16_t*)vec.data(), vec.size() / dimensions()); }
+size_t NativeIndex::get_f16(vector_key_t key, rust::Slice<int16_t> vec) const { if (vec.size() % dimensions()) throw std::invalid_argument("Vector length must be a multiple of index dimensionality"); return index_->get(key, (f16_t*)vec.data(), vec.size() / dimensions()); }
 size_t NativeIndex::get_f32(vector_key_t key, rust::Slice<float> vec) const { if (vec.size() % dimensions()) throw std::invalid_argument("Vector length must be a multiple of index dimensionality"); return index_->get(key, vec.data(), vec.size() / dimensions()); }
 size_t NativeIndex::get_f64(vector_key_t key, rust::Slice<double> vec) const { if (vec.size() % dimensions()) throw std::invalid_argument("Vector length must be a multiple of index dimensionality"); return index_->get(key, vec.data(), vec.size() / dimensions()); }
 // clang-format on
@@ -48,6 +92,21 @@ size_t NativeIndex::expansion_search() const { return index_->expansion_search()
 void NativeIndex::change_expansion_add(size_t n) const { index_->change_expansion_add(n); }
 void NativeIndex::change_expansion_search(size_t n) const { index_->change_expansion_search(n); }
 
+void NativeIndex::change_metric(uptr_t metric, uptr_t state) const {
+    index_->change_metric(metric_punned_t::statefull( //
+        reinterpret_cast<std::uintptr_t>(metric),     //
+        reinterpret_cast<std::uintptr_t>(state),      //
+        index_->metric().metric_kind(),               //
+        index_->scalar_kind()));
+}
+
+void NativeIndex::change_metric_kind(MetricKind metric) const {
+    index_->change_metric(metric_punned_t::builtin( //
+        index_->dimensions(),                       //
+        rust_to_cpp_metric(metric),                 //
+        index_->scalar_kind()));
+}
+
 size_t NativeIndex::remove(vector_key_t key) const {
     labeling_result_t result = index_->remove(key);
     result.error.raise();
@@ -101,32 +160,6 @@ std::unique_ptr<NativeIndex> wrap(index_t&& index) {
     return result;
 }
 
-metric_kind_t rust_to_cpp_metric(MetricKind value) {
-    switch (value) {
-    case MetricKind::IP: return metric_kind_t::ip_k;
-    case MetricKind::L2sq: return metric_kind_t::l2sq_k;
-    case MetricKind::Cos: return metric_kind_t::cos_k;
-    case MetricKind::Pearson: return metric_kind_t::pearson_k;
-    case MetricKind::Haversine: return metric_kind_t::haversine_k;
-    case MetricKind::Divergence: return metric_kind_t::divergence_k;
-    case MetricKind::Hamming: return metric_kind_t::hamming_k;
-    case MetricKind::Tanimoto: return metric_kind_t::tanimoto_k;
-    case MetricKind::Sorensen: return metric_kind_t::sorensen_k;
-    default: return metric_kind_t::unknown_k;
-    }
-}
-
-scalar_kind_t rust_to_cpp_scalar(ScalarKind value) {
-    switch (value) {
-    case ScalarKind::I8: return scalar_kind_t::i8_k;
-    case ScalarKind::F16: return scalar_kind_t::f16_k;
-    case ScalarKind::F32: return scalar_kind_t::f32_k;
-    case ScalarKind::F64: return scalar_kind_t::f64_k;
-    case ScalarKind::B1: return scalar_kind_t::b1x8_k;
-    default: return scalar_kind_t::unknown_k;
-    }
-}
-
 std::unique_ptr<NativeIndex> new_native_index(IndexOptions const& options) {
     metric_kind_t metric_kind = rust_to_cpp_metric(options.metric);
     scalar_kind_t scalar_kind = rust_to_cpp_scalar(options.quantization);
diff --git a/rust/lib.hpp b/rust/lib.hpp
index eca7d06c..a810d347 100644
--- a/rust/lib.hpp
+++ b/rust/lib.hpp
@@ -1,12 +1,17 @@
 #pragma once
 #include "rust/cxx.h"
 
-#include <memory> // `std::shared_ptr`
-
-#include <usearch/index_dense.hpp>
-
+// We don't have to forward decalre all of those:
 struct Matches;
 struct IndexOptions;
+enum class MetricKind;
+enum class ScalarKind;
+
+#include <usearch/index_dense.hpp> // `unum::usearch::index_dense_t`
+
+#include <memory> // `std::unique_ptr`
+
+using uptr_t = size_t;
 
 class NativeIndex {
   public:
@@ -21,18 +26,29 @@ class NativeIndex {
 
     void reserve(size_t) const;
 
+    void add_b1x8(vector_key_t key, rust::Slice<uint8_t const> vector) const;
     void add_i8(vector_key_t key, rust::Slice<int8_t const> vector) const;
-    void add_f16(vector_key_t key, rust::Slice<uint16_t const> vector) const;
+    void add_f16(vector_key_t key, rust::Slice<int16_t const> vector) const;
     void add_f32(vector_key_t key, rust::Slice<float const> vector) const;
     void add_f64(vector_key_t key, rust::Slice<double const> vector) const;
 
-    Matches search_i8(rust::Slice<int8_t const> vector, size_t count) const;
-    Matches search_f16(rust::Slice<uint16_t const> vector, size_t count) const;
-    Matches search_f32(rust::Slice<float const> vector, size_t count) const;
-    Matches search_f64(rust::Slice<double const> vector, size_t count) const;
-
+    Matches search_b1x8(rust::Slice<uint8_t const> query, size_t count) const;
+    Matches search_i8(rust::Slice<int8_t const> query, size_t count) const;
+    Matches search_f16(rust::Slice<int16_t const> query, size_t count) const;
+    Matches search_f32(rust::Slice<float const> query, size_t count) const;
+    Matches search_f64(rust::Slice<double const> query, size_t count) const;
+
+    // clang-format off
+    Matches filtered_search_b1x8(rust::Slice<uint8_t const> query, size_t count, uptr_t filter_function, uptr_t filter_state) const;
+    Matches filtered_search_i8(rust::Slice<int8_t const> query, size_t count, uptr_t filter_function, uptr_t filter_state) const;
+    Matches filtered_search_f16(rust::Slice<int16_t const> query, size_t count, uptr_t filter_function, uptr_t filter_state) const;
+    Matches filtered_search_f32(rust::Slice<float const> query, size_t count, uptr_t filter_function, uptr_t filter_state) const;
+    Matches filtered_search_f64(rust::Slice<double const> query, size_t count, uptr_t filter_function, uptr_t filter_state) const;
+    // clang-format on
+
+    size_t get_b1x8(vector_key_t key, rust::Slice<uint8_t> vector) const;
     size_t get_i8(vector_key_t key, rust::Slice<int8_t> vector) const;
-    size_t get_f16(vector_key_t key, rust::Slice<uint16_t> vector) const;
+    size_t get_f16(vector_key_t key, rust::Slice<int16_t> vector) const;
     size_t get_f32(vector_key_t key, rust::Slice<float> vector) const;
     size_t get_f64(vector_key_t key, rust::Slice<double> vector) const;
 
@@ -41,6 +57,9 @@ class NativeIndex {
     void change_expansion_add(size_t n) const;
     void change_expansion_search(size_t n) const;
 
+    void change_metric(uptr_t metric, uptr_t state) const;
+    void change_metric_kind(MetricKind metric) const;
+
     size_t count(vector_key_t key) const;
     size_t remove(vector_key_t key) const;
     size_t rename(vector_key_t from, vector_key_t to) const;
diff --git a/rust/lib.rs b/rust/lib.rs
index 9c4607e5..9bda57a8 100644
--- a/rust/lib.rs
+++ b/rust/lib.rs
@@ -1,34 +1,234 @@
+use std::boxed::Box;
+
+/// The key type used to identify vectors in the index.
+/// It is a 64-bit unsigned integer.
+pub type Key = u64;
+
+/// The distance type used to represent the similarity between vectors.
+/// It is a 32-bit floating-point number.
+pub type Distance = f32;
+
+/// Callback signature for custom metric functions, defined in the Rust layer and used in the C++ layer.
+pub type StatefullMetric = unsafe extern "C" fn(
+    *const std::ffi::c_void,
+    *const std::ffi::c_void,
+    *mut std::ffi::c_void,
+) -> Distance;
+
+/// Callback signature for custom predicate functions, defined in the Rust layer and used in the C++ layer.
+pub type StatefullPredicate = unsafe extern "C" fn(Key, *mut std::ffi::c_void) -> bool;
+
+/// Represents errors that can occur when addressing bits.
+#[derive(Debug)]
+pub enum BitAddressableError {
+    /// Error indicating the specified index is out of the allowable range.
+    IndexOutOfRange,
+}
+
+impl std::fmt::Display for BitAddressableError {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        match *self {
+            BitAddressableError::IndexOutOfRange => write!(f, "Index out of range"),
+        }
+    }
+}
+
+impl std::error::Error for BitAddressableError {}
+
+/// Trait for types that can be addressed at the bit level.
+/// Provides methods to set and get individual bits within the implementing type.
+pub trait BitAddressable {
+    /// Sets a bit at the specified index.
+    /// Returns an error if the index is out of range.
+    ///
+    /// # Arguments
+    ///
+    /// * `index` - The index of the bit to set.
+    /// * `value` - The value to set the bit to (`true` for 1, `false` for 0).
+    fn set_bit(&mut self, index: usize, value: bool) -> Result<(), BitAddressableError>;
+
+    /// Gets the value of a bit at the specified index.
+    /// Returns an error if the index is out of range.
+    ///
+    /// # Arguments
+    ///
+    /// * `index` - The index of the bit to retrieve.
+    fn get_bit(&self, index: usize) -> Result<bool, BitAddressableError>;
+}
+
+#[allow(non_camel_case_types)]
+pub struct b1x8(pub u8);
+impl b1x8 {
+    /// Casts a slice of `u8` to a slice of `b1x8`.
+    pub fn from_u8s(slice: &[u8]) -> &[Self] {
+        unsafe { std::slice::from_raw_parts(slice.as_ptr() as *const Self, slice.len()) }
+    }
+
+    /// Casts a mutable slice of `u8` to a mutable slice of `b1x8`.
+    pub fn from_mut_u8s(slice: &mut [u8]) -> &mut [Self] {
+        unsafe { std::slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut Self, slice.len()) }
+    }
+
+    /// Casts a slice of `b1x8` back to a slice of `u8`.
+    pub fn to_u8s(slice: &[Self]) -> &[u8] {
+        unsafe { std::slice::from_raw_parts(slice.as_ptr() as *const u8, slice.len()) }
+    }
+
+    /// Casts a mutable slice of `b1x8` back to a mutable slice of `u8`.
+    pub fn to_mut_u8s(slice: &mut [Self]) -> &mut [u8] {
+        unsafe { std::slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut u8, slice.len()) }
+    }
+}
+
+impl BitAddressable for b1x8 {
+    /// Sets a bit at a specific index within the byte.
+    ///
+    /// # Arguments
+    ///
+    /// * `index` - The 0-based index of the bit to set, ranging from 0 to 7.
+    /// * `value` - The boolean value to assign to the bit (`true` for 1, `false` for 0).
+    ///
+    /// # Returns
+    ///
+    /// This method returns `Ok(())` if the bit was successfully set, or an `Err(BitAddressableError::IndexOutOfRange)`
+    /// if the provided index is outside the valid range.
+    fn set_bit(&mut self, index: usize, value: bool) -> Result<(), BitAddressableError> {
+        if index >= 8 {
+            Err(BitAddressableError::IndexOutOfRange)
+        } else {
+            if value {
+                self.0 |= 1 << index;
+            } else {
+                self.0 &= !(1 << index);
+            }
+            Ok(())
+        }
+    }
+
+    /// Retrieves the value of a bit at a specific index within the byte.
+    ///
+    /// # Arguments
+    ///
+    /// * `index` - The 0-based index of the bit to retrieve, ranging from 0 to 7.
+    ///
+    /// # Returns
+    ///
+    /// Returns `Ok(true)` if the bit is set (1), `Ok(false)` if the bit is not set (0),
+    /// or an `Err(BitAddressableError::IndexOutOfRange)` if the provided index is outside
+    /// the valid range.
+    fn get_bit(&self, index: usize) -> Result<bool, BitAddressableError> {
+        if index >= 8 {
+            Err(BitAddressableError::IndexOutOfRange)
+        } else {
+            Ok(((self.0 >> index) & 1) == 1)
+        }
+    }
+}
+
+impl BitAddressable for [b1x8] {
+    /// Sets a bit at a specific index across the slice of `b1x8`.
+    fn set_bit(&mut self, index: usize, value: bool) -> Result<(), BitAddressableError> {
+        let byte_index = index / 8;
+        let bit_index = index % 8;
+        if byte_index >= self.len() {
+            Err(BitAddressableError::IndexOutOfRange)
+        } else {
+            self[byte_index].set_bit(bit_index, value)
+        }
+    }
+
+    /// Gets a bit at a specific index across the slice of `b1x8`.
+    fn get_bit(&self, index: usize) -> Result<bool, BitAddressableError> {
+        let byte_index = index / 8;
+        let bit_index = index % 8;
+        if byte_index >= self.len() {
+            Err(BitAddressableError::IndexOutOfRange)
+        } else {
+            self[byte_index].get_bit(bit_index)
+        }
+    }
+}
+
+#[allow(non_camel_case_types)]
+pub struct f16(i16);
+impl f16 {
+    /// Casts a slice of `i16` to a slice of `f16`.
+    pub fn from_i16s(slice: &[i16]) -> &[Self] {
+        unsafe { std::slice::from_raw_parts(slice.as_ptr() as *const Self, slice.len()) }
+    }
+
+    /// Casts a mutable slice of `i16` to a mutable slice of `f16`.
+    pub fn from_mut_i16s(slice: &mut [i16]) -> &mut [Self] {
+        unsafe { std::slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut Self, slice.len()) }
+    }
+
+    /// Casts a slice of `f16` back to a slice of `i16`.
+    pub fn to_i16s(slice: &[Self]) -> &[i16] {
+        unsafe { std::slice::from_raw_parts(slice.as_ptr() as *const i16, slice.len()) }
+    }
+
+    /// Casts a mutable slice of `f16` back to a mutable slice of `i16`.
+    pub fn to_mut_i16s(slice: &mut [Self]) -> &mut [i16] {
+        unsafe { std::slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut i16, slice.len()) }
+    }
+}
+
 #[cxx::bridge]
 pub mod ffi {
-    // Shared structs with fields visible to both languages.
-    #[derive(Debug)]
-    struct Matches {
-        keys: Vec<u64>,
-        distances: Vec<f32>,
-    }
 
+    /// The metric kind used to differentiate built-in distance functions.
     #[derive(Debug)]
+    #[repr(i32)]
     enum MetricKind {
+        Unknown,
+        /// The Inner Product metric, defined as `IP = 1 - sum(a[i] * b[i])`.
         IP,
+        /// The squared Euclidean Distance metric, defined as `L2 = sum((a[i] - b[i])^2)`.
         L2sq,
+        /// The Cosine Similarity metric, defined as `Cos = 1 - sum(a[i] * b[i]) / (sqrt(sum(a[i]^2) * sqrt(sum(b[i]^2)))`.
         Cos,
+        /// The Pearson Correlation metric.
         Pearson,
+        /// The Haversine (Great Circle) Distance metric.
         Haversine,
+        /// The Jensen Shannon Divergence metric.
         Divergence,
+        /// The bit-level Hamming Distance metric, defined as the number of differing bits.
         Hamming,
+        /// The bit-level Tanimoto (Jaccard) metric, defined as the number of intersecting bits divided by the number of union bits.
         Tanimoto,
+        /// The bit-level Sorensen metric.
         Sorensen,
     }
 
+    /// The scalar kind used to differentiate built-in vector element types.
     #[derive(Debug)]
+    #[repr(i32)]
     enum ScalarKind {
+        Unknown,
+        /// 64-bit double-precision IEEE 754 floating-point number.
         F64,
+        /// 32-bit single-precision IEEE 754 floating-point number.
         F32,
+        /// 16-bit half-precision IEEE 754 floating-point number (different from `bf16`).
         F16,
+        /// 8-bit signed integer.
         I8,
+        /// 1-bit binary value, packed 8 per byte.
         B1,
     }
 
+    /// The resulting matches from a search operation.
+    /// It contains the keys and distances of the closest vectors.
+    #[derive(Debug)]
+    struct Matches {
+        keys: Vec<u64>,
+        distances: Vec<f32>,
+    }
+
+    /// The index options used to configure the dense index during creation.
+    /// It contains the number of dimensions, the metric kind, the scalar kind,
+    /// the connectivity, the expansion values, and the multi-flag.
     #[derive(Debug, PartialEq)]
     struct IndexOptions {
         dimensions: usize,
@@ -49,8 +249,16 @@ pub mod ffi {
 
         pub fn expansion_add(self: &NativeIndex) -> usize;
         pub fn expansion_search(self: &NativeIndex) -> usize;
-        pub fn change_expansion_add(self: &NativeIndex, n: usize) -> Result<()>;
-        pub fn change_expansion_search(self: &NativeIndex, n: usize) -> Result<()>;
+        pub fn change_expansion_add(self: &NativeIndex, n: usize);
+        pub fn change_expansion_search(self: &NativeIndex, n: usize);
+        pub fn change_metric_kind(self: &NativeIndex, metric: MetricKind);
+
+        /// Changes the metric function used to calculate the distance between vectors.
+        /// Avoids the `std::ffi::c_void` type and the `StatefullMetric` type, that the FFI
+        /// does not support, replacing them with basic pointer-sized integer types.
+        /// The first two arguments are the pointers to the vectors to compare, and the third
+        /// argument is the `metric_state` propagated from the Rust layer.
+        pub fn change_metric(self: &NativeIndex, metric: usize, metric_state: usize);
 
         pub fn new_native_index(options: &IndexOptions) -> Result<UniquePtr<NativeIndex>>;
         pub fn reserve(self: &NativeIndex, capacity: usize) -> Result<()>;
@@ -60,18 +268,57 @@ pub mod ffi {
         pub fn capacity(self: &NativeIndex) -> usize;
         pub fn serialized_length(self: &NativeIndex) -> usize;
 
+        pub fn add_b1x8(self: &NativeIndex, key: u64, vector: &[u8]) -> Result<()>;
         pub fn add_i8(self: &NativeIndex, key: u64, vector: &[i8]) -> Result<()>;
-        pub fn add_f16(self: &NativeIndex, key: u64, vector: &[u16]) -> Result<()>;
+        pub fn add_f16(self: &NativeIndex, key: u64, vector: &[i16]) -> Result<()>;
         pub fn add_f32(self: &NativeIndex, key: u64, vector: &[f32]) -> Result<()>;
         pub fn add_f64(self: &NativeIndex, key: u64, vector: &[f64]) -> Result<()>;
 
+        pub fn search_b1x8(self: &NativeIndex, query: &[u8], count: usize) -> Result<Matches>;
         pub fn search_i8(self: &NativeIndex, query: &[i8], count: usize) -> Result<Matches>;
-        pub fn search_f16(self: &NativeIndex, query: &[u16], count: usize) -> Result<Matches>;
+        pub fn search_f16(self: &NativeIndex, query: &[i16], count: usize) -> Result<Matches>;
         pub fn search_f32(self: &NativeIndex, query: &[f32], count: usize) -> Result<Matches>;
         pub fn search_f64(self: &NativeIndex, query: &[f64], count: usize) -> Result<Matches>;
 
+        pub fn filtered_search_b1x8(
+            self: &NativeIndex,
+            query: &[u8],
+            count: usize,
+            filter: usize,
+            filter_state: usize,
+        ) -> Result<Matches>;
+        pub fn filtered_search_i8(
+            self: &NativeIndex,
+            query: &[i8],
+            count: usize,
+            filter: usize,
+            filter_state: usize,
+        ) -> Result<Matches>;
+        pub fn filtered_search_f16(
+            self: &NativeIndex,
+            query: &[i16],
+            count: usize,
+            filter: usize,
+            filter_state: usize,
+        ) -> Result<Matches>;
+        pub fn filtered_search_f32(
+            self: &NativeIndex,
+            query: &[f32],
+            count: usize,
+            filter: usize,
+            filter_state: usize,
+        ) -> Result<Matches>;
+        pub fn filtered_search_f64(
+            self: &NativeIndex,
+            query: &[f64],
+            count: usize,
+            filter: usize,
+            filter_state: usize,
+        ) -> Result<Matches>;
+
+        pub fn get_b1x8(self: &NativeIndex, key: u64, buffer: &mut [u8]) -> Result<usize>;
         pub fn get_i8(self: &NativeIndex, key: u64, buffer: &mut [i8]) -> Result<usize>;
-        pub fn get_f16(self: &NativeIndex, key: u64, buffer: &mut [u16]) -> Result<usize>;
+        pub fn get_f16(self: &NativeIndex, key: u64, buffer: &mut [i16]) -> Result<usize>;
         pub fn get_f32(self: &NativeIndex, key: u64, buffer: &mut [f32]) -> Result<usize>;
         pub fn get_f64(self: &NativeIndex, key: u64, buffer: &mut [f64]) -> Result<usize>;
 
@@ -93,21 +340,117 @@ pub mod ffi {
     }
 }
 
+// Re-export the FFI structs and enums at the crate root for easy access
+pub use ffi::{IndexOptions, MetricKind, ScalarKind};
+
+/// Represents custom metric functions for calculating distances between vectors in various formats.
+///
+/// This enum allows the encapsulation of custom distance calculation logic for vectors of different
+/// data types, facilitating the use of custom metrics in vector space operations. Each variant of this
+/// enum holds a boxed function pointer (`Box<dyn Fn(...) -> Distance + Send + Sync>`) that defines the
+/// distance calculation between two vectors of a specific type. The function returns a `Distance`, which
+/// is typically a floating-point value representing the calculated distance between the two vectors.
+///
+/// # Variants
+///
+/// - `B1X8Metric`: A metric function for binary vectors packed in `u8` containers, represented here by `b1x8`.
+/// - `I8Metric`: A metric function for vectors of 8-bit signed integers (`i8`).
+/// - `F16Metric`: A metric function for vectors of 16-bit floating-point numbers, using a custom `f16` type
+///   to represent half-precision floats.
+/// - `F32Metric`: A metric function for vectors of 32-bit floating-point numbers (`f32`).
+/// - `F64Metric`: A metric function for vectors of 64-bit floating-point numbers (`f64`).
+///
+/// Each metric function takes two pointers to the vectors of the respective type and returns a `Distance`.
+///
+/// # Usage
+///
+/// Custom metric functions can be used to define how distances are calculated between vectors, enabling
+/// the implementation of various distance metrics such as Euclidean distance, Manhattan distance, or
+/// Cosine similarity, depending on the specific requirements of the application.
+///
+/// # Safety
+///
+/// Since these functions operate on raw pointers, care must be taken to ensure that the pointers are valid
+/// and that the lifetime of the referenced data extends at least as long as the lifetime of the metric
+/// function's use. Improper use of these functions can lead to undefined behavior.
+///
+/// # Examples
+///
+/// ```
+/// use usearch::{MetricFunction, Distance, f16, b1x8};
+///
+/// // Example of defining a custom Euclidean distance function for f32 vectors
+/// let euclidean: MetricFunction = MetricFunction::F32Metric(Box::new(|a, b| {
+///     // Safety: Assume a and b are valid for the number of dimensions in context.
+///     let dimensions = 256;
+///     let a = unsafe { std::slice::from_raw_parts(a, dimensions) };
+///     let b = unsafe { std::slice::from_raw_parts(b, dimensions) };
+///     a.iter().zip(b.iter())
+///         .map(|(a, b)| (a - b).powi(2))
+///         .sum::<f32>()
+///         .sqrt()
+/// }));
+/// ```
+///
+/// In this example, `dimensions` should be defined and valid for the vectors `a` and `b`.
+pub enum MetricFunction {
+    B1X8Metric(Box<dyn Fn(*const b1x8, *const b1x8) -> Distance + Send + Sync>),
+    I8Metric(Box<dyn Fn(*const i8, *const i8) -> Distance + Send + Sync>),
+    F16Metric(Box<dyn Fn(*const f16, *const f16) -> Distance + Send + Sync>),
+    F32Metric(Box<dyn Fn(*const f32, *const f32) -> Distance + Send + Sync>),
+    F64Metric(Box<dyn Fn(*const f64, *const f64) -> Distance + Send + Sync>),
+}
+
+/// Approximate Nearest Neighbors search index for dense vectors.
+///
+/// The `Index` struct provides an abstraction over a dense vector space, allowing
+/// for efficient addition, search, and management of high-dimensional vectors.
+/// It supports various distance metrics and vector types through generic interfaces.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```rust
+/// use usearch::{Index, IndexOptions, MetricKind, ScalarKind};
+///
+/// // Create an index with specific options
+/// let mut options = IndexOptions::default();
+/// options.dimensions = 4; // Set the number of dimensions for vectors
+/// options.metric = MetricKind::Cos; // Use cosine similarity for distance measurement
+/// options.quantization = ScalarKind::F32; // Use 32-bit floating point numbers
+///
+/// let index = Index::new(&options).expect("Failed to create index.");
+/// index.reserve(1000).expect("Failed to reserve capacity.");
+///
+/// // Add vectors to the index
+/// let vector1: Vec<f32> = vec![0.0, 1.0, 0.0, 1.0];
+/// let vector2: Vec<f32> = vec![1.0, 0.0, 1.0, 0.0];
+/// index.add(1, &vector1).expect("Failed to add vector1.");
+/// index.add(2, &vector2).expect("Failed to add vector2.");
+///
+/// // Search for the nearest neighbors to a query vector
+/// let query: Vec<f32> = vec![0.5, 0.5, 0.5, 0.5];
+/// let results = index.search(&query, 5).expect("Search failed.");
+/// for (key, distance) in results.keys.iter().zip(results.distances.iter()) {
+///     println!("Key: {}, Distance: {}", key, distance);
+/// }
+/// ```
+///
 pub struct Index {
     inner: cxx::UniquePtr<ffi::NativeIndex>,
+    metric_fn: Option<MetricFunction>,
 }
 
 impl Default for ffi::IndexOptions {
     fn default() -> Self {
-        use crate::ffi::MetricKind;
-        use crate::ffi::ScalarKind;
         Self {
-            dimensions: 128,
-            metric: MetricKind::IP,
-            quantization: ScalarKind::F32,
-            connectivity: 32,
-            expansion_add: 2,
-            expansion_search: 3,
+            dimensions: 256,
+            metric: MetricKind::Cos,
+            quantization: ScalarKind::F16,
+            connectivity: 0,
+            expansion_add: 0,
+            expansion_search: 0,
             multi: false,
         }
     }
@@ -127,39 +470,227 @@ impl Clone for ffi::IndexOptions {
     }
 }
 
+/// The `VectorType` trait defines operations for managing and querying vectors
+/// in an index. It supports generic operations on vectors of different types,
+/// allowing for the addition, retrieval, and search of vectors within an index.
 pub trait VectorType {
-    fn add(index: &Index, key: u64, vector: &[Self]) -> Result<(), cxx::Exception>
+    /// Adds a vector to the index under the specified key.
+    ///
+    /// # Parameters
+    /// - `index`: A reference to the `Index` where the vector is to be added.
+    /// - `key`: The key under which the vector should be stored.
+    /// - `vector`: A slice representing the vector to be added.
+    ///
+    /// # Returns
+    /// - `Ok(())` if the vector was successfully added to the index.
+    /// - `Err(cxx::Exception)` if an error occurred during the operation.
+    fn add(index: &Index, key: Key, vector: &[Self]) -> Result<(), cxx::Exception>
     where
         Self: Sized;
-    fn get(index: &Index, key: u64, buffer: &mut [Self]) -> Result<usize, cxx::Exception>
+
+    /// Retrieves a vector from the index by its key.
+    ///
+    /// # Parameters
+    /// - `index`: A reference to the `Index` from which the vector is to be retrieved.
+    /// - `key`: The key of the vector to retrieve.
+    /// - `buffer`: A mutable slice where the retrieved vector will be stored. The size of the
+    ///   buffer determines the maximum number of elements that can be retrieved.
+    ///
+    /// # Returns
+    /// - `Ok(usize)` indicating the number of elements actually written into the `buffer`.
+    /// - `Err(cxx::Exception)` if an error occurred during the operation.
+    fn get(index: &Index, key: Key, buffer: &mut [Self]) -> Result<usize, cxx::Exception>
     where
         Self: Sized;
+
+    /// Performs a search in the index using the given query vector, returning
+    /// up to `count` closest matches.
+    ///
+    /// # Parameters
+    /// - `index`: A reference to the `Index` where the search is to be performed.
+    /// - `query`: A slice representing the query vector.
+    /// - `count`: The maximum number of matches to return.
+    ///
+    /// # Returns
+    /// - `Ok(ffi::Matches)` containing the matches found.
+    /// - `Err(cxx::Exception)` if an error occurred during the search operation.
     fn search(index: &Index, query: &[Self], count: usize) -> Result<ffi::Matches, cxx::Exception>
     where
         Self: Sized;
+
+    /// Performs a filtered search in the index using a query vector and a custom
+    /// filter function, returning up to `count` matches that satisfy the filter.
+    ///
+    /// # Parameters
+    /// - `index`: A reference to the `Index` where the search is to be performed.
+    /// - `query`: A slice representing the query vector.
+    /// - `count`: The maximum number of matches to return.
+    /// - `filter`: A closure that takes a `Key` and returns `true` if the corresponding
+    ///   vector should be included in the search results, or `false` otherwise.
+    ///
+    /// # Returns
+    /// - `Ok(ffi::Matches)` containing the matches that satisfy the filter.
+    /// - `Err(cxx::Exception)` if an error occurred during the filtered search operation.
+    fn filtered_search<F>(
+        index: &Index,
+        query: &[Self],
+        count: usize,
+        filter: F,
+    ) -> Result<ffi::Matches, cxx::Exception>
+    where
+        Self: Sized,
+        F: Fn(Key) -> bool;
+
+    /// Changes the metric used for distance calculations within the index.
+    ///
+    /// # Parameters
+    /// - `index`: A mutable reference to the `Index` for which the metric is to be changed.
+    /// - `metric`: A boxed closure that defines the new metric for distance calculation. The
+    ///   closure must take two pointers to elements of type `Self` and return a `Distance`.
+    ///
+    /// # Returns
+    /// - `Ok(())` if the metric was successfully changed.
+    /// - `Err(cxx::Exception)` if an error occurred during the operation.
+    fn change_metric(
+        index: &mut Index,
+        metric: Box<dyn Fn(*const Self, *const Self) -> Distance + Send + Sync>,
+    ) -> Result<(), cxx::Exception>
+    where
+        Self: Sized;
+}
+
+impl VectorType for f32 {
+    fn search(index: &Index, query: &[Self], count: usize) -> Result<ffi::Matches, cxx::Exception> {
+        index.inner.search_f32(query, count)
+    }
+    fn get(index: &Index, key: Key, vector: &mut [Self]) -> Result<usize, cxx::Exception> {
+        index.inner.get_f32(key, vector)
+    }
+    fn add(index: &Index, key: Key, vector: &[Self]) -> Result<(), cxx::Exception> {
+        index.inner.add_f32(key, vector)
+    }
+    fn filtered_search<F>(
+        index: &Index,
+        query: &[Self],
+        count: usize,
+        filter: F,
+    ) -> Result<ffi::Matches, cxx::Exception>
+    where
+        Self: Sized,
+        F: Fn(Key) -> bool,
+    {
+        // Trampoline is the function that knows how to call the Rust closure.
+        extern "C" fn trampoline<F: Fn(u64) -> bool>(key: u64, closure_address: usize) -> bool {
+            let closure = closure_address as *const F;
+            unsafe { (*closure)(key) }
+        }
+
+        // Temporarily cast the closure to a raw pointer for passing.
+        unsafe {
+            let trampoline_fn: usize = std::mem::transmute(trampoline::<F> as *const ());
+            let closure_address: usize = &filter as *const F as usize;
+            index
+                .inner
+                .filtered_search_f32(query, count, trampoline_fn, closure_address)
+        }
+    }
+
+    fn change_metric(
+        index: &mut Index,
+        metric: Box<dyn Fn(*const Self, *const Self) -> Distance + Send + Sync>,
+    ) -> Result<(), cxx::Exception> {
+        // Store the metric function in the Index.
+        type MetricFn = fn(*const f32, *const f32) -> Distance;
+        index.metric_fn = Some(MetricFunction::F32Metric(metric));
+
+        // Trampoline is the function that knows how to call the Rust closure.
+        // The `first` is a pointer to the first vector, `second` is a pointer to the second vector,
+        // and `index_wrapper` is a pointer to the `index` itself, from which we can infer the metric function
+        // and the number of dimensions.
+        extern "C" fn trampoline(first: usize, second: usize, closure_address: usize) -> Distance {
+            let first_ptr = first as *const f32;
+            let second_ptr = second as *const f32;
+            let closure: MetricFn = unsafe { std::mem::transmute(closure_address) };
+            closure(first_ptr, second_ptr)
+        }
+
+        unsafe {
+            let trampoline_fn: usize = std::mem::transmute(trampoline as *const ());
+            let closure_address = match index.metric_fn {
+                Some(MetricFunction::F32Metric(ref metric)) => metric as *const _ as usize,
+                _ => panic!("Expected F32Metric"),
+            };
+            index.inner.change_metric(trampoline_fn, closure_address)
+        }
+
+        Ok(())
+    }
 }
 
 impl VectorType for i8 {
     fn search(index: &Index, query: &[Self], count: usize) -> Result<ffi::Matches, cxx::Exception> {
         index.inner.search_i8(query, count)
     }
-    fn get(index: &Index, key: u64, vector: &mut [Self]) -> Result<usize, cxx::Exception> {
+    fn get(index: &Index, key: Key, vector: &mut [Self]) -> Result<usize, cxx::Exception> {
         index.inner.get_i8(key, vector)
     }
-    fn add(index: &Index, key: u64, vector: &[Self]) -> Result<(), cxx::Exception> {
+    fn add(index: &Index, key: Key, vector: &[Self]) -> Result<(), cxx::Exception> {
         index.inner.add_i8(key, vector)
     }
-}
+    fn filtered_search<F>(
+        index: &Index,
+        query: &[Self],
+        count: usize,
+        filter: F,
+    ) -> Result<ffi::Matches, cxx::Exception>
+    where
+        Self: Sized,
+        F: Fn(Key) -> bool,
+    {
+        // Trampoline is the function that knows how to call the Rust closure.
+        extern "C" fn trampoline<F: Fn(u64) -> bool>(key: u64, closure_address: usize) -> bool {
+            let closure = closure_address as *const F;
+            unsafe { (*closure)(key) }
+        }
 
-impl VectorType for f32 {
-    fn search(index: &Index, query: &[Self], count: usize) -> Result<ffi::Matches, cxx::Exception> {
-        index.inner.search_f32(query, count)
-    }
-    fn get(index: &Index, key: u64, vector: &mut [Self]) -> Result<usize, cxx::Exception> {
-        index.inner.get_f32(key, vector)
+        // Temporarily cast the closure to a raw pointer for passing.
+        unsafe {
+            let trampoline_fn: usize = std::mem::transmute(trampoline::<F> as *const ());
+            let closure_address: usize = &filter as *const F as usize;
+            index
+                .inner
+                .filtered_search_i8(query, count, trampoline_fn, closure_address)
+        }
     }
-    fn add(index: &Index, key: u64, vector: &[Self]) -> Result<(), cxx::Exception> {
-        index.inner.add_f32(key, vector)
+    fn change_metric(
+        index: &mut Index,
+        metric: Box<dyn Fn(*const Self, *const Self) -> Distance + Send + Sync>,
+    ) -> Result<(), cxx::Exception> {
+        // Store the metric function in the Index.
+        type MetricFn = fn(*const i8, *const i8) -> Distance;
+        index.metric_fn = Some(MetricFunction::I8Metric(metric));
+
+        // Trampoline is the function that knows how to call the Rust closure.
+        // The `first` is a pointer to the first vector, `second` is a pointer to the second vector,
+        // and `index_wrapper` is a pointer to the `index` itself, from which we can infer the metric function
+        // and the number of dimensions.
+        extern "C" fn trampoline(first: usize, second: usize, closure_address: usize) -> Distance {
+            let first_ptr = first as *const i8;
+            let second_ptr = second as *const i8;
+            let closure: MetricFn = unsafe { std::mem::transmute(closure_address) };
+            closure(first_ptr, second_ptr)
+        }
+
+        unsafe {
+            let trampoline_fn: usize = std::mem::transmute(trampoline as *const ());
+            let closure_address = match index.metric_fn {
+                Some(MetricFunction::I8Metric(ref metric)) => metric as *const _ as usize,
+                _ => panic!("Expected I8Metric"),
+            };
+            index.inner.change_metric(trampoline_fn, closure_address)
+        }
+
+        Ok(())
     }
 }
 
@@ -167,18 +698,218 @@ impl VectorType for f64 {
     fn search(index: &Index, query: &[Self], count: usize) -> Result<ffi::Matches, cxx::Exception> {
         index.inner.search_f64(query, count)
     }
-    fn get(index: &Index, key: u64, vector: &mut [Self]) -> Result<usize, cxx::Exception> {
+    fn get(index: &Index, key: Key, vector: &mut [Self]) -> Result<usize, cxx::Exception> {
         index.inner.get_f64(key, vector)
     }
-    fn add(index: &Index, key: u64, vector: &[Self]) -> Result<(), cxx::Exception> {
+    fn add(index: &Index, key: Key, vector: &[Self]) -> Result<(), cxx::Exception> {
         index.inner.add_f64(key, vector)
     }
+    fn filtered_search<F>(
+        index: &Index,
+        query: &[Self],
+        count: usize,
+        filter: F,
+    ) -> Result<ffi::Matches, cxx::Exception>
+    where
+        Self: Sized,
+        F: Fn(Key) -> bool,
+    {
+        // Trampoline is the function that knows how to call the Rust closure.
+        extern "C" fn trampoline<F: Fn(u64) -> bool>(key: u64, closure_address: usize) -> bool {
+            let closure = closure_address as *const F;
+            unsafe { (*closure)(key) }
+        }
+
+        // Temporarily cast the closure to a raw pointer for passing.
+        unsafe {
+            let trampoline_fn: usize = std::mem::transmute(trampoline::<F> as *const ());
+            let closure_address: usize = &filter as *const F as usize;
+            index
+                .inner
+                .filtered_search_f64(query, count, trampoline_fn, closure_address)
+        }
+    }
+    fn change_metric(
+        index: &mut Index,
+        metric: Box<dyn Fn(*const Self, *const Self) -> Distance + Send + Sync>,
+    ) -> Result<(), cxx::Exception> {
+        // Store the metric function in the Index.
+        type MetricFn = fn(*const f64, *const f64) -> Distance;
+        index.metric_fn = Some(MetricFunction::F64Metric(metric));
+
+        // Trampoline is the function that knows how to call the Rust closure.
+        // The `first` is a pointer to the first vector, `second` is a pointer to the second vector,
+        // and `index_wrapper` is a pointer to the `index` itself, from which we can infer the metric function
+        // and the number of dimensions.
+        extern "C" fn trampoline(first: usize, second: usize, closure_address: usize) -> Distance {
+            let first_ptr = first as *const f64;
+            let second_ptr = second as *const f64;
+            let closure: MetricFn = unsafe { std::mem::transmute(closure_address) };
+            closure(first_ptr, second_ptr)
+        }
+
+        unsafe {
+            let trampoline_fn: usize = std::mem::transmute(trampoline as *const ());
+            let closure_address = match index.metric_fn {
+                Some(MetricFunction::F64Metric(ref metric)) => metric as *const _ as usize,
+                _ => panic!("Expected F64Metric"),
+            };
+            index.inner.change_metric(trampoline_fn, closure_address)
+        }
+
+        Ok(())
+    }
+}
+
+impl VectorType for f16 {
+    fn search(index: &Index, query: &[Self], count: usize) -> Result<ffi::Matches, cxx::Exception> {
+        index.inner.search_f16(f16::to_i16s(query), count)
+    }
+    fn get(index: &Index, key: Key, vector: &mut [Self]) -> Result<usize, cxx::Exception> {
+        index.inner.get_f16(key, f16::to_mut_i16s(vector))
+    }
+    fn add(index: &Index, key: Key, vector: &[Self]) -> Result<(), cxx::Exception> {
+        index.inner.add_f16(key, f16::to_i16s(vector))
+    }
+    fn filtered_search<F>(
+        index: &Index,
+        query: &[Self],
+        count: usize,
+        filter: F,
+    ) -> Result<ffi::Matches, cxx::Exception>
+    where
+        Self: Sized,
+        F: Fn(Key) -> bool,
+    {
+        // Trampoline is the function that knows how to call the Rust closure.
+        extern "C" fn trampoline<F: Fn(u64) -> bool>(key: u64, closure_address: usize) -> bool {
+            let closure = closure_address as *const F;
+            unsafe { (*closure)(key) }
+        }
+
+        // Temporarily cast the closure to a raw pointer for passing.
+        unsafe {
+            let trampoline_fn: usize = std::mem::transmute(trampoline::<F> as *const ());
+            let closure_address: usize = &filter as *const F as usize;
+            index.inner.filtered_search_f16(
+                f16::to_i16s(query),
+                count,
+                trampoline_fn,
+                closure_address,
+            )
+        }
+    }
+
+    fn change_metric(
+        index: &mut Index,
+        metric: Box<dyn Fn(*const Self, *const Self) -> Distance + Send + Sync>,
+    ) -> Result<(), cxx::Exception> {
+        // Store the metric function in the Index.
+        type MetricFn = fn(*const f16, *const f16) -> Distance;
+        index.metric_fn = Some(MetricFunction::F16Metric(metric));
+
+        // Trampoline is the function that knows how to call the Rust closure.
+        // The `first` is a pointer to the first vector, `second` is a pointer to the second vector,
+        // and `index_wrapper` is a pointer to the `index` itself, from which we can infer the metric function
+        // and the number of dimensions.
+        extern "C" fn trampoline(first: usize, second: usize, closure_address: usize) -> Distance {
+            let first_ptr = first as *const f16;
+            let second_ptr = second as *const f16;
+            let closure: MetricFn = unsafe { std::mem::transmute(closure_address) };
+            closure(first_ptr, second_ptr)
+        }
+
+        unsafe {
+            let trampoline_fn: usize = std::mem::transmute(trampoline as *const ());
+            let closure_address = match index.metric_fn {
+                Some(MetricFunction::F16Metric(ref metric)) => metric as *const _ as usize,
+                _ => panic!("Expected F16Metric"),
+            };
+            index.inner.change_metric(trampoline_fn, closure_address)
+        }
+
+        Ok(())
+    }
+}
+
+impl VectorType for b1x8 {
+    fn search(index: &Index, query: &[Self], count: usize) -> Result<ffi::Matches, cxx::Exception> {
+        index.inner.search_b1x8(b1x8::to_u8s(query), count)
+    }
+    fn get(index: &Index, key: Key, vector: &mut [Self]) -> Result<usize, cxx::Exception> {
+        index.inner.get_b1x8(key, b1x8::to_mut_u8s(vector))
+    }
+    fn add(index: &Index, key: Key, vector: &[Self]) -> Result<(), cxx::Exception> {
+        index.inner.add_b1x8(key, b1x8::to_u8s(vector))
+    }
+    fn filtered_search<F>(
+        index: &Index,
+        query: &[Self],
+        count: usize,
+        filter: F,
+    ) -> Result<ffi::Matches, cxx::Exception>
+    where
+        Self: Sized,
+        F: Fn(Key) -> bool,
+    {
+        // Trampoline is the function that knows how to call the Rust closure.
+        extern "C" fn trampoline<F: Fn(u64) -> bool>(key: u64, closure_address: usize) -> bool {
+            let closure = closure_address as *const F;
+            unsafe { (*closure)(key) }
+        }
+
+        // Temporarily cast the closure to a raw pointer for passing.
+        unsafe {
+            let trampoline_fn: usize = std::mem::transmute(trampoline::<F> as *const ());
+            let closure_address: usize = &filter as *const F as usize;
+            index.inner.filtered_search_b1x8(
+                b1x8::to_u8s(query),
+                count,
+                trampoline_fn,
+                closure_address,
+            )
+        }
+    }
+
+    fn change_metric(
+        index: &mut Index,
+        metric: Box<dyn Fn(*const Self, *const Self) -> Distance + Send + Sync>,
+    ) -> Result<(), cxx::Exception> {
+        // Store the metric function in the Index.
+        type MetricFn = fn(*const b1x8, *const b1x8) -> Distance;
+        index.metric_fn = Some(MetricFunction::B1X8Metric(metric));
+
+        // Trampoline is the function that knows how to call the Rust closure.
+        // The `first` is a pointer to the first vector, `second` is a pointer to the second vector,
+        // and `index_wrapper` is a pointer to the `index` itself, from which we can infer the metric function
+        // and the number of dimensions.
+        extern "C" fn trampoline(first: usize, second: usize, closure_address: usize) -> Distance {
+            let first_ptr = first as *const b1x8;
+            let second_ptr = second as *const b1x8;
+            let closure: MetricFn = unsafe { std::mem::transmute(closure_address) };
+            closure(first_ptr, second_ptr)
+        }
+
+        unsafe {
+            let trampoline_fn: usize = std::mem::transmute(trampoline as *const ());
+            let closure_address = match index.metric_fn {
+                Some(MetricFunction::B1X8Metric(ref metric)) => metric as *const _ as usize,
+                _ => panic!("Expected B1X8Metric"),
+            };
+            index.inner.change_metric(trampoline_fn, closure_address)
+        }
+
+        Ok(())
+    }
 }
 
 impl Index {
     pub fn new(options: &ffi::IndexOptions) -> Result<Self, cxx::Exception> {
         match ffi::new_native_index(options) {
-            Ok(inner) => Result::Ok(Self { inner }),
+            Ok(inner) => Result::Ok(Self {
+                inner,
+                metric_fn: None,
+            }),
             Err(err) => Err(err),
         }
     }
@@ -194,15 +925,28 @@ impl Index {
     }
 
     /// Updates the expansion value used during index creation. Rarely used.
-    pub fn change_expansion_add(self: &Index, n: usize) -> Result<(), cxx::Exception> {
+    pub fn change_expansion_add(self: &Index, n: usize) {
         self.inner.change_expansion_add(n)
     }
 
     /// Updates the expansion value used during search operations.
-    pub fn change_expansion_search(self: &Index, n: usize) -> Result<(), cxx::Exception> {
+    pub fn change_expansion_search(self: &Index, n: usize) {
         self.inner.change_expansion_search(n)
     }
 
+    /// Changes the metric kind used to calculate the distance between vectors.
+    pub fn change_metric_kind(self: &Index, metric: ffi::MetricKind) {
+        self.inner.change_metric_kind(metric)
+    }
+
+    /// Overrides the metric function used to calculate the distance between vectors.
+    pub fn change_metric<T: VectorType>(
+        self: &mut Index,
+        metric: Box<dyn Fn(*const T, *const T) -> Distance + Send + Sync>,
+    ) {
+        T::change_metric(self, metric).unwrap();
+    }
+
     /// Retrieves the hardware acceleration information.
     pub fn hardware_acceleration(&self) -> String {
         use core::ffi::CStr;
@@ -230,13 +974,37 @@ impl Index {
         T::search(self, query, count)
     }
 
+    /// Performs k-Approximate Nearest Neighbors (kANN) Search for closest vectors to the provided query
+    /// satisfying a custom filter function.
+    ///
+    /// # Arguments
+    ///
+    /// * `query` - A slice containing the query vector data.
+    /// * `count` - The maximum number of neighbors to search for.
+    /// * `filter` - A closure that takes a `Key` and returns `true` if the corresponding vector should be included in the search results, or `false` otherwise.
+    ///
+    /// # Returns
+    ///
+    /// A `Result` containing the matches found.
+    pub fn filtered_search<T: VectorType, F>(
+        self: &Index,
+        query: &[T],
+        count: usize,
+        filter: F,
+    ) -> Result<ffi::Matches, cxx::Exception>
+    where
+        F: Fn(Key) -> bool,
+    {
+        T::filtered_search(self, query, count, filter)
+    }
+
     /// Adds a vector with a specified key to the index.
     ///
     /// # Arguments
     ///
     /// * `key` - The key associated with the vector.
     /// * `vector` - A slice containing the vector data.
-    pub fn add<T: VectorType>(self: &Index, key: u64, vector: &[T]) -> Result<(), cxx::Exception> {
+    pub fn add<T: VectorType>(self: &Index, key: Key, vector: &[T]) -> Result<(), cxx::Exception> {
         T::add(self, key, vector)
     }
 
@@ -253,7 +1021,7 @@ impl Index {
     /// * `vector` - A slice containing the vector data.
     pub fn get<T: VectorType>(
         self: &Index,
-        key: u64,
+        key: Key,
         vector: &mut [T],
     ) -> Result<usize, cxx::Exception> {
         T::get(self, key, vector)
@@ -268,7 +1036,7 @@ impl Index {
     /// * `vector` - A mutable vector containing the vector data.
     pub fn export<T: VectorType + Default + Clone>(
         self: &Index,
-        key: u64,
+        key: Key,
         vector: &mut Vec<T>,
     ) -> Result<usize, cxx::Exception> {
         let dim = self.dimensions();
@@ -325,7 +1093,7 @@ impl Index {
     /// # Returns
     ///
     /// `true` if the vector is successfully removed, `false` otherwise.
-    pub fn remove(self: &Index, key: u64) -> Result<usize, cxx::Exception> {
+    pub fn remove(self: &Index, key: Key) -> Result<usize, cxx::Exception> {
         self.inner.remove(key)
     }
 
@@ -339,7 +1107,7 @@ impl Index {
     /// # Returns
     ///
     /// `true` if the vector is renamed, `false` otherwise.
-    pub fn rename(self: &Index, from: u64, to: u64) -> Result<usize, cxx::Exception> {
+    pub fn rename(self: &Index, from: Key, to: Key) -> Result<usize, cxx::Exception> {
         self.inner.rename(from, to)
     }
 
@@ -352,7 +1120,7 @@ impl Index {
     /// # Returns
     ///
     /// `true` if the index contains the vector with the given key, `false` otherwise.
-    pub fn contains(self: &Index, key: u64) -> bool {
+    pub fn contains(self: &Index, key: Key) -> bool {
         self.inner.contains(key)
     }
 
@@ -365,7 +1133,7 @@ impl Index {
     /// # Returns
     ///
     /// Number of vectors found.
-    pub fn count(self: &Index, key: u64) -> usize {
+    pub fn count(self: &Index, key: Key) -> usize {
         self.inner.count(key)
     }
 
@@ -445,8 +1213,12 @@ mod tests {
     use crate::ffi::MetricKind;
     use crate::ffi::ScalarKind;
 
+    use crate::b1x8;
+    use crate::f16;
     use crate::new_index;
+    use crate::Distance;
     use crate::Index;
+    use crate::Key;
 
     use std::env;
 
@@ -527,6 +1299,7 @@ mod tests {
     fn test_add_get_vector() {
         let mut options = IndexOptions::default();
         options.dimensions = 5;
+        options.quantization = ScalarKind::F32;
         let index = Index::new(&options).unwrap();
         assert!(index.reserve(10).is_ok());
 
@@ -625,10 +1398,10 @@ mod tests {
             index.memory_usage(),
             index.capacity(),
         );
-        assert!(index.change_expansion_add(10).is_ok());
+        index.change_expansion_add(10);
         assert_eq!(index.expansion_add(), 10);
         assert!(index.add(42, &first).is_ok());
-        assert!(index.change_expansion_add(12).is_ok());
+        index.change_expansion_add(12);
         assert_eq!(index.expansion_add(), 12);
         assert!(index.add(43, &second).is_ok());
         assert_eq!(index.size(), 2);
@@ -640,14 +1413,14 @@ mod tests {
             index.capacity(),
         );
 
-        assert!(index.change_expansion_search(10).is_ok());
+        index.change_expansion_search(10);
         assert_eq!(index.expansion_search(), 10);
         // Read back the tags
         let results = index.search(&first, 10).unwrap();
         println!("{:?}", results);
         assert_eq!(results.keys.len(), 2);
 
-        assert!(index.change_expansion_search(12).is_ok());
+        index.change_expansion_search(12);
         assert_eq!(index.expansion_search(), 12);
         let results = index.search(&first, 10).unwrap();
         println!("{:?}", results);
@@ -694,4 +1467,109 @@ mod tests {
         assert_ne!(opts.metric, options.metric);
         assert!(new_index(&opts).is_ok());
     }
+
+    #[test]
+    fn test_search_with_stateless_filter() {
+        let mut options = IndexOptions::default();
+        options.dimensions = 5;
+        let index = Index::new(&options).unwrap();
+        index.reserve(10).unwrap();
+
+        // Adding sample vectors to the index
+        let first: [f32; 5] = [0.2, 0.1, 0.2, 0.1, 0.3];
+        let second: [f32; 5] = [0.3, 0.2, 0.4, 0.0, 0.1];
+        index.add(1, &first).unwrap();
+        index.add(2, &second).unwrap();
+
+        // Stateless filter: checks if the key is odd
+        let is_odd = |key: Key| key % 2 == 1;
+        let query = vec![0.2, 0.1, 0.2, 0.1, 0.3]; // Example query vector
+        let results = index.filtered_search(&query, 10, is_odd).unwrap();
+        assert!(
+            results.keys.iter().all(|&key| key % 2 == 1),
+            "All keys must be odd"
+        );
+    }
+
+    #[test]
+    fn test_search_with_stateful_filter() {
+        use std::collections::HashSet;
+
+        let mut options = IndexOptions::default();
+        options.dimensions = 5;
+        let index = Index::new(&options).unwrap();
+        index.reserve(10).unwrap();
+
+        // Adding sample vectors to the index
+        let first: [f32; 5] = [0.2, 0.1, 0.2, 0.1, 0.3];
+        index.add(1, &first).unwrap();
+        index.add(2, &first).unwrap();
+
+        let allowed_keys = vec![1, 2, 3].into_iter().collect::<HashSet<Key>>();
+        // Clone `allowed_keys` for use in the closure
+        let filter_keys = allowed_keys.clone();
+        let stateful_filter = move |key: Key| filter_keys.contains(&key);
+
+        let query = vec![0.2, 0.1, 0.2, 0.1, 0.3]; // Example query vector
+        let results = index.filtered_search(&query, 10, stateful_filter).unwrap();
+
+        // Use the original `allowed_keys` for assertion
+        assert!(
+            results.keys.iter().all(|&key| allowed_keys.contains(&key)),
+            "All keys must be in the allowed set"
+        );
+    }
+
+    #[test]
+    fn test_change_distance_function() {
+        let mut options = IndexOptions::default();
+        options.dimensions = 2; // Adjusted for simplicity in creating test vectors
+        let mut index = Index::new(&options).unwrap();
+        index.reserve(10).unwrap();
+
+        // Adding a simple vector to test the distance function changes
+        let vector: [f32; 2] = [1.0, 0.0];
+        index.add(1, &vector).unwrap();
+
+        // Stateful distance function with adjustments for pointer to slice conversion
+        let first_factor: f32 = 2.0;
+        let second_factor: f32 = 0.7;
+        let stateful_distance = Box::new(move |a: *const f32, b: *const f32| unsafe {
+            let a_slice = std::slice::from_raw_parts(a, 2);
+            let b_slice = std::slice::from_raw_parts(b, 2);
+            (a_slice[0] - b_slice[0]).abs() * first_factor
+                + (a_slice[1] - b_slice[1]).abs() * second_factor
+        });
+        index.change_metric(stateful_distance);
+    }
+
+    #[test]
+    fn test_binary_vectors_and_hamming_distance() {
+        let index = Index::new(&IndexOptions {
+            dimensions: 8,
+            metric: MetricKind::Hamming,
+            quantization: ScalarKind::B1,
+            ..Default::default()
+        })
+        .unwrap();
+
+        // Binary vectors represented as `b1x8` slices
+        let vector42: Vec<b1x8> = vec![b1x8(0b00001111)];
+        let vector43: Vec<b1x8> = vec![b1x8(0b11110000)];
+        let query: Vec<b1x8> = vec![b1x8(0b01111000)];
+
+        // Adding binary vectors to the index
+        index.reserve(10).unwrap();
+        index.add(42, &vector42).unwrap();
+        index.add(43, &vector43).unwrap();
+
+        let results = index.search(&query, 5).unwrap();
+
+        // Validate the search results based on Hamming distance
+        assert_eq!(results.keys.len(), 2);
+        assert_eq!(results.keys[0], 43);
+        assert_eq!(results.distances[0], 2.0);
+        assert_eq!(results.keys[1], 42);
+        assert_eq!(results.distances[1], 6.0);
+    }
 }
diff --git a/sqlite/lib.cpp b/sqlite/lib.cpp
index e6196a28..8fb6ca0e 100644
--- a/sqlite/lib.cpp
+++ b/sqlite/lib.cpp
@@ -63,7 +63,7 @@ static void sqlite_dense(sqlite3_context* context, int argc, sqlite3_value** arg
         void const* vec2 = sqlite3_value_blob(argv[1]);
 
         std::size_t dimensions = (size_t)(bytes1)*CHAR_BIT / bits_per_scalar(scalar_kind_ak);
-        metric_t metric = metric_t(dimensions, metric_kind_ak, scalar_kind_ak);
+        metric_t metric = metric_t::builtin(dimensions, metric_kind_ak, scalar_kind_ak);
         distance_punned_t distance =
             metric(reinterpret_cast<byte_t const*>(vec1), reinterpret_cast<byte_t const*>(vec2));
         sqlite3_result_double(context, distance);
@@ -148,7 +148,7 @@ static void sqlite_dense(sqlite3_context* context, int argc, sqlite3_value** arg
         }
 
         // Compute the distance itself
-        metric_t metric = metric_t(dimensions, metric_kind_ak, parsed_scalar_kind_gt<scalar_kind_ak>::kind);
+        metric_t metric = metric_t::builtin(dimensions, metric_kind_ak, parsed_scalar_kind_gt<scalar_kind_ak>::kind);
         distance_punned_t distance =
             metric(reinterpret_cast<byte_t const*>(parsed1), reinterpret_cast<byte_t const*>(parsed2));
         sqlite3_result_double(context, distance);
@@ -187,7 +187,7 @@ static void sqlite_dense(sqlite3_context* context, int argc, sqlite3_value** arg
         }
 
         // Compute the distance itself
-        metric_t metric = metric_t(dimensions, metric_kind_ak, parsed_scalar_kind_gt<scalar_kind_ak>::kind);
+        metric_t metric = metric_t::builtin(dimensions, metric_kind_ak, parsed_scalar_kind_gt<scalar_kind_ak>::kind);
         distance_punned_t distance =
             metric(reinterpret_cast<byte_t const*>(parsed1), reinterpret_cast<byte_t const*>(parsed2));
         sqlite3_result_double(context, distance);


Test patch:
diff --git a/c/test.c b/c/test.c
index 1f086a9a..2498aa06 100644
--- a/c/test.c
+++ b/c/test.c
@@ -72,6 +72,8 @@ void test_init(size_t const collection_size, size_t const dimensions) {
     ASSERT(usearch_capacity(index, &error) == collection_size, error);
     ASSERT(usearch_dimensions(index, &error) == dimensions, error);
     ASSERT(usearch_connectivity(index, &error) == opts.connectivity, error);
+    ASSERT(usearch_hardware_acceleration(index, &error), error);
+    ASSERT(usearch_memory_usage(index, &error), error);
 
     usearch_free(index, &error);
     ASSERT(!error, error);
@@ -361,6 +363,8 @@ void test_view(size_t const collection_size, size_t const dimensions) {
 }
 
 int main(int argc, char const* argv[]) {
+    printf("Running tests...\n");
+    printf("USearch version: %s\n", usearch_version());
 
     size_t collection_sizes[] = {11, 512};
     size_t dimensions[] = {83, 2}; // Not all distance functions make sense for 1 dimensional data
diff --git a/cpp/test.cpp b/cpp/test.cpp
index 2bfdcaf3..779cc77d 100644
--- a/cpp/test.cpp
+++ b/cpp/test.cpp
@@ -65,6 +65,17 @@ void test_cosine(index_at& index, std::vector<std::vector<scalar_at>> const& vec
 
     // Perform exact search
     matched_count = index.search(vector_first, 5, args...).dump_to(matched_keys, matched_distances);
+    expect(matched_count != 0);
+
+    // Perform filtered exact search, keeping only odd values
+    if constexpr (punned_ak) {
+        auto is_odd = [](vector_key_t key) -> bool { return (key & 1) != 0; };
+        matched_count =
+            index.filtered_search(vector_first, 5, is_odd, args...).dump_to(matched_keys, matched_distances);
+        expect(matched_count != 0);
+        for (std::size_t i = 0; i < matched_count; i++)
+            expect(is_odd(matched_keys[i]));
+    }
 
     // Validate scans
     std::size_t count = 0;