Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

5 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

FlowBridge

FlowBridge is a cross-language bridge for signals and slots between C++, Objective-C, and Swift. Type-safe events in C++ and convenient hooks in Swift.


✨ Features

  • Type-safe signals in C++
  • Automatic bridging to Swift / Objective-C
  • Pass values (string, number, bool, binary data) between layers
  • No boilerplate callbacks β€” event-driven design

πŸ“¦ Installation

Add FlowBridge as a Swift Package dependency:

dependencies: [
    .package(url: "https://github.com/danrom11/FlowBridge.git", from: "2.1.0")
]

πŸ”§ Usage

FlowBridge revolves around signals (events you define in C++) and slots (handlers you connect in Swift/Objective-C).

1. Define a signal in C++

Use the FLOW_SIGNAL macro to declare a named signal:

#include "FlowBridge.hpp"

FLOW_SIGNAL(tick_score);

ℹ️ You don’t strictly need to register a signal β€” emitting will create it automatically. But calling FlowBridge::registerSignal(tick_score) is recommended for clearer architecture and to document the intent.

2. Emit from C++

Emit an event whenever you want:

FlowBridge::emit(tick_score, "Hello from C++");

You can pass strings, numbers, booleans, or even binary data

3. Connect in Swift

In Swift, subscribe by name and handle the payload:

import FlowBridge

struct FlowSignals {
  static let tick_score = "tick_score"
}

FlowBridge.connect(FlowSignals.tick_score) { data in
  if let text = data as? String {
    print("Received:", text)
  }
}

Or you can use a selector:

import FlowBridge

struct FlowSignals {
  static let tick_score = "tick_score"
}

    
@objc func test(_ data: Any?) {
  print("Data: \(data ?? "none")")
        
  if let stringData = data as? String {
    DispatchQueue.main.async {
      self.nameLabel.text = stringData
    }
  }
}

override func viewDidLoad() {
  super.viewDidLoad()
  nameLabel.text = "0"
        
  FlowBridge.connect(FlowSignals.tick_score, target: self, slot: #selector(test(_:)))
        
  let manager = ManagerWrapper.shared
  manager().start(withInterval: 1000)
}

πŸ“¦ Passing Complex Structures with TLV

Starting from version 2.1.0, FlowBridge supports automatic serialization/deserialization of complex data types (dictionaries, arrays, nested structures) using TLV (Type-Length-Value).

Example: Sending a Document from C++ to Swift

C++ side:

#include "FlowBridge.hpp"
#include "tlv.hpp"

// Create a document structure
tlv::Map document{
    {"user_id", int64_t(42)},
    {"name", std::string("Alice")},
    {"role", std::string("developer")},
    {"skills", tlv::Array{
        std::string("C++"),
        std::string("Swift"),
        std::string("Objective-C")
    }},
    {"active", true},
    {"rating", 4.8}
};

// Emit signal with TLV-encoded data
FlowBridge::emit("user_profile", tlv::encode(tlv::Value(document)));

Swift side:

import FlowBridge

FlowBridge.connect("user_profile") { data in
    // Receive automatically decoded dictionary
    if let profile = data as? [String: Any] {
        let userId = profile["user_id"] as? Int ?? 0
        let name = profile["name"] as? String ?? ""
        let role = profile["role"] as? String ?? ""
        let skills = profile["skills"] as? [String] ?? []
        let active = profile["active"] as? Bool ?? false
        let rating = profile["rating"] as? Double ?? 0.0
        
        print("User: \(name) (ID: \(userId))")
        print("Role: \(role)")
        print("Skills: \(skills.joined(separator: ", "))")
        print("Active: \(active), Rating: \(rating)")
    }
}

Example: Sending Data from Swift to C++

Swift side:

import FlowBridge

// Send a request with parameters
FlowBridge.emit("api_request", data: [
    "endpoint": "/users",
    "method": "GET",
    "params": [
        "page": 1,
        "limit": 20,
        "sort": "name"
    ],
    "headers": [
        "Authorization": "Bearer token123",
        "Accept": "application/json"
    ]
])

C++ side:

#include "FlowBridge.hpp"
#include "tlv.hpp"

// Connect to signal with TLV handling
static FlowBridge::Connection connection = 
    FlowBridge::connect<std::vector<uint8_t>>("api_request",
    [](const std::vector<uint8_t>& buffer) {
        try {
            tlv::Value value = tlv::decode(buffer);
            
            // Check if we received a dictionary
            if (auto request = std::get_if<tlv::Map>(&value)) {
                
                // Extract endpoint
                auto endpoint_it = request->find("endpoint");
                if (endpoint_it != request->end()) {
                    if (auto endpoint = std::get_if<std::string>(&endpoint_it->second)) {
                        std::cout << "Endpoint: " << *endpoint << std::endl;
                    }
                }
                
                // Extract parameters
                auto params_it = request->find("params");
                if (params_it != request->end()) {
                    if (auto params = std::get_if<tlv::Map>(&params_it->second)) {
                        auto page_it = params->find("page");
                        if (page_it != params->end()) {
                            if (auto page = std::get_if<int64_t>(&page_it->second)) {
                                std::cout << "Page: " << *page << std::endl;
                            }
                        }
                    }
                }
            }
        } catch (const std::exception& e) {
            std::cerr << "Failed to decode TLV: " << e.what() << std::endl;
        }
    });

Supported Types

Swift type C++ type TLV representation
nil nullptr null
Bool bool boolean
Int int64_t integer
Double double float
String std::string string
Data std::vector<uint8_t> binary
Array tlv::Array array
Dictionary tlv::Map map

TLV Advantages

  • Type safety β€” data preserves its types during transmission
  • Arbitrary nesting β€” dictionaries can contain arrays that contain other dictionaries
  • Automatic deserialization β€” data arrives in Swift ready to use
  • Efficiency β€” compact binary representation

πŸ“‚ Examples

A full demo project is available in https://github.com/danrom11/FlowBridge-Examples

About

FlowBridge is a cross-language bridge for signals and slots between C++, Objective-C, and Swift. Type-safe events in C++ and convenient hooks in Swift.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages