From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: ludo@gnu.org (Ludovic =?utf-8?Q?Court=C3=A8s?=) Newsgroups: gmane.lisp.guile.user Subject: Re: Bytestructures, FFI Date: Wed, 01 Jun 2016 23:40:13 +0200 Message-ID: <87eg8gegg2.fsf@gnu.org> References: <87oa7mauvd.fsf@T420.taylan> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Trace: ger.gmane.org 1464817274 4621 80.91.229.3 (1 Jun 2016 21:41:14 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Wed, 1 Jun 2016 21:41:14 +0000 (UTC) To: guile-user@gnu.org Original-X-From: guile-user-bounces+guile-user=m.gmane.org@gnu.org Wed Jun 01 23:41:08 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 1b8Dsx-0001P8-Pf for guile-user@m.gmane.org; Wed, 01 Jun 2016 23:41:08 +0200 Original-Received: from localhost ([::1]:44264 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b8Dst-0004Wj-Fn for guile-user@m.gmane.org; Wed, 01 Jun 2016 17:41:03 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:44659) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b8DsN-0004Uj-Fw for guile-user@gnu.org; Wed, 01 Jun 2016 17:40:32 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1b8DsJ-0005CX-AM for guile-user@gnu.org; Wed, 01 Jun 2016 17:40:31 -0400 Original-Received: from plane.gmane.org ([80.91.229.3]:33530) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b8DsI-0005BQ-Sp for guile-user@gnu.org; Wed, 01 Jun 2016 17:40:27 -0400 Original-Received: from list by plane.gmane.org with local (Exim 4.69) (envelope-from ) id 1b8DsF-0000vr-56 for guile-user@gnu.org; Wed, 01 Jun 2016 23:40:23 +0200 Original-Received: from reverse-83.fdn.fr ([80.67.176.83]) by main.gmane.org with esmtp (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Wed, 01 Jun 2016 23:40:23 +0200 Original-Received: from ludo by reverse-83.fdn.fr with local (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Wed, 01 Jun 2016 23:40:23 +0200 X-Injected-Via-Gmane: http://gmane.org/ Original-Lines: 119 Original-X-Complaints-To: usenet@ger.gmane.org X-Gmane-NNTP-Posting-Host: reverse-83.fdn.fr X-URL: http://www.fdn.fr/~lcourtes/ X-Revolutionary-Date: 14 Prairial an 224 de la =?utf-8?Q?R=C3=A9volution?= X-PGP-Key-ID: 0x090B11993D9AEBB5 X-PGP-Key: http://www.fdn.fr/~lcourtes/ludovic.asc X-PGP-Fingerprint: 3CE4 6455 8A84 FDC6 9DB4 0CFB 090B 1199 3D9A EBB5 X-OS: x86_64-unknown-linux-gnu User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux) Cancel-Lock: sha1:KLlcAizRbesE/9sbqYpRdSaoBNk= X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 80.91.229.3 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:12590 Archived-At: Hi! taylanbayirli@gmail.com (Taylan Ulrich "Bayırlı/Kammer") skribis: > 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))))) Gradually, without thinking much about it ;-), I ended up writing something along these lines in (guix build syscalls), but with slightly different goals. Initially, that was because I was unsatisfied with ‘make-c-struct’ and ‘parse-c-struct’, notably the fact that they insisted on creating lists and computing offsets etc. at run time. The ‘define-c-struct’ macro in that module defines a variable containing the size in bytes of the structure, a procedure to write an instance of that structure to a bytevector, and one to read from a bytevector. Example: --8<---------------cut here---------------start------------->8--- (define-c-struct sockaddr-in ; sizeof-sockaddrin (lambda (family port address) (make-socket-address family address port)) read-sockaddr-in write-sockaddr-in! (family unsigned-short) (port (int16 ~ big)) (address (int32 ~ big))) ;; … (define (write-socket-address! sockaddr bv index) "Write SOCKADDR, a socket address as returned by 'make-socket-address', to bytevector BV at INDEX." (let ((family (sockaddr:fam sockaddr))) (cond ((= family AF_INET) (write-sockaddr-in! bv index family (sockaddr:port sockaddr) (sockaddr:addr sockaddr))) ((= family AF_INET6) (write-sockaddr-in6! bv index family (sockaddr:port sockaddr) (sockaddr:flowinfo sockaddr) (sockaddr:addr sockaddr) (sockaddr:scopeid sockaddr))) (else (error "unsupported socket address" sockaddr))))) (define* (read-socket-address bv #:optional (index 0)) "Read a socket address from bytevector BV at INDEX." (let ((family (bytevector-u16-native-ref bv index))) (cond ((= family AF_INET) (read-sockaddr-in bv index)) ((= family AF_INET6) (read-sockaddr-in6 bv index)) (else ;; XXX: Unsupported address family, such as AF_PACKET. Return a ;; vector such that the caller can at least use 'sockaddr:fam'. (vector family))))) --8<---------------cut here---------------end--------------->8--- The expanded ‘read-sockaddr-in’ looks like this: --8<---------------cut here---------------start------------->8--- (define* (read-sockaddr-in bv #:optional (offset 0)) (let ((family (bytevector-uint-ref bv (#{1+}# (logior (#{1-}# offset) (#{1-}# 2))) (native-endianness) 2)) (port (bytevector-uint-ref bv (#{1+}# (logior (#{1-}# (+ (#{1+}# (logior (#{1-}# offset) (#{1-}# 2))) 2)) (#{1-}# 2))) 'big 2)) (address (bytevector-uint-ref bv (#{1+}# (logior (#{1-}# (+ (#{1+}# (logior (#{1-}# (+ (#{1+}# (logior (#{1-}# offset) (#{1-}# 2))) 2)) (#{1-}# 2))) 2)) (#{1-}# 4))) 'big 4))) (make-socket-address family address port))) --8<---------------cut here---------------end--------------->8--- No extra allocations and computations. http://git.savannah.gnu.org/cgit/guix.git/tree/guix/build/syscalls.scm#n264 I’m sure we could build a higher-level interface on top of that, for instance for when we want a C struct to directly have a corresponding Scheme record (as is the case of ‘%statfs’ in the file above.) Ludo’.