From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: taylanbayirli@gmail.com (Taylan Ulrich =?utf-8?Q?Bay=C4=B1rl=C4=B1?= =?utf-8?Q?=2FKammer?=) Newsgroups: gmane.lisp.guile.user Subject: Bytestructures, FFI Date: Tue, 31 May 2016 22:29:58 +0300 Message-ID: <87oa7mauvd.fsf@T420.taylan> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: ger.gmane.org 1464723012 17086 80.91.229.3 (31 May 2016 19:30:12 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Tue, 31 May 2016 19:30:12 +0000 (UTC) To: guile-user@gnu.org Original-X-From: guile-user-bounces+guile-user=m.gmane.org@gnu.org Tue May 31 21:30:06 2016 Return-path: Envelope-to: guile-user@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1b7pMZ-0005L1-CL for guile-user@m.gmane.org; Tue, 31 May 2016 21:30:04 +0200 Original-Received: from localhost ([::1]:38083 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b7pMX-00038R-T7 for guile-user@m.gmane.org; Tue, 31 May 2016 15:30:01 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:58626) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b7pMA-000388-8p for guile-user@gnu.org; Tue, 31 May 2016 15:29:39 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1b7pM4-0005fm-7N for guile-user@gnu.org; Tue, 31 May 2016 15:29:37 -0400 Original-Received: from mail-wm0-x232.google.com ([2a00:1450:400c:c09::232]:34835) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b7pM3-0005fg-TB for guile-user@gnu.org; Tue, 31 May 2016 15:29:32 -0400 Original-Received: by mail-wm0-x232.google.com with SMTP id a136so148698050wme.0 for ; Tue, 31 May 2016 12:29:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:subject:date:message-id:user-agent:mime-version; bh=wmnjZ9BFuUtlHSqX/6SK8nAQ7vLtL5uRNoFcwwq6GH8=; b=KCI4qcqAcm/GQ7klR7h4nwW1CtfKyoXRqr2VZlj8ZF9Yv1CA4HRL7/onAuOM3GvEx1 mYVMKD7a08pUDoRHM0T4kJKeG+VLqaC+tCPL57bj7bBgEVLqbPOMYle58QYTzGxS7q9A cPlcyoE/4Qmm+B/Kafc4Y2a3j6Di+xEUQqg+ogRICfg6qNCzDnrJjuPCip+jul3CmyRP jKjDIEwE+3ptRKY7INPGJMvcis3Gc0j5dqSuwrbjlX6p+Ch+nRVG4fWComIKHbHYRXuu URlM5rIPYI7OHVyKS+goW5hyZ+XBtULZ13CDFj5JuO+dPi9EsAFWbFsfx4tCIgg162yF Wamw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id:user-agent :mime-version; bh=wmnjZ9BFuUtlHSqX/6SK8nAQ7vLtL5uRNoFcwwq6GH8=; b=cNPH8a6jZjUhnim9Hlm419hVC0/AGAz/3JwTEseN/tShlE53XGgQtnbqIzSYZtRgoV 6RKNsVfKkp5Zwj/SK1Sdxz0TlQBRwwfUqAVAmf5Mot2UqcG+Iq0hR36MOlwbUgYi12Ia yoZpPT2iiFlqrRFDSS4ka7A7i8lAK+FBO5jeA0U9M3CM2bQUw2134CayGhHT7AmbYQmD udduHFliEfDw5DB5M69f/R3JV3ySaku0czmYZ1TziSrWs/NQk3r0FoerMJafcZ0zg6u1 /A7gbWYnjTyno8yRe0gfARlaIraIvo+KoWh2F2exq578of8zPJj0Fzdqnrc4uFOL3F/7 DqNA== X-Gm-Message-State: ALyK8tLL5AhpHw+3ydm7SiUxg0X1AYDpQTZiU3Ib3gcyFsKjRK8gqvFw/nTfyvYw/4070w== X-Received: by 10.194.157.36 with SMTP id wj4mr33393445wjb.139.1464722970275; Tue, 31 May 2016 12:29:30 -0700 (PDT) Original-Received: from T420.taylan ([88.243.89.56]) by smtp.gmail.com with ESMTPSA id y3sm41500338wji.40.2016.05.31.12.29.29 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 31 May 2016 12:29:29 -0700 (PDT) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a00:1450:400c:c09::232 X-BeenThere: guile-user@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: General Guile related discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guile-user-bounces+guile-user=m.gmane.org@gnu.org Original-Sender: "guile-user" Xref: news.gmane.org gmane.lisp.guile.user:12586 Archived-At: Hi there, I had announced this project a while ago, here: https://lists.gnu.org/archive/html/guile-user/2015-08/msg00034.html I just added support for converting a bytestructure descriptor into a type descriptor as per Guile's FFI module. E.g. the uint8 descriptor in (bytestructures guile numeric) converts to the value of the uint8 variable in the (system foreign) module, and a struct descriptor such as (bs:struct `((x ,uint8) (y ,uint16))) converts to what one would get from evaluating (list uint8 uint16) after importing (system foreign). (Such lists are accepted by Guile's FFI to denote structs; it's yet undocumented in the manual.) For convenience, a bs:pointer->proc procedure is offered, that wraps pointer->procedure and adds bytestructure related functionality. Here's a minimal example of how to use it: --- start transcript --- taylan@T420:~/src/scheme/bytestructures$ cat test.c typedef struct { struct { int x; float y; } s; int z; float t[3]; } foo_t; foo_t testfunc(foo_t arg) { ++arg.s.x; ++arg.s.y; ++arg.z; ++arg.t[0]; ++arg.t[1]; ++arg.t[2]; return arg; } taylan@T420:~/src/scheme/bytestructures$ gcc -shared -o libtest.so test.c taylan@T420:~/src/scheme/bytestructures$ sudo mv libtest.so /usr/lib/ taylan@T420:~/src/scheme/bytestructures$ guile GNU Guile 2.0.11 Copyright (C) 1995-2014 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. scheme@(guile-user)> (import (bytestructures guile)) scheme@(guile-user)> (import (bytestructures guile ffi)) scheme@(guile-user)> (define foo_t (bs:struct `((s ,(bs:struct `((x ,int) (y ,float32)))) (z ,int) (t ,(bs:vector 3 float32))))) scheme@(guile-user)> (define foo (bytestructure foo_t '((s ((x 1) (y 2.2))) (z 3) (t #(0 1 2))))) scheme@(guile-user)> (bytestructure-ref foo 's 'x) $1 = 1 scheme@(guile-user)> (bytestructure-ref foo 't 1) $2 = 1.0 scheme@(guile-user)> (define testfunc (bs:pointer->proc foo_t ;return value type (dynamic-func "testfunc" (dynamic-link "libtest")) (list foo_t))) ;list of argument types scheme@(guile-user)> (define foo2 (testfunc foo)) scheme@(guile-user)> (bytestructure-ref foo2 's 'x) $3 = 2 scheme@(guile-user)> (bytestructure-ref foo2 't 1) $4 = 2.0 scheme@(guile-user)> --- end transcript --- To recap: We have a C file which defines a struct, and a function that takes such a struct and returns a new one with some of the fields' values modified. We make this a shared library. In Guile, we can express the same struct layout via a bytestructure descriptor object, which we put in the variable foo_t. We can also instantiate such a struct in memory, reified in Scheme as a bytestructure object, which we put into the variable foo. We use bs:pointer->proc to create a Scheme procedure that wraps the function in our shared library; bs:pointer->proc allows us to use the foo_t descriptor in the return value and argument list declarations. We can now call this procedure with the struct we had created from Scheme and put in the variable foo as a bytestructure object. The new struct returned by the C function is automatically turned into a bytestructure object that can be used from Scheme with the bytestructures API. Neat, isn't it? If test.c instead contained: void testfunc(foo_t *arg) { ++arg->s.x; ++arg->s.y; ++arg->z; ++arg->t[0]; ++arg->t[1]; ++arg->t[2]; } (i.e. testfunc now takes a struct pointer and modifies it in-place) then we could create our procedure like: scheme@(guile-user)> (import (prefix (system foreign) ffi:)) scheme@(guile-user)> (define testfunc (bs:pointer->proc ffi:void (dynamic-func "testfunc" (dynamic-link "libtest")) (list '*))) and things would work like this: scheme@(guile-user)> (testfunc foo) scheme@(guile-user)> (bytestructure-ref foo 's 'x) $3 = 2 scheme@(guile-user)> (bytestructure-ref foo 't 1) $4 = 2.0 Magic! Note that while bytestructures supports unions and bit-fields, libffi and therefore (system foreign) does not, so the above won't work yet for types in which unions or bitfields are involved. Unions can possibly be supported with a little hack, which I'll look into later. I have not yet made the semantics of bs:pointer->proc concrete, and it's yet undocumented. Feel free to ask me questions here or on Freenode under the nick 'taylan'. Comments are welcome too! Taylan