{"id":19562699,"url":"https://github.com/jamsocket/fractional_index","last_synced_at":"2025-03-22T03:02:41.390Z","repository":{"id":46036245,"uuid":"406361998","full_name":"jamsocket/fractional_index","owner":"jamsocket","description":"A Rust implementation of fractional indexing.","archived":false,"fork":false,"pushed_at":"2024-09-17T19:52:55.000Z","size":55,"stargazers_count":55,"open_issues_count":2,"forks_count":5,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-19T12:44:05.663Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jamsocket.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-09-14T12:41:10.000Z","updated_at":"2025-03-14T08:16:05.000Z","dependencies_parsed_at":"2024-05-16T06:32:06.886Z","dependency_job_id":"93207d13-55cb-46ae-a60d-6f47e6e72f3b","html_url":"https://github.com/jamsocket/fractional_index","commit_stats":null,"previous_names":["jamsocket/fractional_index"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamsocket%2Ffractional_index","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamsocket%2Ffractional_index/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamsocket%2Ffractional_index/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamsocket%2Ffractional_index/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jamsocket","download_url":"https://codeload.github.com/jamsocket/fractional_index/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244431054,"owners_count":20451611,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-11T05:15:25.042Z","updated_at":"2025-03-22T03:02:41.370Z","avatar_url":"https://github.com/jamsocket.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `fractional_index`\n\n[![GitHub Repo stars](https://img.shields.io/github/stars/jamsocket/fractional_index?style=social)](https://github.com/jamsocket/fractional_index)\n[![crates.io](https://img.shields.io/crates/v/fractional_index.svg)](https://crates.io/crates/fractional_index)\n[![docs.rs](https://img.shields.io/badge/docs-release-brightgreen)](https://docs.rs/fractional_index/)\n[![build](https://github.com/jamsocket/fractional_index/actions/workflows/rust.yml/badge.svg)](https://github.com/jamsocket/fractional_index/actions/workflows/rust.yml)\n[![dependency status](https://deps.rs/repo/github/jamsocket/fractional_index/status.svg)](https://deps.rs/repo/github/jamsocket/fractional_index)\n\nThis crate implements fractional indexing, a term coined by Figma in their blog post\n[*Realtime Editing of Ordered Sequences*](https://www.figma.com/blog/realtime-editing-of-ordered-sequences/).\n\nSpecifically, this crate provides a type called `FractionalIndex`. A `FractionalIndex` acts as a\n“black box” that is only useful for comparing to\nanother `FractionalIndex`. A `FractionalIndex` can only be constructed from a default constructor or by\nreference to an existing `FractionalIndex`.\n\nThis is useful as a key in a `BTreeMap` when we want to be able to arbitrarily insert or\nre-order elements in a collection, but don't actually care what the key is. It’s also useful for resloving conflicts when a list is modified concurrently by multiple users.\n\n## Usage\n\nThe API of `FractionalIndex` is very simple:\n\n- `FractionalIndex::default()` creates a new fractional index.\n- `FractionalIndex::new_before(a)` creates a fractional index before another.\n- `FractionalIndex::new_after(a)` creates a fractional index after another.\n- `FractionalIndex::new_between(a, b)` creates a fractional index between two others.\n\n```rust\nuse fractional_index::FractionalIndex;\n\nfn main() {\n  // Construct a fractional index.\n  let index = FractionalIndex::default();\n\n  // Construct another fractional index that comes before it.\n  let before_index = FractionalIndex::new_before(\u0026index);\n  assert!(before_index \u003c index);\n\n  // Construct a third fractional index between the other two.\n  let between_index = FractionalIndex::new_between(\n    \u0026before_index,\n    \u0026index\n  ).unwrap();\n  assert!(before_index \u003c between_index);\n  assert!(between_index \u003c index);\n}\n```\n\n### Stringification\n\n`FractionalIndexes` are stored as byte strings, but they can be converted to and from strings.\n\n```rust\nuse fractional_index::FractionalIndex;\n\nfn main() {\n  let a = FractionalIndex::default();\n  let b = FractionalIndex::new_after(\u0026a);\n  let c = FractionalIndex::new_between(\u0026a, \u0026b).unwrap();\n  \n  let c_str = c.to_string();\n  assert_eq!(\"817f80\", c_str);\n  let c = FractionalIndex::new_between(\u0026a, \u0026b).unwrap();\n}\n```\n\nThe lexicographical order of two stringified `FractionalIndex` values is the same as the order of the unstringified version.\n\n```rust\nuse fractional_index::FractionalIndex;\n\nfn main() {\n  let a = FractionalIndex::default();\n  let b = FractionalIndex::new_after(\u0026a);\n  let c = FractionalIndex::new_between(\u0026a, \u0026b).unwrap();\n  \n  assert!(a.to_string() \u003c c.to_string());\n  assert!(c.to_string() \u003c b.to_string());\n}\n```\n\nThis is mostly useful when constructing indexes that you need to be able to compare in a language with native string comparison but not bytestring comparison, like JavaScript.\n\n### `::new()` constructor\n\nThe `::new()` constructor generalizes over `::default()`, `::new_before()`, `::new_after()`, and `::new_between()`.\n\n```rust\nuse fractional_index::FractionalIndex;\n\nfn main() {\n  let a = FractionalIndex::default();\n  let a2 = FractionalIndex::new(None, None).unwrap();\n  assert_eq!(a, a2);\n\n  let b = FractionalIndex::new_after(\u0026a);\n  let b2 = FractionalIndex::new(Some(\u0026a), None).unwrap();\n  assert_eq!(b, b2);\n  \n  let c = FractionalIndex::new_between(\u0026a, \u0026b).unwrap();\n  let c2 = FractionalIndex::new(Some(\u0026a), Some(\u0026b)).unwrap();\n  assert_eq!(c, c2);\n}\n```\n\n### Serialization\n\nWith the `serde` feature (enabled by default), `FractionalIndexes` can be serialized.\n\n```rust\nuse fractional_index::FractionalIndex;\nuse serde::{Serialize, Deserialize};\n\n#[derive(Serialize, Deserialize, Debug, PartialEq)]\nstruct MyStruct {\n  a: FractionalIndex,\n  b: FractionalIndex,\n  c: FractionalIndex,\n}\n\nfn main() {\n  let a = FractionalIndex::default();\n  let b = FractionalIndex::new_after(\u0026a);\n  let c = FractionalIndex::new_between(\u0026a, \u0026b).unwrap();\n\n  let my_struct = MyStruct {\n    a: a.clone(),\n    b: b.clone(),\n    c: c.clone(),\n  };\n\n  let json_string = serde_json::to_string(\u0026my_struct).unwrap();\n  let my_struct_de = serde_json::from_str(\u0026json_string).unwrap();\n\n  assert_eq!(my_struct, my_struct_de);\n}\n```\n\nBy default, `FractionalIndexes` are serialized as byte arrays, which can be serialized efficiently in formats like [bincode](https://github.com/bincode-org/bincode).\n\nThese byte arrays are less useful when using a format like JSON to send data to a non-Rust programming language.\n\nFor these use cases, we provide a stringifying serializer which can be enabled by annotating a field with `#[serde(with=\"fractional_index::stringify\")]`.\n\n```rust\nuse fractional_index::FractionalIndex;\nuse serde::{Serialize, Deserialize};\nuse serde_json::json;\n\n#[derive(Serialize, Deserialize, Debug, PartialEq)]\nstruct MyStruct {\n  #[serde(with=\"fractional_index::stringify\")]\n  a: FractionalIndex,\n  #[serde(with=\"fractional_index::stringify\")]\n  b: FractionalIndex,\n  #[serde(with=\"fractional_index::stringify\")]\n  c: FractionalIndex,\n}\n\nfn main() {\n  let a = FractionalIndex::default();\n  let b = FractionalIndex::new_after(\u0026a);\n  let c = FractionalIndex::new_between(\u0026a, \u0026b).unwrap();\n\n  let my_struct = MyStruct {\n    a: a.clone(),\n    b: b.clone(),\n    c: c.clone(),\n  };\n\n  let json_value = serde_json::to_value(\u0026my_struct).unwrap();\n\n  let expected = json!({\n    \"a\": \"80\",\n    \"b\": \"8180\",\n    \"c\": \"817f80\",\n  });\n\n  assert_eq!(expected, json_value);\n}\n```\n\n## Stability\n\nThe byte representation of a `FractionalIndex` can be relied upon to be fully forward- and backward-compatible with future versions of this crate, meaning that the serialized representation of two `FractionalIndex`es produced by any version of this crate will compare the same way when deserialized in any other version.\n\nThe actual byte representation of `FractionalIndex`es created by `new_before`, `new_after`, and `new_between` may differ between versions, but the result will always compare appropriately with the reference `FractionalIndex`(es) used for construction regardless of version.\n\nThe byte representation of a `FractionalIndex` is **not** meant to be compatible with the byte representaiton of a `ZenoIndex`, nor are their serialized counterparts.\n\n## Version 2.x.x note\n\nIn version 1.x.x of this crate, fractional indexing was implemented through a struct called `ZenoIndex`. The implementation of `ZenoIndex` is similar to `FractionalIndex`, and they both represent the underlying data as a byte string, but `ZenoIndex` requires a custom comparison function to be used with that byte string. `FractionalIndex` changes the byte representation so that a lexicographical comparison of the underlying byte data is all that is required to compare two `FractionalIndex`es.\n\nThe `ZenoIndex` struct is still available in version 2.x.x of this crate, but it is deprecated. New code should use `FractionalIndex` instead, which implements the same functionality.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamsocket%2Ffractional_index","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjamsocket%2Ffractional_index","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamsocket%2Ffractional_index/lists"}