[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-80533":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":13,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":15,"stars7d":16,"stars30d":17,"stars90d":15,"forks30d":15,"starsTrendScore":15,"compositeScore":18,"rankGlobal":10,"rankLanguage":10,"license":19,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":10,"pushedAt":10,"updatedAt":41,"readmeContent":42,"aiSummary":43,"trendingCount":15,"starSnapshotCount":15,"syncStatus":44,"lastSyncTime":45,"discoverSource":46},80533,"hsrs","harmont-dev\u002Fhsrs","harmont-dev","Type-safe Haskell Rust Bindings","",null,"Rust",76,1,6,0,4,15,44.4,"MIT License",false,"main",true,[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40],"bindgen","binding-generator","bindings","borsh","cabal","cargo","codegen","ffi","haskell","haskell-bindings","interop","macros","proc-macro","rust","rust-bindings","serialization","type-safe","2026-06-12 04:01:29","# hsrs\n\n[![actions status](https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Factions\u002Fworkflow\u002Fstatus\u002Fharmont-dev\u002Fhsrs\u002Fci.yml?branch=main&logo=github)](https:\u002F\u002Fgithub.com\u002Fharmont-dev\u002Fhsrs\u002Factions)\n[![codecov](https:\u002F\u002Fimg.shields.io\u002Fcodecov\u002Fc\u002Fgh\u002Fharmont-dev\u002Fhsrs?logo=codecov)](https:\u002F\u002Fcodecov.io\u002Fgh\u002Fharmont-dev\u002Fhsrs)\n[![crates.io](https:\u002F\u002Fimg.shields.io\u002Fcrates\u002Fv\u002Fhsrs?logo=rust)](https:\u002F\u002Fcrates.io\u002Fcrates\u002Fhsrs)\n[![minimum rustc 1.85](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Frustc-1.85+-blue?logo=rust)](https:\u002F\u002Fblog.rust-lang.org\u002F2025\u002F02\u002F20\u002FRust-1.85.0.html)\n[![discord](https:\u002F\u002Fimg.shields.io\u002Fdiscord\u002F1503184719578136576?logo=discord)](https:\u002F\u002Fdiscord.gg\u002FTcXYncqFWj)\n\nCall Rust from Haskell with type-safe, automatically generated FFI bindings.\n\nAnnotate your Rust types and functions, run the code generator, and get idiomatic Haskell that handles memory management, serialization, and type conversions for you.\n\n## Quick start\n\n### 1. Annotate your Rust code\n\n```rust\n#[hsrs::module]\nmod canvas {\n    #[hsrs::value_type]\n    pub struct Point {\n        pub x: i32,\n        pub y: i32,\n    }\n\n    #[hsrs::data_type]\n    pub struct Canvas {\n        points: Vec\u003CPoint>,\n    }\n\n    impl Canvas {\n        #[hsrs::function]\n        pub fn new() -> Self { Self { points: vec![] } }\n\n        #[hsrs::function]\n        pub fn add_point(&mut self, p: Point) { self.points.push(p); }\n\n        #[hsrs::function]\n        pub fn count(&self) -> u64 { self.points.len() as u64 }\n    }\n}\n```\n\n### 2. Generate Haskell bindings\n\n```sh\ncargo install hsrs-codegen\nhsrs-codegen src\u002Flib.rs -o Bindings.hs\n```\n\n### 3. Use from Haskell\n\n```haskell\nimport Bindings\n\nmain :: IO ()\nmain = do\n  c \u003C- new\n  addPoint c (Point 10 20)\n  n \u003C- count c\n  print n  -- 1\n```\n\nThat's it. Memory is managed automatically via `ForeignPtr`, and complex types like `Point` are serialized across the boundary with [Borsh](https:\u002F\u002Fborsh.io).\n\n## Setup\n\n**Rust side** — add `hsrs` to your crate:\n\n```toml\n[lib]\ncrate-type = [\"lib\", \"staticlib\"]\n\n[dependencies]\nhsrs = \"0.1\"\n```\n\n**Haskell side** — add the `hsrs` runtime package:\n\n```cabal\nbuild-depends:\n    hsrs >= 0.1 && \u003C 0.2\n```\n\nThis pulls in Borsh serialization automatically — no extra dependencies needed.\n\n## What you can annotate\n\n| Annotation | What it does | Haskell result |\n|---|---|---|\n| `#[hsrs::data_type]` | Opaque struct passed by pointer | `ForeignPtr` newtype with automatic cleanup |\n| `#[hsrs::enumeration]` | C-compatible enum (`repr(u8)`) | `Word8` newtype with pattern synonyms |\n| `#[hsrs::value_type]` | Struct passed by value via Borsh | `data` record with Borsh deriving |\n| `#[hsrs::function]` | Method exported over FFI | Type-safe Haskell wrapper |\n| `#[hsrs::module]` | Groups a data type with its methods | Generates all FFI glue for the type |\n\n`Result\u003CT, E>` becomes `Either E T`, `Option\u003CT>` becomes `Maybe T`, `Vec\u003CT>` becomes `[T]`, and `String` becomes `Text` — all serialized transparently via Borsh.\n\n## Supported types\n\n| Rust | Haskell | Transfer |\n|---|---|---|\n| `i8`, `i16`, `i32`, `i64` | `Int8`, `Int16`, `Int32`, `Int64` | Direct (C FFI) |\n| `u8`, `u16`, `u32`, `u64` | `Word8`, `Word16`, `Word32`, `Word64` | Direct (C FFI) |\n| `bool` | `CBool` | Direct (C FFI) |\n| `usize` \u002F `isize` | `Word64` \u002F `Int64` | Direct (C FFI) |\n| `#[hsrs::enumeration]` enum | `Word8` newtype + patterns | Direct (C FFI) |\n| `#[hsrs::value_type]` struct | `data` record | Borsh |\n| `String` | `Text` | Borsh |\n| `Vec\u003CT>` | `[T]` | Borsh |\n| `Option\u003CT>` | `Maybe T` | Borsh |\n| `Result\u003CT, E>` | `Either E T` | Borsh |\n\n## Platform notes\n\n`usize` and `isize` are mapped to `Word64` and `Int64` respectively. This matches 64-bit platforms (x86_64, aarch64). If you target 32-bit platforms, be aware that values may be truncated.\n\n## Full example\n\n\u003Cdetails>\n\u003Csummary>A small VM with enums, value types, Result, and Option\u003C\u002Fsummary>\n\n### Rust\n\n```rust\n#[hsrs::module]\nmod quecto_vm {\n    #[derive(Debug, PartialEq, Eq)]\n    #[hsrs::enumeration]\n    pub enum Register { Reg0, Reg1, Count }\n\n    #[derive(Debug, PartialEq, Eq)]\n    #[hsrs::value_type]\n    pub struct Point { pub x: i32, pub y: i32 }\n\n    #[derive(Debug, PartialEq, Eq)]\n    #[hsrs::value_type]\n    pub struct VmError { pub code: u32 }\n\n    #[hsrs::data_type]\n    pub struct QuectoVm {\n        registers: [i64; Register::Count as usize],\n        clock: usize,\n    }\n\n    impl QuectoVm {\n        #[hsrs::function]\n        pub fn new() -> Self { \u002F* ... *\u002F }\n\n        #[hsrs::function]\n        pub fn store(&mut self, r: Register, v: i64) { \u002F* ... *\u002F }\n\n        #[hsrs::function]\n        pub fn snapshot(&self) -> Point { \u002F* ... *\u002F }\n\n        #[hsrs::function]\n        pub fn safe_div(&mut self, a: Register, b: Register) -> Result\u003Ci64, VmError> { \u002F* ... *\u002F }\n\n        #[hsrs::function]\n        pub fn nonzero(&self, r: Register) -> Option\u003Ci64> { \u002F* ... *\u002F }\n    }\n}\n```\n\n### Generated Haskell\n\n```haskell\nnewtype Register = Register Word8\n  deriving (Eq, Show, Storable)\n  deriving (BorshSize, ToBorsh, FromBorsh) via Word8\n\npattern Reg0 :: Register\npattern Reg0 = Register 0\n\ndata Point = Point\n  { pointX :: Int32\n  , pointY :: Int32\n  } deriving (Generic, Eq, Show)\n  deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct Point\n\ndata VmError = VmError\n  { vmErrorCode :: Word32\n  } deriving (Generic, Eq, Show)\n  deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct VmError\n\ndata QuectoVmRaw\nnewtype QuectoVm = QuectoVm (ForeignPtr QuectoVmRaw)\n\nnew       :: IO QuectoVm\nstore     :: QuectoVm -> Register -> Int64 -> IO ()\nsnapshot  :: QuectoVm -> IO Point\nsafeDiv   :: QuectoVm -> Register -> Register -> IO (Either VmError Int64)\nnonzero   :: QuectoVm -> Register -> IO (Maybe Int64)\n```\n\n\u003C\u002Fdetails>\n\n## License\n\nMIT OR Apache-2.0\n","hsrs 是一个用于生成 Haskell 和 Rust 之间类型安全的 FFI 绑定的工具。其核心功能包括通过注解 Rust 代码自动生成 Haskell 绑定，支持内存管理、序列化和类型转换。该工具利用 Borsh 进行跨语言的数据序列化，并提供了多种注解来处理不同类型的数据结构和函数。适合于需要在 Haskell 项目中调用 Rust 代码且希望保持类型安全性和开发效率的场景，如高性能计算、数据处理等。",2,"2026-06-11 04:01:08","CREATED_QUERY"]