{"id":49528040,"url":"https://github.com/geeknoid/multitude","last_synced_at":"2026-05-02T04:04:57.281Z","repository":{"id":354026210,"uuid":"1221712958","full_name":"geeknoid/multitude","owner":"geeknoid","description":"Fast and flexible arena allocator for Rust","archived":false,"fork":false,"pushed_at":"2026-04-27T05:10:19.000Z","size":477,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-27T05:22:39.259Z","etag":null,"topics":["arena-allocator","bump-allocator","memory-management"],"latest_commit_sha":null,"homepage":"","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/geeknoid.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-26T15:31:15.000Z","updated_at":"2026-04-27T05:10:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/geeknoid/multitude","commit_stats":null,"previous_names":["geeknoid/harena","geeknoid/multitude"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/geeknoid/multitude","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geeknoid%2Fmultitude","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geeknoid%2Fmultitude/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geeknoid%2Fmultitude/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geeknoid%2Fmultitude/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/geeknoid","download_url":"https://codeload.github.com/geeknoid/multitude/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geeknoid%2Fmultitude/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32522253,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-02T01:12:54.858Z","status":"online","status_checked_at":"2026-05-02T02:00:05.923Z","response_time":132,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["arena-allocator","bump-allocator","memory-management"],"created_at":"2026-05-02T04:04:23.202Z","updated_at":"2026-05-02T04:04:57.261Z","avatar_url":"https://github.com/geeknoid.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# multitude\n\n[![crate.io](https://img.shields.io/crates/v/multitude.svg)](https://crates.io/crates/multitude)\n[![docs.rs](https://docs.rs/multitude/badge.svg)](https://docs.rs/multitude)\n[![CI](https://github.com/geeknoid/multitude/workflows/main/badge.svg)](https://github.com/geeknoid/multitude/actions)\n[![Coverage](https://codecov.io/gh/geeknoid/multitude/graph/badge.svg?token=FCUG0EL5TI)](https://codecov.io/gh/geeknoid/multitude)\n[![Minimum Supported Rust Version 1.95](https://img.shields.io/badge/MSRV-1.95-blue.svg)]()\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)\n\n- [Summary](#summary)\n  - [Bump allocation](#bump-allocation)\n  - [What `multitude` adds](#what-multitude-adds)\n  - [Quick start](#quick-start)\n    - [Smart pointers outlive the arena](#smart pointers-outlive-the-arena)\n    - [Cross-thread sharing](#cross-thread-sharing)\n    - [Owned single smart pointer (`ArenaBox`)](#owned-single-smart pointer-arenabox)\n    - [Collections in the arena](#collections-in-the-arena)\n    - [Build-then-freeze: shrink long-lived collections to a single pointer](#build-then-freeze-shrink-long-lived-collections-to-a-single-pointer)\n  - [Comparison with `bumpalo`](#comparison-with-bumpalo)\n    - [Choosing a smart pointer](#choosing-a-smart pointer)\n    - [Promoting an owned box to a shared `ArenaRc`](#promoting-an-owned-box-to-a-shared-arenarc)\n    - [Building DSTs (`dst` feature)](#building-dsts-dst-feature)\n  - [Crate features](#crate-features)\n  - [Thread support](#thread-support)\n  - [FAQ](#faq)\n    - [Why no small-string optimization for `ArenaString`?](#why-no-small-string-optimization-for-arenastring)\n    - [Why no `SmallVec`-style inline storage for `ArenaVec`?](#why-no-smallvec-style-inline-storage-for-arenavec)\n    - [Why no `ArenaSlice\u003cT\u003e` (single-pointer slice smart pointer)?](#why-no-arenaslicet-single-pointer-slice-smart pointer)\n\n## Summary\n\n\u003c!-- cargo-rdme start --\u003e\n\nFast and flexible arena-based bump allocator.\n\n`multitude` is an arena-based bump allocator designed to improve the performance of applications that have **phase-oriented logic**, which\nis when groups of related allocations live and die together. Service request handling and parsers are two examples of this pattern which usually\nbenefit from a bump allocator.\n\n`multitude` works by accumulating large chunks of memory allocated from the system and then carving out smaller pieces of it for application use\nusing a fast bump allocation strategy, which is considerably faster than allocating from the system. The downside however is that the individual allocations\ncan't be freed separately. Instead, memory is reclaimed and returned to the system in bulk when the entire arena is dropped.\n\n## Why Another Bump Allocator?\n\nThe Rust ecosystem has a few bump allocators, the most popular being [`bumpalo`](https://crates.io/crates/bumpalo).\n`multitude` uses a different implementation strategy and has a richer API surface making it suitable for more\nuse cases. The main features that set `multitude` apart are:\n\n1. **Flexibility.** `multitude` provides multiple allocation styles, all of\n   which can coexist in the same arena:\n\n   - Mutable references with lifetimes tied to the arena (`\u0026mut T`,\n     `\u0026mut str`, `\u0026mut [T]`).\n   - Reference-counted smart pointers ([`Rc`], [`RcStr`]) for\n     single-threaded sharing.\n   - Atomic reference-counted smart pointers ([`Arc`], [`ArcStr`])\n     for cross-thread sharing.\n   - Owned, mutable smart pointers ([`Box`], [`BoxStr`]).\n\n2. **Early Reclamation.** In many situations, `multitude` can reclaim memory from individual chunks as soon as their reference counts drop to zero,\n   without waiting for the entire arena to be dropped. This allows for more efficient memory usage in long-running arenas with many short-lived allocations.\n\n3. **Smart Pointers Can Outlive the Arena.** The reference-counted smart pointers produced by `multitude` can keep their owning chunk alive even after the arena itself has been dropped,\n   allowing for more flexible memory management and longer-lived data structures.\n\n4. **Drop Support.** `multitude` automatically runs `Drop` for allocated values at the appropriate time.\n\n5. **Efficient Immutable String References.** `multitude` provides [`RcStr`], [`ArcStr`], and\n   [`BoxStr`] — single-pointer (8 bytes) smart pointers to UTF-8 strings stored in the arena. Refcounted, atomic-refcounted,\n   and owned-mutable variants respectively, all sharing the same compact layout.\n\n6. **Efficient Mutable Strings and Vectors.** With the `builders` Cargo feature (default-on), `multitude` provides `String` and `Vec` which are growable collections that live in the arena and can be frozen into compact\n   reference-counted smart pointers when you're done building.\n\n7. **Dynamically-Sized Types.** `multitude` supports dynamically-sized types (DSTs) like slices and strings, allowing you to allocate and manage them in the\n   arena with the same flexibility as sized types. The [`dst-factory`](https://crates.io/crates/dst-factory) crate is a great companion for building DSTs in the arena.\n\n8. **`format!`-style Macro.** `multitude` includes a `format!`-style macro that allows you to create formatted strings directly in the arena, avoiding intermediate allocations and copies.\n\n9. **UTF-16 Support.** With the `utf16` Cargo feature, `multitude` provides a parallel set of arena-resident UTF-16 string types ([`RcUtf16Str`],\n   [`ArcUtf16Str`], [`BoxUtf16Str`], `Utf16String`) and a `format_utf16!` macro for FFI / Windows / JS-engine\n   interop without per-call transcoding at every boundary.\n\n10. **`#![no_std]` Support.** `multitude` can be used in `#![no_std]` environments, making it suitable for embedded systems and other resource-constrained contexts.\n\n## Example\n\n```rust\nuse multitude::Arena;\n\nlet arena = Arena::new();\n\n// Cheap reference-counted allocation of any user type.\nstruct Point { x: f64, y: f64 }\nlet p = arena.alloc_rc(Point { x: 3.0, y: 4.0 });\nlet p2 = p.clone();\nassert_eq!(p.x, p2.x);\n\n// Single-pointer immutable strings.\nlet name = arena.alloc_str_rc(\"Alice\");\nassert_eq!(\u0026*name, \"Alice\");\n\n// format! macro returning an String (call .into_arena_str() to\n// freeze into a compact 8-byte RcStr).\nlet greeting = multitude::builders::format!(in \u0026arena, \"Hello, {}!\", \"world\");\nassert_eq!(\u0026*greeting, \"Hello, world!\");\n```\n## Flexibility\n\n`multitude` supports a variety of ways to allocate data and track it over time.\n\n### Simple References\n\nThe simplest use of the arena is to get plain mutable references. The lifetime of those references is then tied\nto the arena's own lifetime.\n\n```rust\nlet arena = multitude::Arena::new();\nlet x: \u0026mut u32 = arena.alloc(42);\nlet y: \u0026mut u32 = arena.alloc(100);\n*x += 1;\n*y += 1;\nassert_eq!(*x, 43);\nassert_eq!(*y, 101);\n\n// Strings and slices too:\nlet s: \u0026mut str = arena.alloc_str(\"hello\");\nlet v: \u0026mut [i32] = arena.alloc_slice_copy(\u0026[1, 2, 3]);\n```\n\nThese references can't outlive the arena, which limits their use. But they are the fastest and\nmost efficient way to allocate from the arena, so if the lifetime constraints are tolerable, simple\nreferences are the way to go.\n\n### Smart Pointers\n\nSmart pointers ([`Rc`], [`Arc`], [`Box`] and their `str` variations) work in a way similar to the like-named types\nin the standard library, except that they reference addresses within an arena.\n\n```rust\nuse multitude::Rc;\n\nstruct Point { x: f64, y: f64 }\n\nlet p: Rc\u003cPoint\u003e = {\n    let arena = multitude::Arena::new();\n    arena.alloc_rc(Point { x: 3.0, y: 4.0 })\n    // arena dropped here\n};\nassert_eq!(p.x, 3.0);\n```\n\nAlthough [`Arena`] itself is single-threaded (`!Send` and `!Sync`), the arc-family of types (e.g., [`Arc`]) enable cross-thread sharing.\n\n```rust\nlet arena = multitude::Arena::new();\nlet shared = arena.alloc_arc(42_u64);\nlet h = std::thread::spawn(move || *shared);\nassert_eq!(42, h.join().unwrap());\n```\n\n[`Box`] is a unique owner whose `Drop` runs `T::drop` immediately\nwhen the smart pointer is dropped and provides `\u0026mut T` access, similar to\n[`alloc::boxed::Box`] but backed by the arena.\n\n```rust\nlet arena = multitude::Arena::new();\nlet mut v = arena.alloc_box(vec![1, 2, 3]);\nv.push(4);\nassert_eq!(*v, vec![1, 2, 3, 4]);\ndrop(v); // Vec's drop runs here, freeing its heap buffer.\n```\n\n### Collections\n\n`Vec` and `String` are growable collections that live in\nthe arena.\n\nAdditionally, you can use an arena as\nthe allocator for any type from the [`allocator_api2`] ecosystem\n(including `hashbrown::HashMap`).\n\n```rust\nuse multitude::Arena;\nuse multitude::builders::{Vec, CollectIn};\n\nlet arena = Arena::new();\n\nlet mut v = arena.alloc_vec::\u003ci32\u003e();\nfor i in 0..5 { v.push(i); }\n\n// CollectIn trait for iterator collection.\nlet squares: Vec\u003ci32, _\u003e = (1..=5).map(|i| i * i).collect_in(\u0026arena);\nassert_eq!(squares.as_slice(), \u0026[1, 4, 9, 16, 25]);\n```\n\n### Freezing\n\n`String` and `Vec` are designed as **transient\nbuilders**. They carry a data pointer + length + capacity + arena reference.\n\nOnce you're done building, you can **freeze them** into immutable smart pointers:\n\n- `String::into_arena_str` → [`RcStr`] (**8 bytes**). The\n  freeze itself is **O(1)** — no copy, no new allocation.\n- `Vec::into_arena_rc` → `Rc\u003c[T]\u003e` (16-byte slice fat\n  pointer; immutable, cloneable, refcount-based). For `T: !Drop`,\n  the freeze is **O(1)** too.\n\nBoth freezes also reclaim any unused capacity left in the buffer\nwhen the conditions allow it, so those bytes become available for\nthe next allocation.\n\n```rust\nuse multitude::{Arena, RcStr};\n\nlet arena = Arena::new();\n\n// Build phase: 32-byte builder, alive briefly.\nlet mut builder = arena.alloc_string();\nbuilder.push_str(\"hello, \");\nbuilder.push_str(\"world\");\n\n// Freeze for storage: 8-byte single-pointer smart pointer. O(1) — no copy.\nlet stored: RcStr = builder.into_arena_str();\nassert_eq!(\u0026*stored, \"hello, world\");\n```\n\nUse this pattern whenever you'd be storing many strings or slices\nlong-term — the per-pointer savings (16 bytes for strings, 8 for\nslices) add up quickly across millions of items, and the frozen\nsmart pointers are also cheaper to clone.\n\n## Comparison with `bumpalo`\n\n[`bumpalo`](https://crates.io/crates/bumpalo) is the closest crate in\nspirit; here's how multitude differs.\n\n| Capability | `bumpalo` | `multitude` |\n|---|---|---|\n| Bump allocation | ✅ | ✅ |\n| Simple references (`\u0026'arena mut T`) | ✅ `Bump::alloc` | ✅ [`Arena::alloc`] |\n| `Allocator` trait integration | ✅ via `allocator-api2` | ✅ via `allocator-api2` |\n| Reclamation granularity | Whole arena at reset | **Per chunk**, as refcounts hit 0 (refcount smart pointers); whole-arena (simple references) |\n| Smart pointers | ❌ (raw `\u0026'bump T`) | ✅ [`Rc`], [`Arc`], [`RcStr`] |\n| Smart pointers outlive the arena | ❌ | ✅ ([`Rc`] / [`Arc`] / [`Box`] and their `str` variants — simple references are lifetime-bound) |\n| Cross-thread sharing of individual values | ❌ | ✅ via [`Arc`] |\n| Automatic per-object `Drop` | Only via `bumpalo::boxed::Box` | ✅ Automatic (refcount smart pointers drop at chunk teardown; [`Box`] / [`BoxStr`] drop at smart pointer drop; simple references drop at arena drop) |\n| Owned single smart pointer (`Drop` on drop) | `bumpalo::boxed::Box` | [`Box`] |\n| Single-pointer string smart pointers | ❌ (`\u0026str` is 16 bytes) | ✅ [`RcStr`] / [`ArcStr`] / [`BoxStr`] are 8 bytes |\n| Growable collections | ✅ `bumpalo::collections` | ✅ `Vec`, `String` |\n| `format!`-style macro | ✅ | ✅ |\n| UTF-16 strings | ❌ | ✅ via `RcUtf16Str` / `ArcUtf16Str` / `BoxUtf16Str` / `Utf16String` (gated on the `utf16` feature) |\n| Dynamically-sized types (DSTs, e.g. `dyn Trait`, `[T]`) | ❌ | ✅ via the `dst` module (gated on the `dst` feature) |\n| `#![no_std]` | ✅ | ✅ |\n\n## Crate Features\n\n- **`std`** — enables `std::io::Write`-style integration\n  where applicable. Disable for `#![no_std]` environments (the crate\n  still requires `alloc`).\n- **`builders`** — enables the [`builders`] module,\n  which contains the growable collection types\n  (`String`,\n  `Vec`,\n  `Utf16String`), the `CollectIn` / `FromIteratorIn` traits, and\n  the `format!` / `vec!` / `format_utf16!` macros. Also adds the\n  matching `Arena::alloc_string` / `alloc_vec` / `alloc_utf16_string`\n  methods. Disable for the leanest builds — the smart pointers\n  ([`RcStr`], [`Rc`], etc.) and `Arena::alloc_str_*` /\n  `alloc_*_slice_*` still work without it.\n- **`stats`** — enables runtime instrumentation counters\n  returned by `Arena::stats`. Disable for the tightest allocation\n  throughput when you don't need observability.\n- **`serde`** — adds `Serialize` impls for [`RcStr`],\n  [`ArcStr`], and (with `builders`)\n  `String` and\n  `Vec`. With\n  `serde + utf16`, also adds `Serialize` impls for the UTF-16\n  types (transcoded to UTF-8 on the wire).\n- **`dst`** — enables the `dst` module (`PendingRc`,\n  `PendingArc`, `PendingBox`) for constructing\n  true dynamically-sized types and trait objects in the arena, plus\n  eight `Arena::alloc_slice_*_box` methods.\n- **`utf16`** — adds a parallel UTF-16 string surface\n  (`RcUtf16Str`, `ArcUtf16Str`, `BoxUtf16Str`, plus\n  `Utf16String` and `format_utf16!` when combined with\n  `builders`) backed by the\n  [`widestring`](https://crates.io/crates/widestring) crate. All\n  length and capacity values are counted in `u16` elements (matching\n  `widestring::Utf16Str::len()`).\n\nThe default-enabled features are `std` and `builders`.\n\n## UTF-16 Strings\n\nWith the `utf16` Cargo feature enabled, `multitude` exposes a\nparallel set of arena-resident UTF-16 string types that mirror the\nUTF-8 surface element-for-element:\n\n| UTF-8 type        | UTF-16 analogue          |\n|-------------------|--------------------------|\n| [`RcStr`]    | `RcUtf16Str`        |\n| [`ArcStr`]   | `ArcUtf16Str`       |\n| [`BoxStr`]   | `BoxUtf16Str`       |\n| `String`   | `Utf16String`       |\n\nStrict (validated) UTF-16 only — lone surrogates are rejected. The\ntypes are interoperable with `widestring::Utf16Str` /\n`widestring::Utf16String` for I/O and FFI bridging.\n\n```rust\nuse multitude::Arena;\nuse widestring::utf16str;\n\nlet arena = Arena::new();\n\n// From a validated \u0026Utf16Str literal:\nlet s = arena.alloc_utf16_str_rc(utf16str!(\"hello, world\"));\nassert_eq!(\u0026*s, utf16str!(\"hello, world\"));\n\n// Or transcode from a \u0026str:\nlet s2 = arena.alloc_utf16_str_rc_from_str(\"hello\");\nassert_eq!(\u0026*s2, utf16str!(\"hello\"));\n\n// Build incrementally and freeze:\nlet mut b = arena.alloc_utf16_string();\nb.push_str(utf16str!(\"abc\"));\nb.push_from_str(\"123\");\nlet frozen = b.into_arena_utf16_str();\nassert_eq!(\u0026*frozen, utf16str!(\"abc123\"));\n\n// format!-style:\nlet name = \"Alice\";\nlet greeting = multitude::builders::format_utf16!(in \u0026arena, \"Hello, {name}!\");\nassert_eq!(greeting.as_utf16_str(), utf16str!(\"Hello, Alice!\"));\n```\n\n## Building DSTs\n\nWith the `dst` Cargo feature enabled, `multitude` exposes the\n`dst` module containing three pending-reservation\nbuilders — `PendingRc`, `PendingArc`, and\n`PendingBox` — for constructing\nvalues whose layout is only known at runtime (custom DSTs, fat\npointers, trait objects).\n\nThe two-phase pattern (reserve raw bytes → initialize → finalize)\nlets you build any value the standard `alloc_*` methods can't\nexpress. For most users, the `dst-factory` companion crate is the\nrecommended high-level driver; the low-level interface looks like:\n\n```rust\nuse core::alloc::Layout;\nuse multitude::{Arena, dst::PendingBox};\n\nlet arena = Arena::new();\n\n// Reserve room for a u32 (any layout works — typically a custom DST).\nlet layout = Layout::new::\u003cu32\u003e();\nlet mut pending = PendingBox::new(\u0026arena, layout);\n\n// Initialize the reservation.\n// Writing a fully-initialized u32 into the reservation is safe\n// because the layout above matches `u32` exactly.\nunsafe { pending.as_mut_ptr().cast::\u003cu32\u003e().write(0xCAFE_BABE); }\n\n// Finalize. For non-Drop types, drop_fn is None.\nlet template: u32 = 0;\n// Bytes are initialized above; u32 doesn't need Drop, so drop_fn is None.\nlet b = unsafe { pending.finalize::\u003cu32\u003e(\u0026raw const template, None) };\nassert_eq!(*b, 0xCAFE_BABE);\n```\n\nThe same feature also enables eight `Arena::alloc_slice_*_box`\nmethods that produce `Box\u003c[T]\u003e` directly (mirroring the\nexisting `_rc`/`_arc` slice methods).\n\n## How it Works\n\nA high-level sketch of what happens when you use the crate. For\nthe gory implementation details, read the source.\n\n### Chunks\n\nThe arena owns a list of large memory **chunks** allocated from the\nsystem. Each user allocation carves out a piece of the current\nchunk via a fast bump-pointer increment. When the current chunk\ncan't fit the next request, the arena rotates to a fresh chunk.\nAllocations larger than a chunk's usable capacity get their own\ndedicated **oversized chunks**.\n\n### Smart Pointers\n\nThe smart-pointer types ([`Rc`], [`Arc`], [`Box`])\nare deliberately compact — typically one pointer plus zero-sized\nmarkers. Reference counts live with the chunk, not with each smart\npointer, so cloning and dropping cost a single counter update.\n\nThe single-pointer string types ([`RcStr`], [`ArcStr`],\n[`BoxStr`]) go further: 8 bytes per smart pointer (vs 16\nfor `\u0026str`).\n\n### Reclamation\n\nWhen the last smart pointer into a chunk is dropped, the arena\nruns every destructor for values it hosted, then either parks the\nchunk in a free-list cache for fast reuse or returns its memory to\nthe system allocator. This **per-chunk reclamation** lets\nlong-lived arenas with churn keep their memory footprint bounded.\n\nSmart pointers ([`Rc`] / [`Arc`] / [`Box`] and their\n`str` variants) may **outlive the arena**: their chunks stay alive\nas long as any smart pointer references them, even after the arena\nitself has been dropped.\n\nReferences returned by [`Arena::alloc`] don't carry refcounts;\ntheir chunks live until arena drop. The borrow checker keeps them\nlifetime-bound to the arena.\n\n### Cross-Thread Sharing\n\nThe arena itself is `!Send` and `!Sync`. Cross-thread sharing\nhappens at the smart-pointer level via [`Arc`] /\n[`ArcStr`], which use atomic refcounts. Single-threaded code\nthat uses [`Rc`] only stays on cheap non-atomic operations.\n\n\u003c!-- cargo-rdme end --\u003e\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeeknoid%2Fmultitude","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgeeknoid%2Fmultitude","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeeknoid%2Fmultitude/lists"}