An open API service indexing awesome lists of open source software.

https://github.com/thelartians/glue

⛓️ Bindings that stick. A simple and generic API for C++ to other language bindings supporting bidirectional communication, inheritance and automatic declarations.
https://github.com/thelartians/glue

automatic bindings cpp declarations glue inheritance language-bindings multi-language scripting-language typescript

Last synced: 2 months ago
JSON representation

⛓️ Bindings that stick. A simple and generic API for C++ to other language bindings supporting bidirectional communication, inheritance and automatic declarations.

Awesome Lists containing this project

README

          

[![Actions Status](https://github.com/TheLartians/Glue/workflows/MacOS/badge.svg)](https://github.com/TheLartians/Glue/actions)
[![Actions Status](https://github.com/TheLartians/Glue/workflows/Windows/badge.svg)](https://github.com/TheLartians/Glue/actions)
[![Actions Status](https://github.com/TheLartians/Glue/workflows/Ubuntu/badge.svg)](https://github.com/TheLartians/Glue/actions)
[![Actions Status](https://github.com/TheLartians/Glue/workflows/Style/badge.svg)](https://github.com/TheLartians/Glue/actions)
[![Actions Status](https://github.com/TheLartians/Glue/workflows/Install/badge.svg)](https://github.com/TheLartians/Glue/actions)
[![codecov](https://codecov.io/gh/TheLartians/Glue/branch/master/graph/badge.svg)](https://codecov.io/gh/TheLartians/Glue)

# Glue

A common interface for C++ to other language bindings.

## Motivation

C++ is a great language for writing algorithms and high-performance code.
However, once it comes to building applications, servers or websites, simple things become complex and we settle for a scripting language to glue C++ components together.
The bindings usually need to be hand-crafted for every exposed type and language.
This project aims to create a generic language binding interface in pure standard C++, which allows two-way interactions, automatic declaration creation and relatively short compile times.

## API

### Maps and values

Glue is based on the [Revisited framework](https://github.com/thelartians/Revisited) and provides convenient wrapper methods.
The most important types for creating the API and are `glue::Value` and `glue::MapValue`.

```cpp
#include
#include

void valueExample() {
// `glue::Value`s hold an `revisited::Any` type that can store any type of value
glue::Value value = "Hello glue!";

// access the any type through the `->` or `*` operator
// `as()` returns an `std::optional` that is defined if the cast is possible
std::cout << *value->as() << std::endl;

// `glue::MapValue` is a wrapper for a container that maps strings to values
// `glue::createAnyMap()` creates a map based on `std::unordered_set`
// Values also accept lambda functions
glue::MapValue map = glue::createAnyMap();
map["myNumber"] = 42;
map["myString"] = value;
map["myCallback"] = [](bool a, float b){ return a ? b : -b; };
map["myMap"] = glue::createAnyMap();

// use helper functions to cast to maps or callbacks.
// the result will evaluate to `false` if no cast is possible.
if (auto f = map["myCallback"].asFunction()) {
// callbacks are stored as a `revisited::AnyFunction` and can accept both values or `Any` arguments
// (here `map["myNumber"]` is casted to an `Any` through the `*` operator)
// `get` returns casts the value to `T` or throws an exception if not possible
std::cout << f(false, *map["myNumber"]).get() << std::endl;
}

// inner maps are also `glue::MapValue`s.
map["myMap"].asMap()["inner"] = "inner value";
}
```

### Classes

Glue also has built-in support for maps representing classes and inheritance.

```cpp
#include
#include
#include

struct A {
std::string member;
};

struct B: public A {
B(std::string value) : A{value} {}
int method(int v) { return int(member.size()) + v; }
};

void classExample() {
auto map = glue::createAnyMap();

// `glue::createClass` is a convience function for declaring maps for class APIs
// `addConstructor()` adds a function that constructs `A` given the argument types `Args...`
// `.addMember("name", &T::member)` adds a setter (`member`) and getter (`setMember`) function
map["A"] = glue::createClass()
.addConstructor<>()
.addMember("member", &A::member)
;

// classes can be made inheritance aware
// `setExtends(map)` uses the argument map or callback to retrieve undefined keys
// `glue::WithBases
()` adds implicit conversions to the listed base classes
// `addMethod("name", &T::method)` adds a method that calls a member function or lambda
map["B"] = glue::createClass(glue::WithBases
())
.setExtends(map["A"])
.addConstructor()
.addMethod("method", &B::method)
.addMethod("lambda", [](const B &b, int x){ return b.member.size() + x; })
;

// contexts collect map class data and can be used to test instance creation
glue::Context context;
context.addRootMap(map);

// `glue::Instance` captures a value and behaves as a class instance
auto b = context.createInstance(map["B"][glue::keys::constructorKey]("arg"));

// calls will be treated as member functions
std::cout << b["member"]().get() << std::endl;
b["setMember"]("new value");
std::cout << b["lambda"](10).get() << std::endl;
}
```

### Declarations

Glue can automatically generate declarations for type-safe scripting using TypeScript or [TypeScriptToLua](https://typescripttolua.github.io).

```cpp
glue::DeclarationPrinter printer;
printer.init();
printer.print(std::cout, map, &context);
```

In the example above, this would result in the following declarations.

```ts
/** @customConstructor A.__new */
declare class A {
constructor()
member(): string
setMember(arg1: string): void
}
/** @customConstructor B.__new */
declare class B extends A {
constructor(arg0: string)
lambda(arg1: number): number
method(arg1: number): number
}
```

## Supported bindings

Here you can find current and planned bindings for Glue.

- [x] Lua: [LuaGlue](https://github.com/TheLartians/LuaGlue)
- [x] JavaScript (Wasm): [EmGlue](https://github.com/TheLartians/EmGlue)
- [ ] JavaScript (Duktape)
- [ ] Python
- [ ] Java
- [ ] Swift
- [ ] Rust

As you can see, many bindings are still missing from the list.
If you've created Glue bindings for any language, feel free to open a PR to add them here.

## Limitations

- No support for pointer or optional arguments in callbacks (yet)
- Class bindings aren't as sophisticated as other libraries bindings such as [sol2](https://github.com/ThePhD/sol2)
- There is a small overhead through the additional abstraction layer compared to native bindings

## Usage

Glue can be easily added to your project using [CPM.cmake](https://github.com/TheLartians/CPM.cmake).

```cmake
CPMAddPackage(
NAME Glue
VERSION 1.0
GIT_REPOSITORY https://github.com/TheLartians/Glue.git
)

target_link_libraries(myLibrary Glue)
```

See [here](https://github.com/TheLartians/TypeScriptXX) for an example project using Glue to create TypeScript bindings for C++.