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

Issue:
Feature: Add swift/obj-c bindings for filteredSearch
### Describe what you are looking for

There are C++ and Rust bindings for filtered search, but they don't yet exist for Swift.

Would love to call this into Swift!  Happy to provide a patch for this.


### Can you contribute to the implementation?

- [X] I can contribute

### Is your feature request specific to a certain interface?

Other bindings

### Contact Details

vardhan.mudunuru@thebrowser.company

### 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:

Fix patch:
diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml
index ef7d3ad3..404b9e11 100644
--- a/.github/workflows/prerelease.yml
+++ b/.github/workflows/prerelease.yml
@@ -33,6 +33,7 @@ jobs:
           version-file: "VERSION"
           update-version-in: |
             package.json:"version": "(\d+\.\d+\.\d+)"
+            package-lock.json:"usearch",\n\s+"version": "(\d+\.\d+\.\d+)"
             CITATION.cff:^version: (\d+\.\d+\.\d+)
             Cargo.toml:^version = "(\d+\.\d+\.\d+)"
             Cargo.lock:name = "usearch"\nversion = "(\d+\.\d+\.\d+)"
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 86ae05bc..94b3b2da 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -33,6 +33,7 @@ jobs:
           version-file: "VERSION"
           update-version-in: |
             package.json:"version": "(\d+\.\d+\.\d+)"
+            package-lock.json:"usearch",\n\s+"version": "(\d+\.\d+\.\d+)"
             CITATION.cff:^version: (\d+\.\d+\.\d+)
             Cargo.toml:^version = "(\d+\.\d+\.\d+)"
             Cargo.lock:name = "usearch"\nversion = "(\d+\.\d+\.\d+)"
diff --git a/.gitignore b/.gitignore
index 5e7a197b..ea441b31 100644
--- a/.gitignore
+++ b/.gitignore
@@ -56,6 +56,9 @@ target/
 .build
 .swiftpm
 
+# Golang builds
+golang/usearch.h
+
 # C# builds
 csharp/**/[Bb]in/
 csharp/**/[Oo]bj/
diff --git a/BENCHMARKS.md b/BENCHMARKS.md
index 84d082a9..df9def46 100644
--- a/BENCHMARKS.md
+++ b/BENCHMARKS.md
@@ -70,21 +70,25 @@ Which would print the following instructions.
 
 ```txt
 SYNOPSIS
-        build_profile/bench_cpp [--vectors <path>] [--queries <path>] [--neighbors <path>] [-b] [-j
-                                <integer>] [-c <integer>] [--expansion-add <integer>]
-                                [--expansion-search <integer>] [--native|--f16quant|--i8quant]
-                                [--ip|--l2sq|--cos|--haversine] [-h]
+        build_profile/bench_cpp [--vectors <path>] [--queries <path>] [--neighbors <path>] [-o
+                                <path>] [-b] [-j <integer>] [-c <integer>] [--expansion-add
+                                <integer>] [--expansion-search <integer>] [--rows-skip <integer>]
+                                [--rows-take <integer>] [-bf16|-f16|-i8|-b1]
+                                [--ip|--l2sq|--cos|--hamming|--tanimoto|--sorensen|--haversine] [-h]
 
 OPTIONS
         --vectors <path>
-                    .fbin file path to construct the index
+                    .[fhbd]bin file path to construct the index
 
         --queries <path>
-                    .fbin file path to query the index
+                    .[fhbd]bin file path to query the index
 
         --neighbors <path>
                     .ibin file path with ground truth
 
+        -o, --output <path>
+                    .usearch output file path
+
         -b, --big   Will switch to uint40_t for neighbors lists with over 4B entries
         -j, --threads <integer>
                     Uses all available cores by default
@@ -98,12 +102,30 @@ OPTIONS
         --expansion-search <integer>
                     Affects search depth
 
-        --native    Use raw templates instead of type-punned classes
-        --f16quant  Enable `f16_t` quantization
-        --i8quant   Enable `int8_t` quantization
+        --rows-skip <integer>
+                    Number of vectors to skip
+
+        --rows-take <integer>
+                    Number of vectors to take
+
+        -bf16, --bf16quant
+                    Enable `bf16_t` quantization
+
+        -f16, --f16quant
+                    Enable `f16_t` quantization
+
+        -i8, --i8quant
+                    Enable `i8_t` quantization
+
+        -b1, --b1quant
+                    Enable `b1x8_t` quantization
+
         --ip        Choose Inner Product metric
         --l2sq      Choose L2 Euclidean metric
         --cos       Choose Angular metric
+        --hamming   Choose Hamming metric
+        --tanimoto  Choose Tanimoto metric
+        --sorensen  Choose Sorensen metric
         --haversine Choose Haversine metric
         -h, --help  Print this help information on this tool and exit
 ```
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index adbc0719..f326e2e0 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -227,6 +227,7 @@ Testing and benchmarking:
 
 ```sh
 npm install -g typescript
+npm install
 npm run build-js
 npm test
 npm run bench
@@ -335,10 +336,10 @@ So one should first compile the C library, link it with GoLang, and only then ru
 cmake -B build_release -DUSEARCH_BUILD_LIB_C=1 -DUSEARCH_BUILD_TEST_C=1 -DUSEARCH_USE_OPENMP=1 -DUSEARCH_USE_SIMSIMD=1 
 cmake --build build_release --config Release -j
 
-mv c/libusearch_c.so golang/ # or .dylib to install the library on MacOS
-cp c/usearch.h golang/ # to make the header available to GoLang
+cp build_release/libusearch_c.so golang/ # or .dylib to install the library on MacOS
+cp c/usearch.h golang/                   # to make the header available to GoLang
 
-cd golang && go test -v ; cd ..
+cd golang && LD_LIBRARY_PATH=. go test -v ; cd ..
 ```
 
 ## Java
