Experimental Rust tool for generating FFI definitions allowing many other languages to call Rust code

Related tags

Utilities diplomat
Overview

Diplomat

Diplomat is an experimental Rust tool for generating FFI definitions allowing many other languages to call Rust code. With Diplomat, you can simply define Rust APIs to be exposed over FFI and get high-level C, C++, and JavaScript bindings automatically!

Diplomat supports languages through a plugin interface that makes it easy to add support for your favourite language. See tool/src/{c, cpp, js} for examples of existing language plugins.

Installation

First, install the CLI tool for generating bindings:

$ cargo install diplomat-tool

Then, add the Diplomat macro and runtime as dependencies to your project:

diplomat = "0.2.0"
diplomat-runtime = "0.2.0"

Getting Started

Documentation on how to use Diplomat can be found in the book.

Architecture

See the design doc for more details.

Building and Testing

Simply run cargo build to build all the libraries and compile an example. To run unit tests, run cargo test.

Diplomat makes use of snapshot tests to check macro and code generation logic. When code generation logic changes and the snapshots need to be updated, run cargo insta review (run cargo install cargo-insta to get the tool) to view the changes and update the snapshots.

Comments
  • C# / dotnet target for `diplomat-tool`

    C# / dotnet target for `diplomat-tool`

    Hi,

    I've been writing a dotnet target for diplomat-tool in order to expose a C# API to picky. I actually used it to generate fully functional bindings to picky in my experiment repository. The only missing piece is a way to return a buffer of bytes (basically something like the DiplomatWriteable, but using std::io::Write instead of std::fmt::Write I guess).

    I still have a few corner cases to fix, but I figured I could open this PR as a draft.

    Todo before I consider the MVP complete

    • [x] Fix generated code when bool type is in return position.
    • [x] Special case to handle results using the unit () type as error.

    Future improvements

    • Proper handling of Option of enum in parameters
    • Support custom types in managed non-opaque struct's fields (aka: avoid double freeing). Currently the only way to access custom types of non-opaque structs is to use the "raw" API with pointers.
    opened by CBenoit 21
  • Remove intermediate `Uint8Array`s during slice conversion

    Remove intermediate `Uint8Array`s during slice conversion

    #172 introduces the DiplomatBuf class in diplomat_runtime.js, which basically handles conversion from JS strings and primitive slices to arrays in wasm memory that Rust can read, which allows us to reduce boilerplate in the codegen.

    Currently, we use TextEncoder.encode to encode strings into a Uint8Array, and then copy that into a view of wasm memory. We should be using TextEncoder.encodeInto to avoid this intermediate array.

    For slices, we use the Uint8Array constructor to convert an iterable of JS numeric objects into an array, and then copy that into wasm memory. We should look into if there are any alternatives like how strings haveencodeInto that would allow us to skip this intermediate array, and then use those if possible.

    opened by QnnOkabayashi 11
  • JS: Struct field getters for opaque types should handle their caching

    JS: Struct field getters for opaque types should handle their caching

    Currently when we return a struct containing opaques we generate a struct with a getter:

    https://github.com/rust-diplomat/diplomat/blob/517f1a4423fb8a88d5af9dcd1465efe8fb9987ec/example/js/api.mjs#L166-L171

    and then the method being generated immediately calls that getter and replaces it with the value:

    https://github.com/rust-diplomat/diplomat/blob/517f1a4423fb8a88d5af9dcd1465efe8fb9987ec/example/js/api.mjs#L99-L105

    We should probably not have this burden be on the method and instead handle this automagically in struct getter code.

    opened by Manishearth 6
  • Unexpected errors `An alias or submodule was found instead of a custom type`

    Unexpected errors `An alias or submodule was found instead of a custom type`

    I tried to run latest diplomat-tool on my FFI wrapper as well as the icu4x one, and got the following errors:

    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    An alias or submodule was found instead of a custom type with the name ICU4XError.
    thread 'main' panicked at 'explicit panic', tool/src/main.rs:98:9
    

    Apparently, some recent change (soon after the last pinned commit for icu4x) added some verification that is a bit too strict, probably this: https://github.com/rust-diplomat/diplomat/blob/main/core/src/ast/types.rs#L742 I'm not exactly sure of the intention behind it, but it probably needs to be relaxed or changed? This prevents usage of types from other modules (especially common for error types).

    opened by CBenoit 5
  • Make C headers self contained

    Make C headers self contained

    This is a prerequisite for making the C++ headers self contained

    You can see this in action at https://github.com/unicode-org/icu4x/pull/2823

    This is a breaking change for people using the C headers in a way where they relied on the exact import order to get additional types. That is considered bad practice and these are the C headers so I'm fine breaking it.

    I'll have to do something similar in C++ though, unsure if it's as kosher there.

    opened by Manishearth 4
  • Demo webpack app + CLI node app

    Demo webpack app + CLI node app

    This PR builds off of #208 by adding a basic webpack demo that bundles everything up and lets you use the demo ICU4X bindings in example/js/lib/ on a webpage. To use, navigate to example/js/app-webpack/, run npm install, and then npm run build to run the bundler. Then index.html can be viewed through the browser (I use LiveServer. Additionally, npm run clean removes all the auto generated files.

    Additionally, I changed example/js/app to instead offer a similar web interface to app-webpack, and can be set up in the same way, where the only difference is that it doesn't bundle everything together nicely. I also replaced the ava tests in app/ with a toy CLI tool that lets you format numbers. The ava tests are still in lib/.

    Finally, this fixes a few small bugs encountered along the way, like how DiplomatBuf finalization code was broken and untested (as also found in https://github.com/unicode-org/icu4x/pull/2216).

    opened by QnnOkabayashi 4
  • Move C++ namespacing around

    Move C++ namespacing around

    This is the baby fix for https://github.com/unicode-org/icu4x/issues/2182, where, at the very least, our capi namespacing is handled by the C headers instead of doing the very unidiomatic namespace capi { #include ... }. Ideally we can have all namespaces managed well, but for now this ought to suffice.

    opened by Manishearth 4
  • Add `Mutability` enum

    Add `Mutability` enum

    Currently, we use bool to indicate mutability, and we end up with things like

    match &param.ty {
        ast::TypeName::StrReference(/* mutable */ true) => { ... },
        // ...
    }
    

    This is bad because without the comment, it's not clear what true refers to. And the comment looks gross.

    This PR introduces the ast::Mutability enum type so that we can express intent through the type system. It's definition is very simple:

    pub enum Mutability {
        Mut,
        Const,
    }
    

    This makes examples like above much more readable:

    match &param.ty {
        ast::TypeName::StrReference(ast::Mutability::Mut) => { ... },
        // ...
    }
    
    opened by QnnOkabayashi 4
  • Multi-level borrows don't work

    Multi-level borrows don't work

    
    struct Foo<'a>(&'a str);
    struct Bar<'b, 'a>(&'b Foo<'a>);
    
    #[diplomat::opaque]
    struct ICU4XFoo<'a>(Foo<'a>);
    
    
    #[diplomat::opaque]
    struct ICU4XBar<'b, 'a>(Bar<'b, 'a>)
    
    impl<'a> ICU4XFoo<'a> {
       pub fn new(x: &str) -> Box<ICU4XFoo<'a>> {
           .....
       }
    
       pub fn get_bar<'b>(&'b self) -> Box<ICU4XBar<'b, 'a>> {
           ....
       }
    }
    

    The generated Rust code will fail to compile because get_bar generates a lifetimeless ICU4XFoo_get_bar() function. When there's a single lifetime in play this is fine, but this rapidly breaks down as there are multiple.

    This is probably something to fix as a part of https://github.com/rust-diplomat/diplomat/issues/12.

    opened by Manishearth 4
  • Ignore `use` tokens that are inside of `cfg(test)`

    Ignore `use` tokens that are inside of `cfg(test)`

    My tests are triggering the UseTree::Glob(_) => todo!("Glob imports are not yet supported {:?}", base_path), since I'm doing:

    #[cfg(test)]
    mod test {
        use super::*;
        ...
    }
    

    I put a print statement in Module::from_syn and the Item doesn't seem to have the context of where it is in the AST to filter them out. I'm not sure how generalized this kind of behavior could be, but at least at this point it would be nice to not analyze tests.

    extract_imports ItemUse {
        attrs: [],
        vis: Inherited,
        use_token: Use,
        leading_colon: None,
        tree: Path(
            UsePath {
                ident: Ident {
                    sym: super,
                    span: bytes(14966..14971),
                },
                colon2_token: Colon2,
                tree: Glob(
                    UseGlob {
                        star_token: Star,
                    },
                ),
            },
        ),
        semi_token: Semi,
    }
    
    bug 
    opened by gregtatum 4
  • Allow optional references to opaques

    Allow optional references to opaques

    We should be able to accept Option<&Opaque> arguments. In languages that support nullable values, the signature can be the same as the non-optional version.

    enhancement 
    opened by sffc 3
  • What is the best C++ type for optional references?

    What is the best C++ type for optional references?

    A few options on the table:

    1. std::optional<std::reference_wrapper<T>>
    2. T*
    3. A custom type

    It is easy to change this; we just need to finalize the decision.

    question 
    opened by sffc 5
  • Cpp2 Follow-ups

    Cpp2 Follow-ups

    • [ ] Refactor C2 to have two entrypoints and only one header field, removing the is_decl parameter of gen_ty_name: https://github.com/rust-diplomat/diplomat/pull/301#discussion_r1045086396
    • [ ] Support LibraryConfig: https://github.com/rust-diplomat/diplomat/pull/301#discussion_r1045087835
    • [ ] Have the CppContext first invoke C generation, and use a separate main.rs code path https://github.com/rust-diplomat/diplomat/pull/301#discussion_r1045088601
    • [ ] Support custom Writeable templates: https://github.com/rust-diplomat/diplomat/pull/301#discussion_r1045095068
    opened by sffc 0
  • HIR's `Slice` should be `SliceRef` or `BorrowedSlice`

    HIR's `Slice` should be `SliceRef` or `BorrowedSlice`

    "Slice" is the unsized datatype [T], which we don't support.

    In the future we want an OwnedSlice (a.k.a. Box<[T]>), so we should be clear about what type of slice this is.

    opened by robertbastian 1
  • Holistic source name system

    Holistic source name system

    Related: https://github.com/rust-diplomat/diplomat/issues/103

    In most places we just splat typ.name() etc into the source, which isn't always safe in the case of reserved keywords.

    In many cases this type will be used as a variable name, or something. Ideally the tool backends will have some kind of special formatter for types (etc) that displays them correctly with additional underscores/etc. In general, every place an AST identifier is printed, we should be using the backend-specific formatter instead.

    opened by Manishearth 1
  • [meta] Greatly improve the quality of the C++ output

    [meta] Greatly improve the quality of the C++ output

    The C++ output of Diplomat was primarily designed with an intention of getting it working. Now that we have it, we should try to make it good

    Some things that need to happen:

    • https://github.com/rust-diplomat/diplomat/issues/278
    • https://github.com/rust-diplomat/diplomat/issues/277
    • https://github.com/rust-diplomat/diplomat/issues/242
    • https://github.com/rust-diplomat/diplomat/issues/271
    • In general going through and fixing all warnings. We have a couple

    We could wati for the CPP2 backend, but I think these might be critical to good adoption, so we should try to do them early.

    We should have a C++ expert vet our final design before we release it.

    opened by Manishearth 1
