Show HN: Hsrs – 用于 Rust 的类型安全 Haskell 绑定生成器

Hacker News Top 工具

摘要

Hsrs 是一个类型安全的 FFI 绑定生成器,允许从 Haskell 调用 Rust 代码,具有自动内存管理、类型转换和 Borsh 序列化功能。它在 Rust 中提供注解,并生成符合语言习惯的 Haskell 包装器。

大家好!我一直在开发 hsrs,这是一个用于 Rust 的类型安全 Haskell 绑定生成器。<p>我没怎么找到能够从 Rust 为 Haskell 生成类型安全且功能丰富的绑定的生成器。自然,两种语言都有丰富的类型系统,所以我惊讶于竟然没有一款优秀的绑定生成器已经存在,于是我决定自己写一个。hsrs 与 pyo3 和 napi-rs 非常相似,如果你用过它们,使用 hsrs 会感到非常顺手。<p>与 hs-bindgen 不同的是,hsrs 的独特之处在于它为 Result、Maybe 等丰富类型提供了类型安全绑定,同时还能生成 Haskell 绑定。仓库中包含一个最小示例,更多细节可以在 Haskell Discourse 上找到:<a href="https://discourse.haskell.org/t/ann-hsrs-ergonomic-haskell-bindings-for-rust/14129" rel="nofollow">https://discourse.haskell.org/t/ann-hsrs-ergonomic-haskell-b...</a>
查看原文
查看缓存全文

缓存时间: 2026/05/19 07:01

harmont-dev/hsrs

来源:https://github.com/harmont-dev/hsrs

hsrs 操作状态

actions status
codecov
crates.io
最低 rustc 版本 1.85 (https://blog.rust-lang.org/2025/02/20/Rust-1.85.0.html)
discord
从 Haskell 调用 Rust,使用类型安全、自动生成的 FFI 绑定。
给你的 Rust 类型和函数加上注解,运行代码生成器,就能得到符合 Haskell 惯用法的代码,它会自动处理内存管理、序列化和类型转换。

快速开始

1. 注解你的 Rust 代码

#[hsrs::module]
mod canvas {
    #[hsrs::value_type]
    pub struct Point {
        pub x: i32,
        pub y: i32,
    }

    #[hsrs::data_type]
    pub struct Canvas {
        points: Vec<Point>,
    }

    impl Canvas {
        #[hsrs::function]
        pub fn new() -> Self {
            Self { points: vec![] }
        }

        #[hsrs::function]
        pub fn add_point(&mut self, p: Point) {
            self.points.push(p);
        }

        #[hsrs::function]
        pub fn count(&self) -> u64 {
            self.points.len() as u64
        }
    }
}

2. 生成 Haskell 绑定

cargo install hsrs-codegen
hsrs-codegen src/lib.rs -o Bindings.hs

3. 在 Haskell 中使用

import Bindings

main :: IO ()
main = do
    c <- new
    addPoint c (Point 10 20)
    n <- count c
    print n  -- 输出 1

就是这样。内存通过 ForeignPtr 自动管理,复杂的类型(如 Point)则通过 Borsh (https://borsh.io) 在边界上进行序列化。

环境搭建

Rust 侧 —— 在 crate 中添加 hsrs

[lib]
crate-type = ["lib", "staticlib"]

[dependencies]
hsrs = "0.1"

Haskell 侧 —— 添加 hsrs 运行时包:

build-depends: hsrs >= 0.1 && < 0.2

这会自动引入 Borsh 序列化,无需额外依赖。

可注解的内容

注解作用Haskell 结果
#[hsrs::data_type]通过指针传递的不透明结构体ForeignPtr 新类型,自动清理
#[hsrs::enumeration]与 C 兼容的枚举(repr(u8)Word8 新类型,带有模式同义词
#[hsrs::value_type]通过 Borsh 按值传递的结构体data 记录,派生 Borsh
#[hsrs::function]通过 FFI 导出的方法类型安全的 Haskell 包装器
#[hsrs::module]将数据类型及其方法分组为该类型生成所有 FFI 胶水代码

Result 变为 Either E TOption 变为 Maybe TVec<T> 变为 [T]String 变为 Text —— 所有类型都通过 Borsh 透明地序列化。

支持的类型

RustHaskell传输方式
i8, i16, i32, i64Int8, Int16, Int32, Int64直接 (C FFI)
u8, u16, u32, u64Word8, Word16, Word32, Word64直接 (C FFI)
boolCBool直接 (C FFI)
usize / isizeWord64 / Int64直接 (C FFI)
#[hsrs::enumeration] 枚举Word8 新类型 + 模式直接 (C FFI)
#[hsrs::value_type] 结构体data 记录Borsh
StringTextBorsh
Vec<T>[T]Borsh
Option<T>Maybe TBorsh
Result<T, E>Either E TBorsh

平台说明

usizeisize 分别映射为 Word64Int64。这与 64 位平台(x86_64、aarch64)一致。如果你面向 32 位平台,请注意值可能被截断。

完整示例

一个带有枚举、值类型、Result 和 Option 的小型虚拟机

Rust

#[hsrs::module]
mod quecto_vm {
    #[derive(Debug, PartialEq, Eq)]
    #[hsrs::enumeration]
    pub enum Register {
        Reg0,
        Reg1,
        Count,
    }

    #[derive(Debug, PartialEq, Eq)]
    #[hsrs::value_type]
    pub struct Point {
        pub x: i32,
        pub y: i32,
    }

    #[derive(Debug, PartialEq, Eq)]
    #[hsrs::value_type]
    pub struct VmError {
        pub code: u32,
    }

    #[hsrs::data_type]
    pub struct QuectoVm {
        registers: [i64; Register::Count as usize],
        clock: usize,
    }

    impl QuectoVm {
        #[hsrs::function]
        pub fn new() -> Self {
            /* ... */
        }

        #[hsrs::function]
        pub fn store(&mut self, r: Register, v: i64) {
            /* ... */
        }

        #[hsrs::function]
        pub fn snapshot(&self) -> Point {
            /* ... */
        }

        #[hsrs::function]
        pub fn safe_div(&mut self, a: Register, b: Register) -> Result<i64, VmError> {
            /* ... */
        }

        #[hsrs::function]
        pub fn nonzero(&self, r: Register) -> Option<i64> {
            /* ... */
        }
    }
}

生成的 Haskell

newtype Register = Register Word8
    deriving (Eq, Show, Storable)
    deriving (BorshSize, ToBorsh, FromBorsh) via Word8

pattern Reg0 :: Register
pattern Reg0 = Register 0

data Point = Point
    { pointX :: Int32
    , pointY :: Int32
    }
    deriving (Generic, Eq, Show)
    deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct Point

data VmError = VmError
    { vmErrorCode :: Word32
    }
    deriving (Generic, Eq, Show)
    deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct VmError

data QuectoVmRaw
newtype QuectoVm = QuectoVm (ForeignPtr QuectoVmRaw)

new :: IO QuectoVm
store :: QuectoVm -> Register -> Int64 -> IO ()
snapshot :: QuectoVm -> IO Point
safeDiv :: QuectoVm -> Register -> Register -> IO (Either VmError Int64)
nonzero :: QuectoVm -> Register -> IO (Maybe Int64)

许可证

MIT 或 Apache-2.0

相似文章

hax:一个Rust验证工具

Lobsters Hottest

hax是一个将Rust代码翻译成F*、Rocq和Lean等正式语言以进行高保障验证的工具。