diff --git a/Package.swift b/Package.swift
index bd1dec33..7f8375bb 100644
--- a/Package.swift
+++ b/Package.swift
@@ -15,11 +15,13 @@ let package = Package(
         .target(
             name: "USearchObjective",
             path: "objc",
-            sources: ["USearchObjective.mm"],
+            sources: ["USearchObjective.mm"],            
             cxxSettings: [
                 .headerSearchPath("../include/"),
                 .headerSearchPath("../fp16/include/"),
-                .headerSearchPath("../simismd/include/"),
+                .headerSearchPath("../simsimd/include/"),
+                .define("USEARCH_USE_FP16LIB", to: "1"),
+                .define("USEARCH_USE_SIMSIMD", to: "1"),
             ]
         ),
         .target(
diff --git a/cpp/bench.cpp b/cpp/bench.cpp
index ee086ff1..63e7f9d3 100644
--- a/cpp/bench.cpp
+++ b/cpp/bench.cpp
@@ -468,6 +468,7 @@ struct args_t {
 
     bool big = false;
 
+    bool quantize_bf16 = false;
     bool quantize_f16 = false;
     bool quantize_i8 = false;
     bool quantize_b1 = false;
@@ -500,6 +501,8 @@ struct args_t {
     }
 
     scalar_kind_t quantization() const noexcept {
+        if (quantize_bf16)
+            return scalar_kind_t::bf16_k;
         if (quantize_f16)
             return scalar_kind_t::f16_k;
         if (quantize_i8)
@@ -611,6 +614,7 @@ int main(int argc, char** argv) {
         (option("--rows-skip") & value("integer", args.vectors_to_skip)).doc("Number of vectors to skip"),
         (option("--rows-take") & value("integer", args.vectors_to_take)).doc("Number of vectors to take"),
         ( //
+            option("-bf16", "--bf16quant").set(args.quantize_bf16).doc("Enable `bf16_t` quantization") |
             option("-f16", "--f16quant").set(args.quantize_f16).doc("Enable `f16_t` quantization") |
             option("-i8", "--i8quant").set(args.quantize_i8).doc("Enable `i8_t` quantization") |
             option("-b1", "--b1quant").set(args.quantize_b1).doc("Enable `b1x8_t` quantization")),
diff --git a/golang/lib.go b/golang/lib.go
index 6b61b1f1..35099626 100644
--- a/golang/lib.go
+++ b/golang/lib.go
@@ -56,6 +56,27 @@ func (m Metric) String() string {
 		panic("Unknown metric")
 	}
 }
+func (m Metric) CValue() C.usearch_metric_kind_t {
+	switch m {
+	case L2sq:
+		return C.usearch_metric_l2sq_k
+	case InnerProduct:
+		return C.usearch_metric_ip_k
+	case Cosine:
+		return C.usearch_metric_cos_k
+	case Haversine:
+		return C.usearch_metric_haversine_k
+	case Pearson:
+		return C.usearch_metric_pearson_k
+	case Hamming:
+		return C.usearch_metric_hamming_k
+	case Tanimoto:
+		return C.usearch_metric_tanimoto_k
+	case Sorensen:
+		return C.usearch_metric_sorensen_k
+	}
+    return C.usearch_metric_l2sq_k
+}
 
 // Quantization represents the type for different scalar kinds used in quantization.
 type Quantization uint8
@@ -137,28 +158,7 @@ func NewIndex(conf IndexConfig) (index *Index, err error) {
 	options.expansion_add = expansion_add
 	options.expansion_search = expansion_search
 	options.multi = multi
-
-	// Map the metric kind to a C enum
-	switch conf.Metric {
-	case L2sq:
-		options.metric_kind = C.usearch_metric_l2sq_k
-	case InnerProduct:
-		options.metric_kind = C.usearch_metric_ip_k
-	case Cosine:
-		options.metric_kind = C.usearch_metric_cos_k
-	case Haversine:
-		options.metric_kind = C.usearch_metric_haversine_k
-	case Pearson:
-		options.metric_kind = C.usearch_metric_pearson_k
-	case Hamming:
-		options.metric_kind = C.usearch_metric_hamming_k
-	case Tanimoto:
-		options.metric_kind = C.usearch_metric_tanimoto_k
-	case Sorensen:
-		options.metric_kind = C.usearch_metric_sorensen_k
-	default:
-		options.metric_kind = C.usearch_metric_unknown_k
-	}
+    options.metric_kind = conf.Metric.CValue()
 
 	// Map the quantization method
 	switch conf.Quantization {
@@ -196,6 +196,66 @@ func (index *Index) Len() (len uint, err error) {
 	return len, err
 }
 
+// SerializedLength reports the expected file size after serialization.
+func (index *Index) SerializedLength() (len uint, err error) {
+	var errorMessage *C.char
+	len = uint(C.usearch_serialized_length((C.usearch_index_t)(unsafe.Pointer(index.opaque_handle)), (*C.usearch_error_t)(&errorMessage)))
+	if errorMessage != nil {
+		err = errors.New(C.GoString(errorMessage))
+	}
+	return len, err
+}
+
+// MemoryUsage reports the memory usage of the index
+func (index *Index) MemoryUsage() (len uint, err error) {
+	var errorMessage *C.char
+	len = uint(C.usearch_memory_usage((C.usearch_index_t)(unsafe.Pointer(index.opaque_handle)), (*C.usearch_error_t)(&errorMessage)))
+	if errorMessage != nil {
+		err = errors.New(C.GoString(errorMessage))
+	}
+	return len, err
+}
+
+// ExpansionAdd returns the expansion value used during index creation
+func (index *Index) ExpansionAdd() (val uint, err error) {
+	var errorMessage *C.char
+	val = uint(C.usearch_expansion_add((C.usearch_index_t)(unsafe.Pointer(index.opaque_handle)), (*C.usearch_error_t)(&errorMessage)))
+	if errorMessage != nil {
+		err = errors.New(C.GoString(errorMessage))
+	}
+	return val, err
+}
+
+// ExpansionSearch returns the expansion value used during search
+func (index *Index) ExpansionSearch() (val uint, err error) {
+	var errorMessage *C.char
+	val = uint(C.usearch_expansion_search((C.usearch_index_t)(unsafe.Pointer(index.opaque_handle)), (*C.usearch_error_t)(&errorMessage)))
+	if errorMessage != nil {
+		err = errors.New(C.GoString(errorMessage))
+	}
+	return val, err
+}
+
+// ChangeExpansionAdd sets the expansion value used during index creation
+func (index *Index) ChangeExpansionAdd(val uint) error {
+	var errorMessage *C.char
+	C.usearch_change_expansion_add((C.usearch_index_t)(unsafe.Pointer(index.opaque_handle)), C.size_t(val), (*C.usearch_error_t)(&errorMessage))
+	if errorMessage != nil {
+		return errors.New(C.GoString(errorMessage))
+	}
+	return nil
+}
+
+// ChangeExpansionSearch sets the expansion value used during search
+func (index *Index) ChangeExpansionSearch(val uint) error {
+	var errorMessage *C.char
+	C.usearch_change_expansion_search((C.usearch_index_t)(unsafe.Pointer(index.opaque_handle)), C.size_t(val), (*C.usearch_error_t)(&errorMessage))
+	if errorMessage != nil {
+		return errors.New(C.GoString(errorMessage))
+	}
+	return nil
+}
+
 // Connectivity returns the connectivity parameter of the index.
 func (index *Index) Connectivity() (con uint, err error) {
 	var errorMessage *C.char
@@ -226,6 +286,17 @@ func (index *Index) Capacity() (cap uint, err error) {
 	return cap, err
 }
 
+// HardwareAcceleration returns a string showing the SIMD capability for the index
+func (index *Index) HardwareAcceleration() (string, error) {
+	var str *C.char
+	var errorMessage *C.char
+	str = C.usearch_hardware_acceleration((C.usearch_index_t)(unsafe.Pointer(index.opaque_handle)), (*C.usearch_error_t)(&errorMessage))
+	if errorMessage != nil {
+		return C.GoString(nil), errors.New(C.GoString(errorMessage))
+	}
+	return C.GoString(str), nil
+}
+
 // Destroy frees the resources associated with the index.
 func (index *Index) Destroy() error {
 	if index.opaque_handle == nil {
@@ -316,6 +387,27 @@ func (index *Index) Get(key Key, count uint) (vectors []float32, err error) {
 	return vectors, nil
 }
 
+// Rename the vector at key from to key to
+func (index *Index) Rename(from Key, to Key) error {
+	var errorMessage *C.char
+	C.usearch_rename((C.usearch_index_t)(unsafe.Pointer(index.opaque_handle)), C.usearch_key_t(from), C.usearch_key_t(to), (*C.usearch_error_t)(&errorMessage))
+	if errorMessage != nil {
+		return errors.New(C.GoString(errorMessage))
+	}
+	return nil
+}
+
+// Distance computes the distance between two vectors
+func Distance(vec1 []float32, vec2 []float32, dims uint, metric Metric) (float32, error) {
+
+	var errorMessage *C.char
+	dist := C.usearch_distance(unsafe.Pointer(&vec1[0]), unsafe.Pointer(&vec2[0]), C.usearch_scalar_f32_k, C.size_t(dims), metric.CValue(), (*C.usearch_error_t)(&errorMessage))
+	if errorMessage != nil {
+		return 0, errors.New(C.GoString(errorMessage))
+	}
+	return float32(dist), nil
+}
+
 // Search performs k-Approximate Nearest Neighbors Search for the closest vectors to the query vector.
 func (index *Index) Search(query []float32, limit uint) (keys []Key, distances []float32, err error) {
 	if index.opaque_handle == nil {
@@ -338,6 +430,189 @@ func (index *Index) Search(query []float32, limit uint) (keys []Key, distances [
 	return keys, distances, nil
 }
 
+// ExactSearch is a multithreaded exact nearest neighbors search
+func ExactSearch(dataset []float32, queries []float32, dataset_size uint, queries_size uint,
+                dataset_stride uint, queries_stride uint, dims uint, metric Metric, 
+                count uint, threads uint, keys_stride uint, distances_stride uint) (keys []Key, distances []float32, err error) {
+	if (len(dataset) % int(dims)) != 0 {
+		return nil, nil, errors.New("Dataset length must be a multiple of the dimensions")
+	}
+	if (len(queries) % int(dims)) != 0 {
+		return nil, nil, errors.New("Queries length must be a multiple of the dimensions")
+	}
+
+	keys = make([]Key, count)
+	distances = make([]float32, count)
+	var errorMessage *C.char
+	C.usearch_exact_search(unsafe.Pointer(&dataset[0]), C.size_t(dataset_size), C.size_t(dataset_stride), unsafe.Pointer(&queries[0]), C.size_t(queries_size), C.size_t(queries_stride), 
+            C.usearch_scalar_f32_k, C.size_t(dims), metric.CValue(), C.size_t(count), C.size_t(threads),
+            (*C.usearch_key_t)(&keys[0]), C.size_t(keys_stride), (*C.usearch_distance_t)(&distances[0]), C.size_t(distances_stride), (*C.usearch_error_t)(&errorMessage))
+	if errorMessage != nil {
+		return nil, nil, errors.New(C.GoString(errorMessage))
+	}
+
+	keys = keys[:count]
+	distances = distances[:count]
+	return keys, distances, nil
+}
+
+// Save saves the index to a specified buffer.
+func (index *Index) SaveBuffer(buf []byte, buffer_size uint) error {
+	if index.opaque_handle == nil {
+		panic("Index is uninitialized")
+	}
+
+	var errorMessage *C.char
+	C.usearch_save_buffer((C.usearch_index_t)(unsafe.Pointer(index.opaque_handle)), unsafe.Pointer(&buf[0]), C.size_t(buffer_size), (*C.usearch_error_t)(&errorMessage))
+	if errorMessage != nil {
+		return errors.New(C.GoString(errorMessage))
+	}
+	return nil
+}
+
+// Loads the index from a specified buffer.
+func (index *Index) LoadBuffer(buf []byte, buffer_size uint) error {
+	if index.opaque_handle == nil {
+		panic("Index is uninitialized")
+	}
+
+	var errorMessage *C.char
+	C.usearch_load_buffer((C.usearch_index_t)(unsafe.Pointer(index.opaque_handle)), unsafe.Pointer(&buf[0]), C.size_t(buffer_size), (*C.usearch_error_t)(&errorMessage))
+	if errorMessage != nil {
+		return errors.New(C.GoString(errorMessage))
+	}
+	return nil
+}
+
+// Loads the index from a specified buffer without copying the data.
+func (index *Index) ViewBuffer(buf []byte, buffer_size uint) error {
+	if index.opaque_handle == nil {
+		panic("Index is uninitialized")
+	}
+
+	var errorMessage *C.char
+	C.usearch_view_buffer((C.usearch_index_t)(unsafe.Pointer(index.opaque_handle)), unsafe.Pointer(&buf[0]), C.size_t(buffer_size), (*C.usearch_error_t)(&errorMessage))
+	if errorMessage != nil {
+		return errors.New(C.GoString(errorMessage))
+	}
+	return nil
+}
+
+// Loads the metadata from a specified buffer.
+func MetadataBuffer(buf []byte, buffer_size uint) (c IndexConfig, err error) {
+	if buf == nil {
+		panic("Buffer is uninitialized")
+	}
+	c = IndexConfig{}
+
+	options := C.struct_usearch_init_options_t{}
+
+	var errorMessage *C.char
+	C.usearch_metadata_buffer(unsafe.Pointer(&buf[0]), C.size_t(buffer_size), &options, (*C.usearch_error_t)(&errorMessage))
+	if errorMessage != nil {
+		return c, errors.New(C.GoString(errorMessage))
+	}
+
+	c.Dimensions = uint(options.dimensions)
+	c.Connectivity = uint(options.connectivity)
+	c.ExpansionAdd = uint(options.expansion_add)
+	c.ExpansionSearch = uint(options.expansion_search)
+	c.Multi = bool(options.multi)
+
+	// Map the metric kind
+	switch options.metric_kind {
+    case C.usearch_metric_l2sq_k:
+	    c.Metric = L2sq
+	case C.usearch_metric_ip_k:
+	    c.Metric = InnerProduct
+    case C.usearch_metric_cos_k:
+	    c.Metric = Cosine
+    case C.usearch_metric_haversine_k:
+	    c.Metric = Haversine
+    case C.usearch_metric_pearson_k:
+	    c.Metric = Pearson
+    case C.usearch_metric_hamming_k:
+	    c.Metric = Hamming
+    case C.usearch_metric_tanimoto_k:
+	    c.Metric = Tanimoto
+    case C.usearch_metric_sorensen_k:
+	    c.Metric = Sorensen
+    }
+
+	// Map the quantization method
+	switch options.quantization {
+    case C.usearch_scalar_f16_k:
+	    c.Quantization = F16
+    case C.usearch_scalar_f32_k:
+	    c.Quantization = F32
+	case C.usearch_scalar_f64_k:
+	    c.Quantization = F64
+	case C.usearch_scalar_i8_k:
+	    c.Quantization = I8
+	case C.usearch_scalar_b1_k:
+	    c.Quantization = B1
+	}
+
+	return c, nil
+}
+
+// Metadata loads the metadata from a specified file.
+func Metadata(path string) (c IndexConfig, err error)  {
+
+	c_path := C.CString(path)
+	defer C.free(unsafe.Pointer(c_path))
+
+	options := C.struct_usearch_init_options_t{}
+
+	var errorMessage *C.char
+	C.usearch_metadata(c_path, &options, (*C.usearch_error_t)(&errorMessage))
+	if errorMessage != nil {
+		return c, errors.New(C.GoString(errorMessage))
+	}
+
+	c.Dimensions = uint(options.dimensions)
+	c.Connectivity = uint(options.connectivity)
+	c.ExpansionAdd = uint(options.expansion_add)
+	c.ExpansionSearch = uint(options.expansion_search)
+	c.Multi = bool(options.multi)
+
+	// Map the metric kind
+	switch options.metric_kind {
+    case C.usearch_metric_l2sq_k:
+	    c.Metric = L2sq
+	case C.usearch_metric_ip_k:
+	    c.Metric = InnerProduct
+    case C.usearch_metric_cos_k:
+	    c.Metric = Cosine
+    case C.usearch_metric_haversine_k:
+	    c.Metric = Haversine
+    case C.usearch_metric_pearson_k:
+	    c.Metric = Pearson
+    case C.usearch_metric_hamming_k:
+	    c.Metric = Hamming
+    case C.usearch_metric_tanimoto_k:
+	    c.Metric = Tanimoto
+    case C.usearch_metric_sorensen_k:
+	    c.Metric = Sorensen
+    }
+
+	// Map the quantization method
+	switch options.quantization {
+    case C.usearch_scalar_f16_k:
+	    c.Quantization = F16
+    case C.usearch_scalar_f32_k:
+	    c.Quantization = F32
+	case C.usearch_scalar_f64_k:
+	    c.Quantization = F64
+	case C.usearch_scalar_i8_k:
+	    c.Quantization = I8
+	case C.usearch_scalar_b1_k:
+	    c.Quantization = B1
+	}
+
+	return c, nil
+}
+
 // Save saves the index to a specified file.
 func (index *Index) Save(path string) error {
 	if index.opaque_handle == nil {
diff --git a/include/usearch/index_dense.hpp b/include/usearch/index_dense.hpp
index 62bef01a..4b6a798b 100644
--- a/include/usearch/index_dense.hpp
+++ b/include/usearch/index_dense.hpp
@@ -950,7 +950,7 @@ class index_dense_gt {
 
     void reserve(index_limits_t limits) {
         if (!try_reserve(limits))
-            throw std::bad_alloc();
+            __usearch_raise_runtime_error("failed to reserve memory");
     }
 
     /**
diff --git a/include/usearch/index_plugins.hpp b/include/usearch/index_plugins.hpp
index 84f628bd..c7c75d95 100644
--- a/include/usearch/index_plugins.hpp
+++ b/include/usearch/index_plugins.hpp
@@ -72,25 +72,8 @@ struct uuid_t {
 class f16_bits_t;
 class bf16_bits_t;
 
-#if !USEARCH_USE_FP16LIB
-#if USEARCH_USE_SIMSIMD
-using f16_native_t = simsimd_f16_t;
-using bf16_native_t = simsimd_bf16_t;
-#elif defined(USEARCH_DEFINED_ARM)
-using f16_native_t = __fp16;
-using bf16_native_t = __fp16; // No better choice on most compilers!
-#else
-using f16_native_t = _Float16;
-using bf16_native_t = _Float16; // No better choice on most compilers!
-#endif
-using f16_t = f16_native_t;
-using bf16_t = bf16_native_t;
-#else
-using f16_native_t = void;
-using bf16_native_t = void;
 using f16_t = f16_bits_t;
 using bf16_t = bf16_bits_t;
-#endif
 
 using f64_t = double;
 using f32_t = float;
@@ -156,12 +139,6 @@ enum class scalar_kind_t : std::uint8_t {
     i8_k = 23,
 };
 
-enum class prefetching_kind_t {
-    none_k,
-    cpu_k,
-    io_uring_k,
-};
-
 template <typename scalar_at> scalar_kind_t scalar_kind() noexcept {
     if (std::is_same<scalar_at, b1x8_t>())
         return scalar_kind_t::b1x8_k;
@@ -352,12 +329,14 @@ inline expected_gt<metric_kind_t> metric_from_name(char const* name) {
  *  @brief Convenience function to upcast a half-precision floating point number to a single-precision one.
  */
 inline float f16_to_f32(std::uint16_t u16) noexcept {
-#if !USEARCH_USE_FP16LIB
+#if USEARCH_USE_FP16LIB
+    return fp16_ieee_to_fp32_value(u16);
+#elif USEARCH_USE_SIMSIMD
+    return simsimd_uncompress_f16(u16);
+#else
     f16_native_t f16;
     std::memcpy(&f16, &u16, sizeof(std::uint16_t));
     return float(f16);
-#else
-    return fp16_ieee_to_fp32_value(u16);
 #endif
 }
 
@@ -365,13 +344,15 @@ inline float f16_to_f32(std::uint16_t u16) noexcept {
  *  @brief Convenience function to downcast a single-precision floating point number to a half-precision one.
  */
 inline std::uint16_t f32_to_f16(float f32) noexcept {
-#if !USEARCH_USE_FP16LIB
+#if USEARCH_USE_FP16LIB
+    return fp16_ieee_from_fp32_value(f32);
+#elif USEARCH_USE_SIMSIMD
+    return simsimd_compress_f16(f32);
+#else
     f16_native_t f16 = f16_native_t(f32);
     std::uint16_t u16;
     std::memcpy(&u16, &f16, sizeof(std::uint16_t));
     return u16;
-#else
-    return fp16_ieee_from_fp32_value(f32);
 #endif
 }
 
@@ -380,6 +361,9 @@ inline std::uint16_t f32_to_f16(float f32) noexcept {
  *  https://github.com/ashvardanian/SimSIMD/blob/ff51434d90c66f916e94ff05b24530b127aa4cff/include/simsimd/types.h#L395-L410
  */
 inline float bf16_to_f32(std::uint16_t u16) noexcept {
+#if USEARCH_USE_SIMSIMD
+    return simsimd_uncompress_bf16(u16);
+#else
     union float_or_unsigned_int_t {
         float f;
         unsigned int i;
@@ -387,6 +371,7 @@ inline float bf16_to_f32(std::uint16_t u16) noexcept {
     union float_or_unsigned_int_t result_union;
     result_union.i = u16 << 16; // Zero extends the mantissa
     return result_union.f;
+#endif
 }
 
 /**
@@ -394,6 +379,9 @@ inline float bf16_to_f32(std::uint16_t u16) noexcept {
  *  https://github.com/ashvardanian/SimSIMD/blob/ff51434d90c66f916e94ff05b24530b127aa4cff/include/simsimd/types.h#L412-L425
  */
 inline std::uint16_t f32_to_bf16(float f32) noexcept {
+#if USEARCH_USE_SIMSIMD
+    return simsimd_compress_bf16(f32);
+#else
     union float_or_unsigned_int_t {
         float f;
         unsigned int i;
@@ -403,6 +391,7 @@ inline std::uint16_t f32_to_bf16(float f32) noexcept {
     value.i >>= 16;
     value.i &= 0xFFFF;
     return (unsigned short)value.i;
+#endif
 }
 
 /**
@@ -1047,6 +1036,10 @@ template <> struct cast_gt<f16_bits_t, f16_bits_t> {
     static bool try_(byte_t const*, std::size_t, byte_t*) noexcept { return false; }
 };
 
+template <> struct cast_gt<bf16_bits_t, bf16_bits_t> {
+    static bool try_(byte_t const*, std::size_t, byte_t*) noexcept { return false; }
+};
+
 template <> struct cast_gt<i8_t, i8_t> {
     static bool try_(byte_t const*, std::size_t, byte_t*) noexcept { return false; }
 };
@@ -1119,23 +1112,23 @@ template <typename to_scalar_at> struct cast_from_i8_gt {
     }
 };
 
-template <> struct cast_gt<i8_t, f16_t> : public cast_from_i8_gt<f16_t> {};
-template <> struct cast_gt<i8_t, bf16_t> : public cast_from_i8_gt<bf16_t> {};
+template <> struct cast_gt<i8_t, f16_bits_t> : public cast_from_i8_gt<f16_t> {};
+template <> struct cast_gt<i8_t, bf16_bits_t> : public cast_from_i8_gt<bf16_t> {};
 template <> struct cast_gt<i8_t, f32_t> : public cast_from_i8_gt<f32_t> {};
 template <> struct cast_gt<i8_t, f64_t> : public cast_from_i8_gt<f64_t> {};
 
-template <> struct cast_gt<f16_t, i8_t> : public cast_to_i8_gt<f16_t> {};
-template <> struct cast_gt<bf16_t, i8_t> : public cast_to_i8_gt<bf16_t> {};
+template <> struct cast_gt<f16_bits_t, i8_t> : public cast_to_i8_gt<f16_t> {};
+template <> struct cast_gt<bf16_bits_t, i8_t> : public cast_to_i8_gt<bf16_t> {};
 template <> struct cast_gt<f32_t, i8_t> : public cast_to_i8_gt<f32_t> {};
 template <> struct cast_gt<f64_t, i8_t> : public cast_to_i8_gt<f64_t> {};
 
-template <> struct cast_gt<b1x8_t, f16_t> : public cast_from_b1x8_gt<f16_t> {};
-template <> struct cast_gt<b1x8_t, bf16_t> : public cast_from_b1x8_gt<bf16_t> {};
+template <> struct cast_gt<b1x8_t, f16_bits_t> : public cast_from_b1x8_gt<f16_t> {};
+template <> struct cast_gt<b1x8_t, bf16_bits_t> : public cast_from_b1x8_gt<bf16_t> {};
 template <> struct cast_gt<b1x8_t, f32_t> : public cast_from_b1x8_gt<f32_t> {};
 template <> struct cast_gt<b1x8_t, f64_t> : public cast_from_b1x8_gt<f64_t> {};
 
-template <> struct cast_gt<f16_t, b1x8_t> : public cast_to_b1x8_gt<f16_t> {};
-template <> struct cast_gt<bf16_t, b1x8_t> : public cast_to_b1x8_gt<bf16_t> {};
+template <> struct cast_gt<f16_bits_t, b1x8_t> : public cast_to_b1x8_gt<f16_t> {};
+template <> struct cast_gt<bf16_bits_t, b1x8_t> : public cast_to_b1x8_gt<bf16_t> {};
 template <> struct cast_gt<f32_t, b1x8_t> : public cast_to_b1x8_gt<f32_t> {};
 template <> struct cast_gt<f64_t, b1x8_t> : public cast_to_b1x8_gt<f64_t> {};
 
@@ -2088,7 +2081,7 @@ class flat_hash_multi_set_gt {
         // Allocate new memory
         data_ = (char*)allocator_t{}.allocate(other.buckets_ * bytes_per_bucket());
         if (!data_)
-            throw std::bad_alloc();
+            __usearch_raise_runtime_error("failed memory allocation");
 
         // Copy metadata
         buckets_ = other.buckets_;
@@ -2128,7 +2121,7 @@ class flat_hash_multi_set_gt {
         // Allocate new memory
         data_ = (char*)allocator_t{}.allocate(other.buckets_ * bytes_per_bucket());
         if (!data_)
-            throw std::bad_alloc();
+            __usearch_raise_runtime_error("failed memory allocation");
 
         // Copy metadata
         buckets_ = other.buckets_;
@@ -2501,7 +2494,7 @@ class flat_hash_multi_set_gt {
 
     void reserve(std::size_t capacity) {
         if (!try_reserve(capacity))
-            throw std::bad_alloc();
+            __usearch_raise_runtime_error("failed to reserve memory");
     }
 
     bool try_emplace(element_t const& element) noexcept {
diff --git a/objc/README.md b/objc/README.md
index 39dc03e3..0dd798ed 100644
--- a/objc/README.md
+++ b/objc/README.md
@@ -106,4 +106,6 @@ UInt32 count = [index count:42];
 
 ## Performance Considerations
 
-Tune the `connectivity`, `quantization`, and other parameters according to the size and dimensionality of your dataset. These settings can significantly affect both the performance and accuracy of your searches. The choice of metric and scalar type (e.g., `USearchScalarF32`, `USearchScalarF16`) also influences the memory usage and computation speed.
+Tune the `connectivity`, `quantization`, and other parameters according to the size and dimensionality of your dataset.
+These settings can significantly affect both the performance and accuracy of your searches.
+The choice of metric and scalar type (e.g., `USearchScalarF32`, `USearchScalarF16`, `USearchScalarF16`) also influences the memory usage and computation speed.
diff --git a/objc/USearchObjective.mm b/objc/USearchObjective.mm
index ad235f10..c8b364d8 100644
--- a/objc/USearchObjective.mm
+++ b/objc/USearchObjective.mm
@@ -61,6 +61,9 @@ scalar_kind_t to_native_scalar(USearchScalar m) {
         case USearchScalarF16:
             return scalar_kind_t::f16_k;
 
+        case USearchScalarBF16:
+            return scalar_kind_t::bf16_k;
+
         case USearchScalarF32:
             return scalar_kind_t::f32_k;
 
@@ -116,10 +119,23 @@ - (UInt32)expansionSearch {
     return static_cast<UInt32>(_native->expansion_search());
 }
 
-+ (instancetype)make:(USearchMetric)metricKind dimensions:(UInt32)dimensions connectivity:(UInt32)connectivity quantization:(USearchScalar)quantization {
++ (instancetype)make:(USearchMetric)metricKind
+          dimensions:(UInt32)dimensions
+        connectivity:(UInt32)connectivity
+        quantization:(USearchScalar)quantization {
+    // Create a single-vector index by default
+    return [self make:metricKind dimensions:dimensions connectivity:connectivity quantization:quantization multi:false];
+}
+
++ (instancetype)make:(USearchMetric)metricKind
+          dimensions:(UInt32)dimensions
+        connectivity:(UInt32)connectivity
+        quantization:(USearchScalar)quantization
+               multi:(BOOL)multi {
     std::size_t dims = static_cast<std::size_t>(dimensions);
 
-    index_config_t config(static_cast<std::size_t>(connectivity));
+    index_dense_config_t config(static_cast<std::size_t>(connectivity));
+    config.multi = multi;
     metric_punned_t metric(dims, to_native_metric(metricKind), to_native_scalar(quantization));
     if (metric.missing()) {
         @throw [NSException exceptionWithName:@"Can't create an index"
@@ -158,6 +174,30 @@ - (UInt32)searchSingle:(Float32 const *_Nonnull)vector
     return static_cast<UInt32>(found);
 }
 
+- (UInt32)getSingle:(USearchKey)key
+             vector:(void *_Nonnull)vector
+              count:(UInt32)wanted {
+    std::size_t result = _native->get(key, (f32_t*)vector, static_cast<std::size_t>(wanted));
+    return static_cast<UInt32>(result);
+}
+
+- (UInt32)filteredSearchSingle:(Float32 const *_Nonnull)vector
+                 count:(UInt32)wanted
+                filter:(USearchFilterFn)predicate
+                  keys:(USearchKey *_Nullable)keys
+             distances:(Float32 *_Nullable)distances {
+    search_result_t result = _native->filtered_search(vector, static_cast<std::size_t>(wanted), predicate);
+
+    if (!result) {
+        @throw [NSException exceptionWithName:@"Can't find in index"
+                                       reason:[NSString stringWithUTF8String:result.error.release()]
+                                     userInfo:nil];
+    }
+
+    std::size_t found = result.dump_to(keys, distances);
+    return static_cast<UInt32>(found);
+}
+
 - (void)addDouble:(USearchKey)key
            vector:(Float64 const *_Nonnull)vector {
     add_result_t result = _native->add(key, (f64_t const *)vector);
@@ -185,6 +225,30 @@ - (UInt32)searchDouble:(Float64 const *_Nonnull)vector
     return static_cast<UInt32>(found);
 }
 
+- (UInt32)getDouble:(USearchKey)key
+             vector:(void *_Nonnull)vector
+              count:(UInt32)wanted {
+    std::size_t result = _native->get(key, (f64_t*)vector, static_cast<std::size_t>(wanted));
+    return static_cast<UInt32>(result);
+}
+
+- (UInt32)filteredSearchDouble:(Float64 const *_Nonnull)vector
+                 count:(UInt32)wanted
+                filter:(USearchFilterFn)predicate
+                  keys:(USearchKey *_Nullable)keys
+             distances:(Float32 *_Nullable)distances {
+    search_result_t result = _native->filtered_search((f64_t const *) vector, static_cast<std::size_t>(wanted), predicate);
+
+    if (!result) {
+        @throw [NSException exceptionWithName:@"Can't find in index"
+                                       reason:[NSString stringWithUTF8String:result.error.release()]
+                                     userInfo:nil];
+    }
+
+    std::size_t found = result.dump_to(keys, distances);
+    return static_cast<UInt32>(found);
+}
+
 - (void)addHalf:(USearchKey)key
          vector:(void const *_Nonnull)vector {
     add_result_t result = _native->add(key, (f16_t const *)vector);
@@ -212,6 +276,13 @@ - (UInt32)searchHalf:(void const *_Nonnull)vector
     return static_cast<UInt32>(found);
 }
 
+- (UInt32)getHalf:(USearchKey)key
+           vector:(void *_Nonnull)vector
+            count:(UInt32)wanted {
+    std::size_t result = _native->get(key, (f16_t*)vector, static_cast<std::size_t>(wanted));
+    return static_cast<UInt32>(result);
+}
+
 - (void)clear {
     _native->clear();
 }
diff --git a/objc/include/USearchObjective.h b/objc/include/USearchObjective.h
index 8cf33945..31606774 100644
--- a/objc/include/USearchObjective.h
+++ b/objc/include/USearchObjective.h
@@ -9,7 +9,8 @@ typedef NS_ENUM(NSUInteger, USearchScalar) {
     USearchScalarF16,
     USearchScalarF64,
     USearchScalarI8,
-    USearchScalarB1
+    USearchScalarB1,
+    USearchScalarBF16,
 };
 
 typedef NS_ENUM(NSUInteger, USearchMetric) {
@@ -28,6 +29,8 @@ typedef NS_ENUM(NSUInteger, USearchMetric) {
 
 typedef UInt64 USearchKey;
 
+typedef bool (^USearchFilterFn)(USearchKey key);
+
 API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0))
 @interface USearchIndex : NSObject
 
@@ -52,6 +55,22 @@ API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0))
  */
 + (instancetype)make:(USearchMetric)metric dimensions:(UInt32)dimensions connectivity:(UInt32)connectivity quantization:(USearchScalar)quantization NS_SWIFT_NAME(make(metric:dimensions:connectivity:quantization:));
 
+/**
+ * @brief Initializes a new index.
+ * @param metric The distance function to compare the dis-similarity of vectors.
+ * @param dimensions The number of dimensions planned for this index.
+ * @param connectivity Number of connections per node in the proximity graph.
+ * Higher connectivity improves quantization, increases memory usage, and reduces construction speed.
+ * @param quantization Quantization of internal vector representations. Lower quantization means higher speed.
+ * @param multi Enables indexing multiple vectors per key when true.
+ */
++ (instancetype)make:(USearchMetric)metricKind
+          dimensions:(UInt32)dimensions
+        connectivity:(UInt32)connectivity
+        quantization:(USearchScalar)quantization
+               multi:(BOOL)multi NS_SWIFT_NAME(make(metric:dimensions:connectivity:quantization:multi:));
+
+
 /**
  * @brief Pre-allocates space in the index for the given number of vectors.
  */
@@ -77,6 +96,32 @@ API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0))
                   keys:(USearchKey *_Nullable)keys
              distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(searchSingle(vector:count:keys:distances:));
 
+/**
+* @brief Retrieves a labeled single-precision vector from the index.
+* @param vector A buffer to store the vector.
+* @param count For multi-indexes, the number of vectors to retrieve.
+* @return Number of vectors exported to `vector`.
+*/
+- (UInt32)getSingle:(USearchKey)key
+    vector:(void *_Nonnull)vector
+    count:(UInt32)count NS_SWIFT_NAME(getSingle(key:vector:count:));
+
+/**
+ * @brief Approximate nearest neighbors search.
+ * @param vector Double-precision query vector.
+ * @param count Upper limit on the number of matches to retrieve.
+ * @param filter Closure called for each key, determining whether to include or
+ *               skip key in the results.
+ * @param keys Optional output buffer for keys of approximate neighbors.
+ * @param distances Optional output buffer for (increasing) distances to approximate neighbors.
+ * @return Number of matches exported to `keys` and `distances`.
+ */
+- (UInt32)filteredSearchSingle:(Float32 const *_Nonnull)vector
+                 count:(UInt32)count
+                filter:(USearchFilterFn)filter
+                  keys:(USearchKey *_Nullable)keys
+             distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(filteredSearchSingle(vector:count:filter:keys:distances:));
+
 /**
  * @brief Adds a labeled vector to the index.
  * @param vector Double-precision vector.
@@ -97,6 +142,31 @@ API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0))
                   keys:(USearchKey *_Nullable)keys
              distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(searchDouble(vector:count:keys:distances:));
 
+/**
+* @brief Retrieves a labeled double-precision vector from the index.
+* @param vector A buffer to store the vector.
+* @param count For multi-indexes, the number of vectors to retrieve.
+* @return Number of vectors exported to `vector`.
+*/
+- (UInt32)getDouble:(USearchKey)key
+    vector:(void *_Nonnull)vector
+    count:(UInt32)count NS_SWIFT_NAME(getDouble(key:vector:count:));
+
+/**
+ * @brief Approximate nearest neighbors search.
+ * @param vector Double-precision query vector.
+ * @param count Upper limit on the number of matches to retrieve.
+ * @param filter Closure called for each key, determining whether to include or
+ *               skip key in the results.
+ * @param keys Optional output buffer for keys of approximate neighbors.
+ * @param distances Optional output buffer for (increasing) distances to approximate neighbors.
+ * @return Number of matches exported to `keys` and `distances`.
+ */
+- (UInt32)filteredSearchDouble:(Float64 const *_Nonnull)vector
+                 count:(UInt32)wanted
+                filter:(USearchFilterFn)predicate
+                  keys:(USearchKey *_Nullable)keys
+             distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(filteredSearchDouble(vector:count:filter:keys:distances:));
 /**
  * @brief Adds a labeled vector to the index.
  * @param vector Half-precision vector.
@@ -117,6 +187,15 @@ API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0), watchos(6.0))
                 keys:(USearchKey *_Nullable)keys
            distances:(Float32 *_Nullable)distances NS_SWIFT_NAME(searchHalf(vector:count:keys:distances:));
 
+/**
+* @brief Retrieves a labeled half-precision vector from the index.
+* @param vector A buffer to store the vector.
+* @param count For multi-indexes, the number of vectors to retrieve.
+* @return Number of vectors exported to `vector`.
+*/
+- (UInt32)getHalf:(USearchKey)key
+        vector:(void *_Nonnull)vector
+        count:(UInt32)count NS_SWIFT_NAME(getHalf(key:vector:count:));
 
 - (Boolean)contains:(USearchKey)key NS_SWIFT_NAME(contains(key:));
 
diff --git a/package-lock.json b/package-lock.json
index 43681b21..fd993382 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
     "name": "usearch",
-    "version": "2.10.5",
+    "version": "2.14.0",
     "lockfileVersion": 3,
     "requires": true,
     "packages": {
         "": {
             "name": "usearch",
-            "version": "2.10.5",
+            "version": "2.14.0",
             "hasInstallScript": true,
             "license": "Apache 2.0",
             "dependencies": {
diff --git a/python/lib.cpp b/python/lib.cpp
index fa1665da..c21f330a 100644
--- a/python/lib.cpp
+++ b/python/lib.cpp
@@ -565,7 +565,7 @@ template <typename scalar_at> struct rows_lookup_gt {
  *      2. vector of distances to those clusters,
  *      3. array with match counts, set to all ones,
  *      4. number of visited nodes,
- *      4. number of computed pairwise distances.
+ *      5. number of computed pairwise distances.
  */
 template <typename index_at>
 static py::tuple cluster_vectors(        //
@@ -639,7 +639,7 @@ static py::tuple cluster_vectors(        //
  *      2. vector of distances to those clusters,
  *      3. array with match counts, set to all ones,
  *      4. number of visited nodes,
- *      4. number of computed pairwise distances.
+ *      5. number of computed pairwise distances.
  */
 template <typename index_at>
 static py::tuple cluster_keys(                            //
diff --git a/python/usearch/index.py b/python/usearch/index.py
index aeda1771..2a4fc1a2 100644
--- a/python/usearch/index.py
+++ b/python/usearch/index.py
@@ -7,6 +7,7 @@
 # Python tooling, linters, and static analyzers. It also embeds JIT
 # into the primary `Index` class, connecting USearch with Numba.
 import os
+import sys
 import math
 from dataclasses import dataclass
 from typing import (
@@ -61,7 +62,15 @@ class CompiledMetric(NamedTuple):
     signature: MetricSignature
 
 
-Key = np.uint64
+# Define TypeAlias for older Python versions
+if sys.version_info >= (3, 10):
+    from typing import TypeAlias
+else:
+    TypeAlias = object  # Fallback for older Python versions
+
+Key: TypeAlias = np.uint64
+
+NoneType: TypeAlias = type(None)
 
 KeyOrKeysLike = Union[Key, Iterable[Key], int, Iterable[int], np.ndarray, memoryview]
 
@@ -71,8 +80,6 @@ class CompiledMetric(NamedTuple):
 
 MetricLike = Union[str, MetricKind, CompiledMetric]
 
-NoneType = type(None)
-
 PathOrBuffer = Union[str, os.PathLike, bytes]
 
 ProgressCallback = Callable[[int, int], bool]
diff --git a/rust/lib.rs b/rust/lib.rs
index 603d3bc7..a46110c4 100644
--- a/rust/lib.rs
+++ b/rust/lib.rs
@@ -1648,21 +1648,29 @@ mod tests {
             quantization: ScalarKind::F16,
             ..Default::default()
         };
-    
+
         let index = new_index(&options).unwrap();
         index.reserve(10).unwrap();
-        index.add(0, &[0.4, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0]).unwrap();
-        index.add(1, &[0.5, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0]).unwrap();
-        index.add(2, &[0.6, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0]).unwrap();
+        index
+            .add(0, &[0.4, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0])
+            .unwrap();
+        index
+            .add(1, &[0.5, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0])
+            .unwrap();
+        index
+            .add(2, &[0.6, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0])
+            .unwrap();
 
         // Make sure non of the distances are zeros
-        let matches = index.search(&[0.05, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0], 2).unwrap();
+        let matches = index
+            .search(&[0.05, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0], 2)
+            .unwrap();
         for distance in matches.distances.iter() {
             assert_ne!(*distance, 0.0);
-        }        
+        }
     }
 
-        #[test]
+    #[test]
     fn test_change_distance_function() {
         let mut options = IndexOptions::default();
         options.dimensions = 2; // Adjusted for simplicity in creating test vectors
diff --git a/swift/Index+Sugar.swift b/swift/Index+Sugar.swift
index 83569e46..7056891e 100644
--- a/swift/Index+Sugar.swift
+++ b/swift/Index+Sugar.swift
@@ -10,6 +10,9 @@ extension USearchIndex {
     public typealias Key = USearchKey
     public typealias Metric = USearchMetric
     public typealias Scalar = USearchScalar
+    /// Function type used to filter out keys in results during search.
+    /// The filter function should return true to include, and false to skip.
+    public typealias FilterFn = (Key) -> Bool
 
     /// Adds a labeled vector to the index.
     /// - Parameter key: Unique identifier for that object.
@@ -54,6 +57,31 @@ extension USearchIndex {
         return search(vector: vector[...], count: count)
     }
 
+    /// Retrieve vectors for a given key.
+    /// - Parameter key: Unique identifier for that object.
+    /// - Parameter count: For multi-indexes, Number of vectors to retrieve. Defaults to 1.
+    /// - Returns: Two-dimensional array of Single-precision vectors.
+    /// - Throws: If runs out of memory.
+    public func get(key: USearchKey, count: Int = 1) -> [[Float]]? {
+        var vector: [Float] = Array(repeating: 0.0, count: Int(self.dimensions) * count)
+        let returnedCount = vector.withContiguousMutableStorageIfAvailable { buf in
+            guard let baseAddress = buf.baseAddress else { return UInt32(0) }
+            return getSingle(
+                key: key,
+                vector: baseAddress,
+                count: CUnsignedInt(count)
+            )
+        }
+        guard let count = returnedCount, count > 0 else { return nil }
+        return stride(
+            from: 0,
+            to: Int(count) * Int(self.dimensions),
+            by: Int(self.dimensions)
+        ).map {
+            Array(vector[$0 ..< $0 + Int(self.dimensions)])
+        }
+    }
+
     /// Adds a labeled vector to the index.
     /// - Parameter key: Unique identifier for that object.
     /// - Parameter vector: Double-precision vector.
@@ -97,6 +125,101 @@ extension USearchIndex {
         search(vector: vector[...], count: count)
     }
 
+    /// Retrieve vectors for a given key.
+    /// - Parameter key: Unique identifier for that object.
+    /// - Parameter count: For multi-indexes, Number of vectors to retrieve. Defaults to 1.
+    /// - Returns: Two-dimensional array of Double-precision vectors.
+    /// - Throws: If runs out of memory.
+    public func get(key: USearchKey, count: Int = 1) -> [[Float64]]? {
+        var vector: [Float64] = Array(repeating: 0.0, count: Int(self.dimensions) * count)
+        let count = vector.withContiguousMutableStorageIfAvailable { buf in
+            guard let baseAddress = buf.baseAddress else { return UInt32(0) }
+            return getDouble(
+                key: key,
+                vector: baseAddress,
+                count: CUnsignedInt(count)
+            )
+        }
+        guard let count = count, count > 0 else { return nil }
+        return stride(
+            from: 0,
+            to: Int(count) * Int(self.dimensions),
+            by: Int(self.dimensions)
+        ).map {
+            Array(vector[$0 ..< $0 + Int(self.dimensions)])
+        }
+    }
+
+    /// Approximate nearest neighbors search.
+    /// - Parameter vector: Single-precision query vector.
+    /// - Parameter count: Upper limit on the number of matches to retrieve.
+    /// - Parameter filter: Closure used to determine whether to skip a key in the results.
+    /// - Returns: Labels and distances to closest approximate matches in decreasing similarity order.
+    /// - Throws: If runs out of memory.
+    public func filteredSearch(vector: ArraySlice<Float32>, count: Int, filter: @escaping FilterFn) -> ([Key], [Float])
+    {
+        var matches: [Key] = Array(repeating: 0, count: count)
+        var distances: [Float] = Array(repeating: 0, count: count)
+        let results = vector.withContiguousStorageIfAvailable {
+            filteredSearchSingle(
+                vector: $0.baseAddress!,
+                count:
+                    CUnsignedInt(count),
+                filter: filter,
+                keys: &matches,
+                distances: &distances
+            )
+        }
+        matches.removeLast(count - Int(results!))
+        distances.removeLast(count - Int(results!))
+        return (matches, distances)
+    }
+
+    /// Approximate nearest neighbors search.
+    /// - Parameter vector: Single-precision query vector.
+    /// - Parameter count: Upper limit on the number of matches to retrieve.
+    /// - Parameter filter: Closure used to determine whether to skip a key in the results.
+    /// - Returns: Labels and distances to closest approximate matches in decreasing similarity order.
+    /// - Throws: If runs out of memory.
+    public func filteredSearch(vector: [Float32], count: Int, filter: @escaping FilterFn) -> ([Key], [Float]) {
+        filteredSearch(vector: vector[...], count: count, filter: filter)
+    }
+
+    /// Approximate nearest neighbors search.
+    /// - Parameter vector: Double-precision query vector.
+    /// - Parameter count: Upper limit on the number of matches to retrieve.
+    /// - Parameter filter: Closure used to determine whether to skip a key in the results.
+    /// - Returns: Labels and distances to closest approximate matches in decreasing similarity order.
+    /// - Throws: If runs out of memory.
+    public func filteredSearch(vector: ArraySlice<Float64>, count: Int, filter: @escaping FilterFn) -> ([Key], [Float])
+    {
+        var matches: [Key] = Array(repeating: 0, count: count)
+        var distances: [Float] = Array(repeating: 0, count: count)
+        let results = vector.withContiguousStorageIfAvailable {
+            filteredSearchDouble(
+                vector: $0.baseAddress!,
+                count:
+                    CUnsignedInt(count),
+                filter: filter,
+                keys: &matches,
+                distances: &distances
+            )
+        }
+        matches.removeLast(count - Int(results!))
+        distances.removeLast(count - Int(results!))
+        return (matches, distances)
+    }
+
+    /// Approximate nearest neighbors search.
+    /// - Parameter vector: Double-precision query vector.
+    /// - Parameter count: Upper limit on the number of matches to retrieve.
+    /// - Parameter filter: Closure used to determine whether to skip a key in the results.
+    /// - Returns: Labels and distances to closest approximate matches in decreasing similarity order.
+    /// - Throws: If runs out of memory.
+    public func filteredSearch(vector: [Float64], count: Int, filter: @escaping FilterFn) -> ([Key], [Float]) {
+        filteredSearch(vector: vector[...], count: count, filter: filter)
+    }
+
     #if arch(arm64)
 
         /// Adds a labeled vector to the index.
@@ -146,6 +269,32 @@ extension USearchIndex {
             search(vector: vector[...], count: count)
         }
 
+        /// Retrieve vectors for a given key.
+        /// - Parameter key: Unique identifier for that object.
+        /// - Parameter count: For multi-indexes, Number of vectors to retrieve. Defaults to 1.
+        /// - Returns: Two-dimensional array of Half-precision vectors.
+        /// - Throws: If runs out of memory.
+        @available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *)
+        public func get(key: USearchKey, count: Int = 1) -> [[Float16]]? {
+            var vector: [Float16] = Array(repeating: 0.0, count: Int(self.dimensions) * count)
+            let count = vector.withContiguousMutableStorageIfAvailable { buf in
+                guard let baseAddress = buf.baseAddress else { return UInt32(0) }
+                return getSingle(
+                    key: key,
+                    vector: baseAddress,
+                    count: CUnsignedInt(count)
+                )
+            }
+            guard let count = count, count > 0 else { return nil }
+            return stride(
+                from: 0,
+                to: Int(count) * Int(self.dimensions),
+                by: Int(self.dimensions)
+            ).map {
+                Array(vector[$0 ..< $0 + Int(self.dimensions)])
+            }
+        }
+
     #endif
 
     /// Number of vectors in the index.
diff --git a/swift/README.md b/swift/README.md
index 9f9720e3..17cfa46b 100644
--- a/swift/README.md
+++ b/swift/README.md
@@ -24,6 +24,8 @@ index.add(key: 43, vector: vectorB)
 
 let results = index.search(vector: vectorA, count: 10)
 assert(results.0[0] == 42)
+let retrieved: [[Float32]]? = index.get(key: 42)
+assert(retrieved![0] == vectorA)
 ```
 
 If using in a SwiftUI application, make sure to annulate the void responses:
diff --git a/swift/Test.swift b/swift/Test.swift
index c6ebeccc..7b1827c8 100644
--- a/swift/Test.swift
+++ b/swift/Test.swift
@@ -31,11 +31,61 @@ class Test: XCTestCase {
         let results = index.search(vector: vectorA, count: 10)
         assert(results.0[0] == 42)
 
+        let fetched: [[Float]]? = index.get(key: 42)
+        assert(fetched?[0] == vectorA)
+
         assert(index.contains(key: 42))
         assert(index.count(key: 42) == 1)
         assert(index.count(key: 49) == 0)
         index.rename(from: 42, to: 49)
         assert(index.count(key: 49) == 1)
+
+        let refetched: [[Float]]? = index.get(key: 49)
+        assert(refetched?[0] == vectorA)
+        let stale: [[Float]]? = index.get(key: 42)
+        assert(stale == nil)
+
+        index.remove(key: 49)
+        assert(index.count(key: 49) == 0)
+    }
+
+    func testUnitMulti() throws {
+        let index = USearchIndex.make(
+            metric: USearchMetric.l2sq,
+            dimensions: 4,
+            connectivity: 8,
+            quantization: USearchScalar.F32,
+            multi: true
+        )
+        let vectorA: [Float32] = [0.3, 0.5, 1.2, 1.4]
+        let vectorB: [Float32] = [0.4, 0.2, 1.2, 1.1]
+        index.reserve(2)
+
+        // Adding a slice
+        index.add(key: 42, vector: vectorA[...])
+
+        // Adding a vector
+        index.add(key: 42, vector: vectorB)
+
+        let results = index.search(vector: vectorA, count: 10)
+        assert(results.0[0] == 42)
+
+        let fetched: [[Float]]? = index.get(key: 42, count: 2)
+        assert(fetched?.contains(vectorA) == true)
+        assert(fetched?.contains(vectorB) == true)
+
+        assert(index.contains(key: 42))
+        assert(index.count(key: 42) == 2)
+        assert(index.count(key: 49) == 0)
+        index.rename(from: 42, to: 49)
+        assert(index.count(key: 49) == 2)
+
+        let refetched: [[Float]]? = index.get(key: 49, count: 2)
+        assert(refetched?.contains(vectorA) == true)
+        assert(refetched?.contains(vectorB) == true)
+        let stale: [[Float]]? = index.get(key: 42)
+        assert(stale == nil)
+
         index.remove(key: 49)
         assert(index.count(key: 49) == 0)
     }
@@ -54,19 +104,131 @@ class Test: XCTestCase {
         index.add(key: 2, vector: [2.1])
         index.add(key: 3, vector: [3.1])
         XCTAssertEqual(index.count, 3)
-        XCTAssertEqual(index.search(vector: [1.0], count: 3).0, [1, 2, 3]) // works 😎
+        XCTAssertEqual(index.search(vector: [1.0], count: 3).0, [1, 2, 3])  // works 😎
 
         // replace second-added entry then ensure all 3 are still returned
         index.remove(key: 2)
         index.add(key: 2, vector: [2.2])
         XCTAssertEqual(index.count, 3)
-        XCTAssertEqual(index.search(vector: [1.0], count: 3).0, [1, 2, 3]) // works 😎
+        XCTAssertEqual(index.search(vector: [1.0], count: 3).0, [1, 2, 3])  // works 😎
 
         // replace first-added entry then ensure all 3 are still returned
         index.remove(key: 1)
         index.add(key: 1, vector: [1.2])
         let afterReplacingInitial = index.search(vector: [1.0], count: 3).0
         XCTAssertEqual(index.count, 3)
-        XCTAssertEqual(afterReplacingInitial, [1, 2, 3]) // v2.11.7 fails with "[1] != [1, 2, 3]" 😨
+        XCTAssertEqual(afterReplacingInitial, [1, 2, 3])  // v2.11.7 fails with "[1] != [1, 2, 3]" 😨
+    }
+
+    func testFilteredSearchSingle() {
+        let index = USearchIndex.make(
+            metric: USearchMetric.l2sq,
+            dimensions: 1,
+            connectivity: 8,
+            quantization: USearchScalar.F32
+        )
+        index.reserve(3)
+
+        // add 3 entries
+        index.add(key: 1, vector: [1.1])
+        index.add(key: 2, vector: [2.1])
+        index.add(key: 3, vector: [3.1])
+        XCTAssertEqual(index.count, 3)
+
+        // filter which accepts all keys:
+        XCTAssertEqual(
+            index.filteredSearch(vector: [1.0], count: 3) {
+                key in true
+            }.0,
+            [1, 2, 3]
+        )  // works 😎
+
+        // filter which rejects all keys:
+        XCTAssertEqual(
+            index.filteredSearch(vector: [1.0], count: 3) {
+                key in false
+            }.0,
+            []
+        )  // works 😎
+
+        // filter function accepts a set of keys passed in through a capture.
+        let acceptedKeys: [USearchKey] = [1, 2]
+        XCTAssertEqual(
+            index.filteredSearch(vector: [1.0], count: 3) {
+                key in acceptedKeys.contains(key)
+            }.0,
+            acceptedKeys
+        )  // works 😎
+
+        // filter function accepts a set of keys passed in through a capture,
+        // and also adheres to the count.
+        XCTAssertEqual(
+            index.filteredSearch(vector: [1.0], count: 1) {
+                key in key > 1
+            }.0,
+            [2]
+        )  // works 😎
+        XCTAssertEqual(
+            index.filteredSearch(vector: [1.0], count: 2) {
+                key in key > 1
+            }.0,
+            [2, 3]
+        )  // works 😎
+    }
+
+    func testFilteredSearchDouble() {
+        let index = USearchIndex.make(
+            metric: USearchMetric.l2sq,
+            dimensions: 1,
+            connectivity: 8,
+            quantization: USearchScalar.F64
+        )
+        index.reserve(3)
+
+        // add 3 entries
+        index.add(key: 1, vector: [Float64(1.1)])
+        index.add(key: 2, vector: [Float64(2.1)])
+        index.add(key: 3, vector: [Float64(3.1)])
+        XCTAssertEqual(index.count, 3)
+
+        // filter which accepts all keys:
+        XCTAssertEqual(
+            index.filteredSearch(vector: [Float64(1.0)], count: 3) {
+                key in true
+            }.0,
+            [1, 2, 3]
+        )  // works 😎
+
+        // filter which rejects all keys:
+        XCTAssertEqual(
+            index.filteredSearch(vector: [Float64(1.0)], count: 3) {
+                key in false
+            }.0,
+            []
+        )  // works 😎
+
+        // filter function accepts a set of keys passed in through a capture.
+        let acceptedKeys: [USearchKey] = [1, 2]
+        XCTAssertEqual(
+            index.filteredSearch(vector: [Float64(1.0)], count: 3) {
+                key in acceptedKeys.contains(key)
+            }.0,
+            acceptedKeys
+        )  // works 😎
+
+        // filter function accepts a set of keys passed in through a capture,
+        // and also respects the count.
+        XCTAssertEqual(
+            index.filteredSearch(vector: [Float64(1.0)], count: 1) {
+                key in key > 1
+            }.0,
+            [2]
+        )  // works 😎
+        XCTAssertEqual(
+            index.filteredSearch(vector: [Float64(1.0)], count: 2) {
+                key in key > 1
+            }.0,
+            [2, 3]
+        )  // works 😎
     }
 }


Test patch:
diff --git a/golang/lib_test.go b/golang/lib_test.go
index 4203640a..acb35cd5 100644
--- a/golang/lib_test.go
+++ b/golang/lib_test.go
@@ -1,9 +1,9 @@
 package usearch
 
 import (
+	"math"
 	"runtime"
 	"testing"
-	"math"
 )
 
 func TestUSearch(t *testing.T) {
@@ -34,10 +34,35 @@ func TestUSearch(t *testing.T) {
 			t.Fatalf("Expected size to be 0, got %d", found_len)
 		}
 
+		found_len, err = ind.SerializedLength()
+		if err != nil {
+			t.Fatalf("Failed to retrieve serialized length: %s", err)
+		}
+		if found_len != 112 {
+			t.Fatalf("Expected serialized length to be 112, got %d", found_len)
+		}
+
 		err = ind.Reserve(100)
 		if err != nil {
 			t.Fatalf("Failed to reserve capacity: %s", err)
 		}
+
+		mem, err := ind.MemoryUsage()
+		if err != nil {
+			t.Fatalf("Failed to retrieve serialized length: %s", err)
+		}
+		if mem == 0 {
+			t.Fatalf("Expected the empty index memory usage to be positive, got zero")
+		}
+
+		s, err := ind.HardwareAcceleration()
+		if err != nil {
+			t.Fatalf("Failed to retrieve hardware acceleration: %s", err)
+		}
+		if s == "" {
+			t.Fatalf("An empty string was returned from HardwareAcceleration")
+		}
+
 	})
 
 	t.Run("Test Insertion", func(t *testing.T) {
@@ -104,5 +129,91 @@ func TestUSearch(t *testing.T) {
 		if keys[0] != 42 || math.Abs(float64(distances[0])) > tolerance {
 			t.Fatalf("Expected result 42 with distance 0, got key %d with distance %f", keys[0], distances[0])
 		}
+
+        // TODO: Add exact search
+	})
+
+	t.Run("Test Save and Load", func(t *testing.T) {
+		dim := uint(128)
+		conf := DefaultConfig(dim)
+		ind, err := NewIndex(conf)
+		if err != nil {
+			t.Fatalf("Failed to construct the index: %s", err)
+		}
+		defer ind.Destroy()
+		ind2, err := NewIndex(conf)
+		if err != nil {
+			t.Fatalf("Failed to construct the index: %s", err)
+		}
+		defer ind2.Destroy()
+		indView, err := NewIndex(conf)
+		if err != nil {
+			t.Fatalf("Failed to construct the index: %s", err)
+		}
+		defer indView.Destroy()
+
+		err = ind.Reserve(100)
+		if err != nil {
+			t.Fatalf("Failed to reserve capacity: %s", err)
+		}
+
+		vec := make([]float32, dim)
+        for i := uint(0); i < dim; i++ {
+		    vec[i] = float32(i) + 0.2
+		    err = ind.Add(uint64(i), vec)
+		    if err != nil {
+			    t.Fatalf("Failed to insert: %s", err)
+		    }
+        }
+
+		ind_length, err := ind.Len()
+		if err != nil {
+			t.Fatalf("Failed to retrieve size: %s", err)
+		}
+
+        // TODO: Add invalid save and loads?
+        buffer_size := uint(1*1024*1024)
+        buf := make([]byte, buffer_size)
+		err = ind.SaveBuffer(buf, buffer_size)
+		if err != nil {
+			t.Fatalf("Failed to save the index to a buffer: %s", err)
+		}
+
+		err = ind2.LoadBuffer(buf, buffer_size)
+		if err != nil {
+			t.Fatalf("Failed to load the index from a buffer: %s", err)
+		}
+
+		ind2_length, err := ind2.Len()
+		if err != nil {
+			t.Fatalf("Failed to retrieve size: %s", err)
+		}
+		if ind_length != ind2_length {
+			t.Fatalf("Loaded index length %d doesn't match original of %d ", ind2_length, ind_length)
+		}
+        // TODO: Check some values
+
+		err = indView.ViewBuffer(buf, buffer_size)
+		if err != nil {
+			t.Fatalf("Failed to load the view from a buffer: %s", err)
+		}
+
+		indView_length, err := indView.Len()
+		if err != nil {
+			t.Fatalf("Failed to retrieve size: %s", err)
+		}
+		if ind_length != indView_length {
+			t.Fatalf("Loaded view length %d doesn't match original of %d ", indView_length, ind_length)
+		}
+
+		conf, err = MetadataBuffer(buf, buffer_size)
+		if err != nil {
+			t.Fatalf("Failed to load the metadata from a buffer: %s", err)
+		}
+		if conf != ind.config {
+			t.Fatalf("Loaded metadata doesn't match the index metadata")
+		}
+
+        // TODO: Check file save/load/metadata
 	})
 }
diff --git a/python/scripts/test_distances.py b/python/scripts/test_distances.py
index ec637189..ea316b80 100644
--- a/python/scripts/test_distances.py
+++ b/python/scripts/test_distances.py
@@ -57,9 +57,8 @@ def test_distances_continuous(metric, quantization, dtype):
     distance_different = index.pairwise_distance([0], [1])
 
     assert not np.allclose(distance_different, 0)
-    assert np.allclose(distance_itself_first, 0, rtol=rtol, atol=atol) and np.allclose(
-        distance_itself_second, 0, rtol=rtol, atol=atol
-    )
+    assert np.allclose(distance_itself_first, 0, rtol=rtol, atol=atol)
+    assert np.allclose(distance_itself_second, 0, rtol=rtol, atol=atol)
 
 
 @pytest.mark.parametrize(