From 3fa476865b32dd1f06bbd54cc7ae28ab9cd101b4 Mon Sep 17 00:00:00 2001 From: xzfc <5121426+xzfc@users.noreply.github.com> Date: Tue, 24 Feb 2026 16:43:59 +0000 Subject: [PATCH] Single edge crate (#8173) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixups of amalgamator Fix issues that break `qdrant-edge` build process: - `use … as segment;` - this causes `ast-grep` rules to replace wrong paths. So, rename to avoid collisions. - `#[macro_use]` and `extern crate` required be in the top-level `lib.rs`. - `format!("…", crate::something::…)` - `ast-grep` can't fix paths inside macros. Fixed by moving `crate::something::…` out of the macro. * Add lib/edge/publish workspace and amalgamation script * Move `lib/edge/examples` into `lib/edge/publish/` workspace And fix them to use the generated `qdrant-edge` crate. * Add github workflow * Cleanup `qdrant-edge` public API Removes empty modules. Checked by `cargo doc`. --- .github/workflows/edge-rust-package.yml | 44 +++ lib/api/src/grpc/conversions.rs | 12 +- lib/edge/examples/README.md | 25 -- lib/edge/publish/.gitignore | 3 + lib/edge/publish/Cargo.toml | 3 + lib/edge/publish/amalgamate.py | 264 ++++++++++++++++++ lib/edge/publish/ast-grep-rules.yaml | 63 +++++ lib/edge/publish/cargo | 21 ++ lib/edge/publish/examples/Cargo.toml | 12 + .../examples/src/bin}/demo.rs | 24 +- .../examples/src/bin}/edge-cli.rs | 2 +- .../examples/src/bin}/facet_test.rs | 6 +- lib/edge/python/src/info.rs | 2 +- lib/edge/src/lib.rs | 19 +- lib/segment/src/lib.rs | 4 - lib/segment/src/types.rs | 6 +- shell.nix | 1 + 17 files changed, 448 insertions(+), 63 deletions(-) create mode 100644 .github/workflows/edge-rust-package.yml delete mode 100644 lib/edge/examples/README.md create mode 100644 lib/edge/publish/.gitignore create mode 100644 lib/edge/publish/Cargo.toml create mode 100755 lib/edge/publish/amalgamate.py create mode 100644 lib/edge/publish/ast-grep-rules.yaml create mode 100755 lib/edge/publish/cargo create mode 100644 lib/edge/publish/examples/Cargo.toml rename lib/edge/{examples => publish/examples/src/bin}/demo.rs (87%) rename lib/edge/{examples => publish/examples/src/bin}/edge-cli.rs (76%) rename lib/edge/{examples => publish/examples/src/bin}/facet_test.rs (92%) diff --git a/.github/workflows/edge-rust-package.yml b/.github/workflows/edge-rust-package.yml new file mode 100644 index 0000000000..3c46dc0ee3 --- /dev/null +++ b/.github/workflows/edge-rust-package.yml @@ -0,0 +1,44 @@ +name: Qdrant Edge Rust Package + +on: + push: + branches: [ master, dev ] + pull_request: + branches: [ '**' ] + +jobs: + edge-rust-package: + name: Test Qdrant Edge Rust Package + + runs-on: ubuntu-latest + + steps: + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Install mold + uses: rui314/setup-mold@v1 + + - name: Install Protoc + uses: arduino/setup-protoc@v3 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install uv + uses: astral-sh/setup-uv@v7 + + - name: Install ast-grep + run: npm install --global @ast-grep/cli + + - name: Checkout Qdrant + uses: actions/checkout@v6 + + - name: Restore Rust build cache + uses: Swatinem/rust-cache@v2 + + - name: Amalgamate + run: lib/edge/publish/amalgamate.py + + - name: Cargo check + working-directory: lib/edge/publish + run: cargo check -p examples diff --git a/lib/api/src/grpc/conversions.rs b/lib/api/src/grpc/conversions.rs index 463c663b0d..1adf8fa2b6 100644 --- a/lib/api/src/grpc/conversions.rs +++ b/lib/api/src/grpc/conversions.rs @@ -1013,13 +1013,13 @@ impl TryFrom for RetrievedPoint { impl From for OrderValue { fn from(value: segment::data_types::order_by::OrderValue) -> Self { - use segment::data_types::order_by as segment; + use segment::data_types::order_by as segment_; use crate::grpc::qdrant::order_value::Variant; let variant = match value { - segment::OrderValue::Float(value) => Variant::Float(value), - segment::OrderValue::Int(value) => Variant::Int(value), + segment_::OrderValue::Float(value) => Variant::Float(value), + segment_::OrderValue::Int(value) => Variant::Int(value), }; Self { @@ -1032,7 +1032,7 @@ impl TryFrom for segment::data_types::order_by::OrderValue { type Error = Status; fn try_from(value: OrderValue) -> Result { - use segment::data_types::order_by as segment; + use segment::data_types::order_by as segment_; use crate::grpc::qdrant::order_value::Variant; @@ -1043,8 +1043,8 @@ impl TryFrom for segment::data_types::order_by::OrderValue { })?; let value = match variant { - Variant::Float(value) => segment::OrderValue::Float(value), - Variant::Int(value) => segment::OrderValue::Int(value), + Variant::Float(value) => segment_::OrderValue::Float(value), + Variant::Int(value) => segment_::OrderValue::Int(value), }; Ok(value) diff --git a/lib/edge/examples/README.md b/lib/edge/examples/README.md deleted file mode 100644 index f03bc3f880..0000000000 --- a/lib/edge/examples/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Qdrant Edge Examples - -This directory contains examples demonstrating how to use the Qdrant Edge library. - -## Try It Out - -To run the examples from within this repository, use the following command: - -```bash -cargo run -p edge --example demo -``` - -If you want to run these examples in your own project, add the following dependencies to your `Cargo.toml`: - -```toml -[dependencies] -edge = { git = "https://github.com/qdrant/qdrant.git", branch = "dev", package = "edge" } -segment = { git = "https://github.com/qdrant/qdrant.git", branch = "dev", package = "segment" } -shard = { git = "https://github.com/qdrant/qdrant.git", branch = "dev", package = "shard" } -uuid = { version = "1", features = ["v4"] } -serde_json = "1" -tempfile = "3" -ordered-float = "5" -fs-err = "3" -``` diff --git a/lib/edge/publish/.gitignore b/lib/edge/publish/.gitignore new file mode 100644 index 0000000000..418ade421a --- /dev/null +++ b/lib/edge/publish/.gitignore @@ -0,0 +1,3 @@ +/Cargo.lock +/examples/target +/qdrant-edge diff --git a/lib/edge/publish/Cargo.toml b/lib/edge/publish/Cargo.toml new file mode 100644 index 0000000000..ccef6fe7fc --- /dev/null +++ b/lib/edge/publish/Cargo.toml @@ -0,0 +1,3 @@ +[workspace] +resolver = "3" +members = [ "examples", "qdrant-edge" ] diff --git a/lib/edge/publish/amalgamate.py b/lib/edge/publish/amalgamate.py new file mode 100755 index 0000000000..df1d43bcca --- /dev/null +++ b/lib/edge/publish/amalgamate.py @@ -0,0 +1,264 @@ +#!/usr/bin/env -S uv run --script +""" +Amalgamation +(noun) +/əˌmælɡəˈmeɪʃən/ + +1. The process of combining multiple crates into a single one. Used to prevent + namespace pollution when publishing to crates.io. +2. The result of amalgamating. +""" +# /// script +# dependencies = [ "tomlkit" ] +# /// + +import functools +import os.path +import re +import shutil +import subprocess +import sys +import textwrap +from collections.abc import Iterable +from pathlib import Path + +import tomlkit + +# Assume this script is in /lib/edge/publish/. +REPO_ROOT = Path(__file__).parent.parent.parent.parent + +AMALGAMATION = Path(__file__).parent / "qdrant-edge" + +PACKAGES_TO_INCLUDE = [ + "api", + "common", + "edge", + "gridstore", + "posting_list", + "quantization", + "segment", + "shard", + "sparse", + "wal", +] + +EXCLUDED_DEPENDENCIES = { + # build dependencies + "prost-build", + "tonic-build", +} + + +def main() -> None: + root_manifest = tomlkit.loads(Path(REPO_ROOT / "Cargo.toml").read_text()) + packages = all_file_dependencies(REPO_ROOT / "lib/edge") + + shutil.rmtree(AMALGAMATION, ignore_errors=True) + + # Copy Rust sources. + for pkg, (path, manifest) in packages.items(): + shutil.copytree(path / "src", AMALGAMATION / "src" / pkg) + os.rename( + AMALGAMATION / "src" / pkg / "lib.rs", + AMALGAMATION / "src" / pkg / "mod.rs", + ) + + # Copy C sources and related build scripts. + shutil.copytree( + REPO_ROOT / "lib/quantization/cpp", AMALGAMATION / "cpp/quantization" + ) + shutil.copy2( + REPO_ROOT / "lib/quantization/build.rs", + AMALGAMATION / "build-quantization.rs", + ) + (AMALGAMATION / "build.rs").write_text('include!("build-quantization.rs");\n') + # TODO: segment/build.rs - for arm neon .c files. + + # Copy resources. + shutil.copytree(REPO_ROOT / "lib/segment/tokenizer", AMALGAMATION / "tokenizer") + + # Write Cargo.toml. + manifest = { + "package": { + "name": "qdrant-edge", + "version": "0.0.0", + "authors": ["Qdrant Team "], + "license": "Apache-2.0", + "edition": "2024", + "publish": False, + }, + **gather_dependencies( + root_manifest, [manifest for _, manifest in packages.values()] + ), + } + (AMALGAMATION / "Cargo.toml").write_text(tomlkit.dumps(manifest)) + + # Write src/lib.rs. + # It just re-exports everything. + (AMALGAMATION / "src/lib.rs").write_text( + textwrap.dedent( + """ + #![allow(unexpected_cfgs)] + #![allow(dead_code, unused_imports)] + pub use edge::*; + pub mod segment; + pub mod shard; + """ + ).lstrip() + + "".join(f"mod {pkg};\n" for pkg in packages.keys() - {"segment", "shard"}) + ) + + # Regex-based fixups. + substitute( + AMALGAMATION / "src/api/grpc/qdrant.rs", + (r'custom\(function = "crate::(.*)"\)', r'custom(function = "crate::api::\1")'), + (r'custom\(function = "(common::.*)"\)', r'custom(function = "crate::\1")'), + ) + substitute( + AMALGAMATION / "build-quantization.rs", + (r"cpp/", r"cpp/quantization/"), + ) + # Remove code that doesn't compile. + substitute( + AMALGAMATION / "src/api/grpc/mod.rs", + (r"^pub mod dynamic_channel_pool;$\n", ""), + (r"^pub mod dynamic_pool;$\n", ""), + (r"^pub mod transport_channel_pool;$\n", ""), + (r"^pub const QDRANT_DESCRIPTOR_SET:.*$\n", ""), + ) + substitute( + AMALGAMATION / "src/segment/common/anonymize.rs", + (r"^pub use macros::Anonymize;$\n", ""), + ) + # Cleanup public API + substitute( + AMALGAMATION.glob("src/**/*.rs"), + (r"^#\[macro_export]$\n", ""), + ) + + # Remove unused code. + shutil.rmtree(AMALGAMATION / "src/segment/index/hnsw_index/gpu") + + # Ast-grep-based fixups. + RULES_TEMPLATE = (Path(__file__).parent / "ast-grep-rules.yaml").read_text() + for package, (_, manifest) in packages.items(): + deps = ( + "|".join( + dep + for dep in manifest["dependencies"].keys() + if dep in PACKAGES_TO_INCLUDE + ) + or "some-nonexistent-package" + ) + rules = RULES_TEMPLATE.replace("%PACKAGE%", package).replace("%DEPS%", deps) + # ast-grep prints stats but it doesn't print the directory it's working on. + print( + end=(package + ": ").ljust(max(len(pkg) for pkg in packages.keys()) + 2), + file=sys.stderr, + flush=True, + ) + subprocess.run( + [ + "ast-grep", + "scan", + "--update-all", + f"--inline-rules={rules}", + AMALGAMATION / "src" / package, + ], + check=True, + ) + + +def gather_dependencies( + root_manifest: tomlkit.TOMLDocument, crates: list[tomlkit.TOMLDocument] +) -> dict[str, dict]: + """Collect and merge dependencies from the provided manifests.""" + dependencies: dict[str, dict] = {} + workspace_deps = { + name: {"version": spec} if isinstance(spec, str) else spec + for name, spec in root_manifest["workspace"]["dependencies"].items() + } + + excluded = set() + + def add_specs(path: tuple[str, ...], specs: dict) -> None: + dest = None + for name, spec in specs.items(): + spec = {"version": spec} if isinstance(spec, str) else spec + if name in EXCLUDED_DEPENDENCIES: + excluded.add(name) + continue + if "path" in spec or spec.get("optional") is True: + continue + if spec.get("workspace") is True: + # Merge two specs. Sloppy as it won't merge features. + spec = { + **workspace_deps[name], + **{k: v for k, v in spec.items() if k != "workspace"}, + } + dest = dest or functools.reduce( + lambda d, k: d.setdefault(k, {}), path, dependencies + ) + table = tomlkit.inline_table() + table.update(dest.get(name, {}) | spec) + dest[name] = table + + SECTIONS = ("dependencies", "build-dependencies", "dev-dependencies") + for manifest in crates: + for section in SECTIONS: + add_specs((section,), manifest.get(section, {})) + for target_name, target_manifest in manifest.get("target", {}).items(): + for section in SECTIONS: + add_specs( + ("target", target_name, section), target_manifest.get(section, {}) + ) + return dependencies + + +def substitute(paths: Path | Iterable[Path], *replacements: tuple[str, str]) -> None: + """Like `sed -i` but worse. Complains if some pattern is not found.""" + seen = [False] * len(replacements) + regexes = [re.compile(pattern, flags=re.MULTILINE) for pattern, _ in replacements] + if isinstance(paths, Path): + paths = (paths,) + for path in paths: + text = path.read_text() + changed = False + for i in range(len(replacements)): + new_text = regexes[i].sub(replacements[i][1], text) + if new_text != text: + text = new_text + changed = True + seen[i] = True + if changed: + path.write_text(text) + for seen, (pattern, _) in zip(seen, replacements): + assert seen, f"Pattern {pattern!r} not found" + + +def all_file_dependencies(root: Path) -> dict[str, tuple[Path, tomlkit.TOMLDocument]]: + """Recursively collect Cargo.toml files for all dependencies. + Returns mapping package_name -> (path_to_package, manifest). + """ + seen: set[Path] = {root} + stack = [root] + result: dict[str, tuple[Path, tomlkit.TOMLDocument]] = {} + + while stack: + path = stack.pop() + manifest = tomlkit.loads((path / "Cargo.toml").read_text()) + name = manifest["package"]["name"] + if name in PACKAGES_TO_INCLUDE: + result[manifest["package"]["name"]] = (path, manifest) + for spec in manifest["dependencies"].values(): + if isinstance(spec, dict) and isinstance(spec.get("path"), str): + dep = Path(os.path.normpath(path / spec["path"])) + if dep not in seen: + seen.add(dep) + stack.append(dep) + + return dict(sorted(result.items())) + + +if __name__ == "__main__": + main() diff --git a/lib/edge/publish/ast-grep-rules.yaml b/lib/edge/publish/ast-grep-rules.yaml new file mode 100644 index 0000000000..0368cfcc1d --- /dev/null +++ b/lib/edge/publish/ast-grep-rules.yaml @@ -0,0 +1,63 @@ +# %PACKAGE% and %DEPS% are injected by python script. + +# Insert `%PACKAGE%` after `crate::`. +# Before: `crate::types::Distance` +# After: `crate::segment::types::Distance` +--- +id: self-crate +language: rust +rule: + kind: crate + not: { inside: { kind: visibility_modifier } } # Don't fix `crate` in `pub(crate)`. +fix: crate::%PACKAGE% +--- +id: self-crate-in-macro-rules +language: rust +rule: + all: + - kind: metavariable + - regex: ^\$crate$ + - inside: { kind: macro_definition, stopBy: end } +fix: $crate::%PACKAGE% + +# Prepend `crate::` before `%DEPS%`. +# Before: `quantization::DistanceType::Dot` +# After: `crate::quantization::DistanceType::Dot` +--- +id: inner-deps +language: rust +rule: + all: + - kind: identifier + - pattern: $MOD + - regex: ^(%DEPS%)$ # Assuming `%DEPS%` is `|`-separated list of dependencies. + - any: + - inside: { kind: scoped_identifier, stopBy: end } + - inside: { kind: scoped_type_identifier, stopBy: end } + - inside: { kind: scoped_use_list, stopBy: end } + - any: + - precedes: { kind: identifier, stopBy: end } + - precedes: { kind: type_identifier, stopBy: end } + - precedes: { kind: use_list, stopBy: end } +fix: crate::$MOD + +# Remove `Anonymize` derives. +# Before: `#[derive(Debug, Anonymize)]` +# After: `#[derive(Debug)]` +--- +id: drop-anonymize-derive +language: rust +rule: + pattern: "Anonymize" + inside: + pattern: "#[derive($$$)]" + stopBy: end +fix: + template: "" + expandEnd: { regex: ',' } +--- +id: drop-anonymize-attr +language: rust +rule: + pattern: "#[anonymize($$$ARGS)]" +fix: "" diff --git a/lib/edge/publish/cargo b/lib/edge/publish/cargo new file mode 100755 index 0000000000..8cc7c13d73 --- /dev/null +++ b/lib/edge/publish/cargo @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +""" +Convenience wrapper for `cargo`. +Sets `CARGO_TARGET_DIR` to reuse `target` directory of the repo root to avoid +building dependencies twice. +""" + +import os +import sys +from pathlib import Path + +# Assume this script is in /lib/edge/publish/. +REPO_ROOT = Path(__file__).parent.parent.parent.parent +"""Repo root, assuming this script lays in /lib/edge/publish/.""" + +os.chdir(Path(__file__).parent) + +env = os.environ.copy() +env.setdefault("CARGO_TARGET_DIR", str(REPO_ROOT / "target")) + +os.execvpe("cargo", ["cargo"] + sys.argv[1:], env) diff --git a/lib/edge/publish/examples/Cargo.toml b/lib/edge/publish/examples/Cargo.toml new file mode 100644 index 0000000000..c8ea549f6b --- /dev/null +++ b/lib/edge/publish/examples/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "examples" +version = "0.0.0" +edition = "2024" +publish = false +description = "Examples demonstrating how to use the Qdrant Edge library" + +[dependencies] +qdrant-edge = { path = "../qdrant-edge" } +anyhow = "1" +fs-err = "3" +serde_json = "1" diff --git a/lib/edge/examples/demo.rs b/lib/edge/publish/examples/src/bin/demo.rs similarity index 87% rename from lib/edge/examples/demo.rs rename to lib/edge/publish/examples/src/bin/demo.rs index 22095acdf9..9c3e015a77 100644 --- a/lib/edge/examples/demo.rs +++ b/lib/edge/publish/examples/src/bin/demo.rs @@ -2,22 +2,22 @@ use std::collections::HashMap; use std::error::Error; use std::path::Path; -use edge::EdgeShard; -use segment::data_types::vectors::{NamedQuery, VectorInternal, VectorStructInternal}; -use segment::types::{ +use qdrant_edge::EdgeShard; +use qdrant_edge::segment::data_types::vectors::{NamedQuery, VectorInternal, VectorStructInternal}; +use qdrant_edge::segment::types::{ Distance, ExtendedPointId, Payload, PayloadStorageType, SegmentConfig, VectorDataConfig, VectorStorageType, WithPayloadInterface, WithVector, }; +use qdrant_edge::shard::count::CountRequestInternal; +use qdrant_edge::shard::facet::FacetRequestInternal; +use qdrant_edge::shard::operations::CollectionUpdateOperations::PointOperation; +use qdrant_edge::shard::operations::point_ops::PointInsertOperationsInternal::PointsList; +use qdrant_edge::shard::operations::point_ops::PointOperations::UpsertPoints; +use qdrant_edge::shard::operations::point_ops::PointStructPersisted; +use qdrant_edge::shard::query::query_enum::QueryEnum; +use qdrant_edge::shard::query::{ScoringQuery, ShardQueryRequest}; +use qdrant_edge::shard::scroll::ScrollRequestInternal; use serde_json::{Value, json}; -use shard::count::CountRequestInternal; -use shard::facet::FacetRequestInternal; -use shard::operations::CollectionUpdateOperations::PointOperation; -use shard::operations::point_ops::PointInsertOperationsInternal::PointsList; -use shard::operations::point_ops::PointOperations::UpsertPoints; -use shard::operations::point_ops::PointStructPersisted; -use shard::query::query_enum::QueryEnum; -use shard::query::{ScoringQuery, ShardQueryRequest}; -use shard::scroll::ScrollRequestInternal; const DATA_DIR: &str = "./qdrant-edge-data"; const VECTOR_NAME: &str = "example-vector"; diff --git a/lib/edge/examples/edge-cli.rs b/lib/edge/publish/examples/src/bin/edge-cli.rs similarity index 76% rename from lib/edge/examples/edge-cli.rs rename to lib/edge/publish/examples/src/bin/edge-cli.rs index 38b7776ab4..30b14f576c 100644 --- a/lib/edge/examples/edge-cli.rs +++ b/lib/edge/publish/examples/src/bin/edge-cli.rs @@ -8,6 +8,6 @@ fn main() -> anyhow::Result<()> { .try_into() .map_err(|args| anyhow::format_err!("unexpected arguments {args:?}"))?; - let _edge_shard = edge::EdgeShard::load(Path::new(&edge_shard_path), None)?; + let _edge_shard = qdrant_edge::EdgeShard::load(Path::new(&edge_shard_path), None)?; Ok(()) } diff --git a/lib/edge/examples/facet_test.rs b/lib/edge/publish/examples/src/bin/facet_test.rs similarity index 92% rename from lib/edge/examples/facet_test.rs rename to lib/edge/publish/examples/src/bin/facet_test.rs index 94a9b504f5..8ceeaa7641 100644 --- a/lib/edge/examples/facet_test.rs +++ b/lib/edge/publish/examples/src/bin/facet_test.rs @@ -1,8 +1,8 @@ use std::error::Error; use std::path::Path; -use edge::EdgeShard; -use shard::facet::FacetRequestInternal; +use qdrant_edge::EdgeShard; +use qdrant_edge::shard::facet::FacetRequestInternal; const SNAPSHOT_PATH: &str = "./test_edge_facet/shard.snapshot"; const DATA_DIR: &str = "./test_edge_facet/shard_data"; @@ -50,7 +50,7 @@ fn main() -> Result<(), Box> { } println!("---- Test Facet with filter ----"); - use segment::types::{Condition, FieldCondition, Filter, Match, ValueVariants}; + use qdrant_edge::segment::types::{Condition, FieldCondition, Filter, Match, ValueVariants}; let filter = Filter::new_must(Condition::Field(FieldCondition::new_match( "color".try_into().unwrap(), diff --git a/lib/edge/python/src/info.rs b/lib/edge/python/src/info.rs index 6f96fd20bb..e52b6dbfaa 100644 --- a/lib/edge/python/src/info.rs +++ b/lib/edge/python/src/info.rs @@ -4,7 +4,7 @@ use std::mem; use bytemuck::TransparentWrapper; use derive_more::Into; -use edge::info::ShardInfo; +use edge::ShardInfo; use pyo3::prelude::*; use segment::json_path::JsonPath; use segment::types::PayloadIndexInfo; diff --git a/lib/edge/src/lib.rs b/lib/edge/src/lib.rs index 7b43b36122..892b012706 100644 --- a/lib/edge/src/lib.rs +++ b/lib/edge/src/lib.rs @@ -1,12 +1,12 @@ -pub mod count; -pub mod facet; -pub mod info; -pub mod query; -pub mod retrieve; -pub mod scroll; -pub mod search; -pub mod snapshots; -pub mod update; +mod count; +mod facet; +mod info; +mod query; +mod retrieve; +mod scroll; +mod search; +mod snapshots; +mod update; use std::num::NonZero; use std::path::{Path, PathBuf}; @@ -16,6 +16,7 @@ use std::time::Duration; use common::save_on_disk::SaveOnDisk; use fs_err as fs; +pub use info::ShardInfo; use parking_lot::Mutex; use segment::common::operation_error::{OperationError, OperationResult}; use segment::entry::NonAppendableSegmentEntry as _; diff --git a/lib/segment/src/lib.rs b/lib/segment/src/lib.rs index 93e9df56a7..5b39e756bd 100644 --- a/lib/segment/src/lib.rs +++ b/lib/segment/src/lib.rs @@ -18,7 +18,3 @@ pub mod json_path; pub mod types; pub mod utils; pub mod vector_storage; - -#[macro_use] -extern crate num_derive; -extern crate core; diff --git a/lib/segment/src/types.rs b/lib/segment/src/types.rs index 57defa8e32..6d6bb54380 100644 --- a/lib/segment/src/types.rs +++ b/lib/segment/src/types.rs @@ -17,6 +17,7 @@ use fnv::FnvBuildHasher; use geo::{Contains, Coord, Distance as GeoDistance, Haversine, LineString, Point, Polygon}; use indexmap::IndexSet; use itertools::Itertools; +use num_derive::FromPrimitive; use ordered_float::OrderedFloat; use schemars::JsonSchema; use serde::{Deserialize, Deserializer, Serialize}; @@ -249,10 +250,11 @@ impl<'de> serde::Deserialize<'de> for ExtendedPointId { return Ok(ExtendedPointId::Uuid(uuid)); } + let value = crate::utils::fmt::SerdeValue(&value); + Err(serde::de::Error::custom(format!( - "value {} is not a valid point ID, \ + "value {value} is not a valid point ID, \ valid values are either an unsigned integer or a UUID", - crate::utils::fmt::SerdeValue(&value), ))) } } diff --git a/shell.nix b/shell.nix index 4fbeacce11..e43121e2c0 100644 --- a/shell.nix +++ b/shell.nix @@ -35,6 +35,7 @@ mkShell { pkgs.rustPlatform.bindgenHook # for bindgen deps # For tests and tools + pkgs.ast-grep # used in lib/edge/publish/amalgamate.py pkgs.cargo-nextest # mentioned in .github/workflows/rust.yml pkgs.ccache # mentioned in shellHook pkgs.curl # used in ./tests