1. Zig is an an emergent general-purpose programming language. Being "a better C", Zig is an order of magnitude simpler than Rust. You can understand Zig code almost immediately if you can read C. It makes Zig a good candidate to implement FFI extensions for Ruby.

    Let's write a tiny little Zig library and call it via FFI from Ruby.

    A Zig function with parameters passed "by value" is too simple for our example. To complicate the matter a bit, we will implement a function with "out" parameters to return a collection of structs from Zig to Ruby. In order to simplify domain, let our function to return a collection of random X:Y points. Our build.zig might look like:

    const std = @import("std");
    
    pub fn build(b: *std.build.Builder) void {
        const lib = b.addSharedLibrary("points", "src/main.zig", .unversioned);
        lib.linkLibC();
        lib.setBuildMode(.ReleaseSafe);
        lib.install();
    }
    

    Since library versioning doesn't directly relate to the topic, we leave the lib unversioned. Please also note that we link LibC. It allows us to use std.heap.c_allocator to allocate memory for points.

    A function to generate a collection of points has signature export fn generatePoints(addr_ptr: *usize, len_ptr: *u8) bool. There is no mechanism to simply return a collection as a function return value. Thus we need two "out" function parameters:

    • an address of the collection (addr_ptr)
    • collection length (len_ptr)
    Let's attach the function to a Ruby module:

    class Point < FFI::Struct
      layout :x, :uchar,
             :y, :uchar
    end
    
    module PointsLib
      extend FFI::Library
    
      ffi_lib "zig-out/lib/libpoints.so"
    
      attach_function :generatePoints, [ULongPtr, UCharPtr], :bool
    

    ULongPtr and UCharPtr is a couple of auxiliary classes we introduce nearby.

    class ULongPtr < FFI::Struct
      layout :value, :ulong
    end
    
    class UCharPtr < FFI::Struct
      layout :value, :char
    end
    

    They allow us to handle the "out" parameters more elegantly. Just note that, attaching and using the function, we don't directly mention Point.

    addr_ptr = ULongPtr.new
    len_ptr  = UCharPtr.new
    
    PointsLib.generatePoints(addr_ptr, len_ptr) or raise("Error in Zig")
    
    addr, len  = addr_ptr[:value], len_ptr[:value]
    

    It is time to write Zig code.

    const Point = extern struct {
        x: i8,
        y: i8,
    };
    
    export fn generatePoints(addr_ptr: *usize, len_ptr: *u8) bool {
        var rnd = std.rand.DefaultPrng.init(std.crypto.random.int(u64)).random();
        var len = rnd.int(u8);                                                    // 1
        var points = std.heap.c_allocator.alloc(Point, len) catch return false;   // 2
        var i: u8 = 0;
        while (i < len) : (i += 1) {
            points[i].x = rnd.int(i8);                                            // 3
            points[i].y = rnd.int(i8);
        }
    
        addr_ptr.* = @ptrToInt(points.ptr);                                       // 4             
        len_ptr.* = len;             
    
        return true;
    }
    

    As you can see, we

    1. randomly generate length of the collection
    2. allocate memory for a slice of Points
    3. iterate over the slice and randomly assign coordinates
    4. set a memory address of the collection and collection length as "out" params values

    Returning to Ruby. We use FFI::Pointer to access the passed collection.

    addr, len  = addr_ptr[:value], len_ptr[:value]
    points_ptr = FFI::Pointer.new(Point.size, addr)
    

    Having a pointer to the collection, we can get points:

    first_point  = Point.new(points_ptr[0])
    second_point = Point.new(points_ptr[1])
    x, y         = first_point[:x], first_point[:y]
    

    The only missing piece is freeing the memory passed to Ruby from Zig. It is a separate Zig function. On Ruby side it looks like:

    attach_function :freePoints, [:ulong, :uchar], :void
    

    and

    PointsLib.freePoints addr, len
    

    On Zig side it is just:

    export fn freePoints(points_ptr: [*]Point, len: u8) void {
        std.heap.c_allocator.free(points_ptr[0..len]);
    }
    

    A completed Ruby method which returns an array of [x, y] arrays is written as:

      def self.coordinates
        addr_ptr = ULongPtr.new
        len_ptr  = UCharPtr.new
    
        PointsLib.generatePoints(addr_ptr, len_ptr) or raise("Error in Zig")
    
        addr, len  = addr_ptr[:value], len_ptr[:value]
        points_ptr = FFI::Pointer.new(Point.size, addr)
    
        coords = (0...len).map do |i|
          point = Point.new(points_ptr[i])
          [point[:x], point[:y]]
        end
    
        PointsLib.freePoints addr, len
    
        coords
      end
    

    That is pretty much it. There are probably many other ways to implement the same functionality. You can play with FFI::ManagedStruct to get rid of an explicit PointsLib.freePoints call. Or you can allocate memory on Ruby side and pass it to Zig to fill up with random points. In this post, we will limit ourselves to only one approach.

    As a recap. We generated a random number of structures on Zig side, returned and used them on Ruby side and freed allocated memory in the end.

    Source code is available on Github.

    0

    Add a comment

  2. 2021 has more distinctly manifested those tectonic shifts in the world that began in in 2020. I look into the future with a mixture of curiosity and feeling of danger. But my blog is not about such global things.

    Language for pet projects
    Ruby (RoR + Hotwire)
    Crystal, PureScript, Rust and Zig.

    Tutorial
    Jordan's Reference for PureScript

    Functional programming
    Monad transformer

    Library
    Hotwire
    ViewComponent

    IT book
    Data-Oriented Programming by Yehonathan Sharvit

    False start
    Yew (a small WASM app crashes unpredictable in runtime)

    Historical video
    На этот раз окончательный закат Западной цивилизации Юрий Слёзкин

    Thinker
    Павел Щелин

    Museum
    Museo del Prado
    Palau Nacional de Montjuïc

    0

    Add a comment

  3.                                                                                                     The 21st century has finally begun.


    Phrase

    Me: There is no history. Only historiography.

    Memoirs

    Окаянные дни Ивана Бунина.

    Historical video

    Присоединение Сибири: механизмы и логистика Михаила Кречмара.

    Что за татаро-монголы в русских былинах? Александра Пыжикова.

    Tool

    Wikipedia as a tool for the systematic study of history.

    Entertaining video

    Warhammer 40,000 fan film project.

    Music

    Les Indes galantes

    Intrigue

    Otto Celera 500L

    Surprise

    A seven-year-old watches sitcoms ("The IT Crowd", “The Big Bang Theory”, “How I Met Your Mother”, etc).

    Family

    My daughter has successfully passed admission tests to one of the very best state schools in the country.

    0

    Add a comment


  4. IT book
    Designing Data-Intensive Applications by Martin Kleppmann
    A Philosophy of Software Design by John Ousterhout is the opposite of Kleppmann's book. Much shorter. Much more provocative.

    IT blog post
    Startup strategy is like Kung Fu

    Intrigue
    Flutter UI toolkit
    Phoenix’s LiveView approach adoption in Rails community.
    WebAssembly.

    Library
    Stimulus (especially in conjunction with Turbolinks)

    Tool
    Android Studio

    False start
    Vue.js

    Parallel reality
    Product automation software

    Podcast episode
    Обучение программистов бесплатно за два часа без смс

    Movie
    The Great Beauty

    TV Series
    Breaking Bad (season 1)
    Unbelievable
    Chernobyl (miniseries)

    Content
    Youtube as a social phenomenon.

    Existential
    Intractable question: "If you could invite any five people (living or dead) to a dinner party, who would you invite?"
    ʻOumuamua

    Radio show
    Донское побоище с Олегом Двуреченским

    Blog post
    Манускрипты. Артефакты. Культуры

    Historian

    Mark Solonin

    Historic site
    Doge's Palace
    Hampton Court Palace

    Museum
    Pinacoteca di Brera
    Museu Nacional de Arte Antiga
    Pinacoteca Nazionale di Bologna

    0

    Add a comment

  5. Service Mesh Wars with William Morgan

    Python's new governance and core team


    0

    Add a comment

  6. Facebook Strategy with Mike Vernal

    Monolithic Repositories with Ciera Jaspan


    0

    Add a comment

  7. Sage Advice (and Reasons You Probably Won't Follow It) from Jason Cohen of WP Engine


    SE-Radio Episode 362: Simon Riggs on Advanced Features of PostgreSQL

    Wasmer is taking WebAssembly beyond the browser

    024 - Kent Beck, Author of Test-Driven Development: By Example



    0

    Add a comment

  8. SE-Radio Episode 360: Pete Koomen on A/B Testing

    https://www.se-radio.net/2019/03/se-radio-episode-360-pete-koomen-on-a-b-testing/

    FaunaDB with Evan Weaver



    0

    Add a comment

  9. Grady Booch on Today’s Artificial Intelligence Reality and What it Means for Developers

    A UI framework without the framework

    RocksDB with Dhruba Borthakur and Igor Canadi


    SDCast #97: в гостях Александр Тоболь, руководитель разработки платформ видео и лента в ОК


    0

    Add a comment

  10. Interesting podcasts I found this January. I will do monthly posts on this topic.

    Taking on Google and Facebook as a Solo Open-Source Founder with Evan You of Vue.js


    Software as a Reflection of Values With Bryan Cantrill


    Anchor: Podcast Platform with Nir Zicherman



    Обучение программистов бесплатно за два часа без смс — Episode 0226




    0

    Add a comment

Author
Popular Posts
Popular Posts
  • Zig is an an emergent general-purpose programming language. Being "a better C", Zig is an order of magnitude simpler than Rust...
  • IT book Category Theory for Programmers by Bartosz Milewski I still read the book. Will see how it goes. The first third, I've re...
  • IT book Compilers: Principles, Techniques, and Tools by Alfred V. Aho, Monica S. Lam, Ravi Sethi, and Jeffrey D. Ullman Finally I found a...
Labels
Blog Archive
Loading