Owner
null
ffizz is a library of utilities for exporting Rust libs for use in other languages

ffizz ffizz is a library of utilities for exporting Rust libs for use in other languages. FFI generally requires a lot of unsafe code, which in turn r

Dustin J. Mitchell 2 Aug 29, 2022
Simplified glue code generation for Deno FFI libraries written in Rust.

deno_bindgen This tool aims to simplify glue code generation for Deno FFI libraries written in Rust. Quickstart # install CLI deno install -Afq -n den

Divy Srivastava 173 Dec 17, 2022
Interface definitions for the Compute@Edge platform in witx.

?? compute-at-edge-abi This repository contains witx definitions for the Compute@Edge platform ABI. About witx The witx file format is an experimental

Fastly 14 Apr 5, 2022
AVR device definitions

avrd AVR device definitons in Rust. Documentation This crate exposes information about different AVR microcontrollers so it can be used pragmatically.

The AVR-Rust project 32 Dec 28, 2022
Membrane is an opinionated crate that generates a Dart package from a Rust library. Extremely fast performance with strict typing and zero copy returns over the FFI boundary via bincode.

Membrane is an opinionated crate that generates a Dart package from a Rust library. Extremely fast performance with strict typing and zero copy returns over the FFI boundary via bincode.

Jerel Unruh 70 Dec 13, 2022
A simple web-app allowing you to batch archive groups of repositories from a given organization

ice-repos My goal here is to build a simple web-app allowing you to batch archive groups of repositories from a given organization, using Rust+Yew. As

Nic McPhee 6 Nov 5, 2022
Rust Util Collection, a simple and friendly error-chain, with many useful utils as an addition.

RUC Rust Util Collection, a simple and friendly error-chain, with many useful utils as an addition. The painful experience of using error-chain gave b

漢 6 Mar 27, 2022
An example of a fairing for rocket to use tracing (as this pops up at many places in dicussions and questions)

Rocket Tracing Fairing Example This repository aims to give a short example of how you can add a Fairing to your Rocket for tracing and how to use it

Christof Weickhardt 9 Nov 23, 2022
A tool of generating and viewing dice roll success distributions.

AZDice A GUI tool for generating and visualising dice roll probability distributions. Aims Intended to help people trying to get game balance just rig

null 13 Mar 2, 2021
Modeling is a tools to analysis different languages by Ctags

Modeling Modeling is a tools to analysis different languages by Ctags process: generate to opt call ctags with opt analysis ctags logs output resulse

Inherd OS Team (硬核开源小组) 13 Sep 13, 2022
Generating Permutations with Rust

rust_permutations Generating Permutations with Rust Permutation Input: a string of unknown length that can contain only three characters: 0, 1, or . F

Flavio Rasseli 1 Oct 25, 2021
tiny_id is a Rust library for generating non-sequential, tightly-packed short IDs.

tiny_id tiny_id is a Rust library for generating non-sequential, tightly-packed short IDs. Most other short ID generators just string together random

Paul Butler 33 Aug 6, 2022
Ever wanted to torture your CPU by generating every image possible?

dumpsterfire Ever wanted to torture your CPU by generating every image possible? Well, now you can! This thing is worse than mining Bitcoin, since the

null 2 Jun 14, 2022
A mostly drop-in replacement for mercantile written w/ rust, plus several other util(e)ities.

utiles utiles = utils + tiles A mostly drop-in replacement for mercantile written w/ rust, plus several other util(e)ities. Installation pip install u

jesse 5 Jun 20, 2023
A service for helping your cat find other cats

Check back later! Discord Self-hosting This is an open-source service! Feel free to host you own private instances. All we ask is you credit us and li

ibx34 4 Oct 31, 2021
Experimental syntax for Rust

Osy.rs Experimental syntax for Rust Hey everyone, this readme needs work! The spec has been roughed out in Osy.rs_spec.alpha, but the file could be be

null 3 Dec 17, 2021
An experimental Rust crate for sigstore

Continuous integration Docs License This is an experimental crate to interact with sigstore. This is under high development, many features and checks

sigstore 89 Dec 29, 2022
Experimental playground for wiktionary data

wikt Experimental playground for wiktionary data. This document might not update as often as the code does. Set up You'll want a minimum of 10 GB free

Félix Saparelli 8 Jul 9, 2022
An experimental programming language for exploring first class iterators.

An experimental programming language for exploring first class iterators.

Miccah 4 Nov 23, 2021