1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-29 19:30:36 +02:00

Expose read-c-struct, write-c-struct syntax

* module/system/foreign.scm (read-c-struct): Rename from read-fields.
Export.
(write-c-struct): Rename from write-fields.  Export.
(%write-c-struct, %read-c-struct): Add % prefix to these private
bindings.
This commit is contained in:
Andy Wingo 2024-03-17 21:39:16 +01:00
parent d7ae468c17
commit e15617dc0e
2 changed files with 63 additions and 21 deletions

View file

@ -1,6 +1,6 @@
@c -*-texinfo-*-
@c This is part of the GNU Guile Reference Manual.
@c Copyright (C) 1996, 1997, 2000-2004, 2007-2014, 2016-2017, 2021
@c Copyright (C) 1996, 1997, 2000-2004, 2007-2014, 2016-2017, 2021, 2024
@c Free Software Foundation, Inc.
@c See the file guile.texi for copying conditions.
@ -761,24 +761,64 @@ also be a list of types, in which case the alignment of a
@code{struct} with ABI-conventional packing is returned.
@end deffn
Guile also provides some convenience methods to pack and unpack foreign
pointers wrapping C structs.
Guile also provides some convenience syntax to efficiently read and
write C structs to and from bytevectors.
@deffn {Scheme Procedure} make-c-struct types vals
Create a foreign pointer to a C struct containing @var{vals} with types
@code{types}.
@deffn {Scheme Syntax} read-c-struct bv offset @* ((field type) @dots{}) k
Read a C struct with fields of type @var{type}... from the bytevector
@var{bv}, at offset @var{offset}. Bind the fields to the identifiers
@var{field}..., and return @code{(@var{k} @var{field} ...)}.
@var{vals} and @code{types} should be lists of the same length.
Unless cross-compiling, the field types are evaluated at macro-expansion
time. This allows the resulting bytevector accessors and size/alignment
computations to be completely inlined.
@end deffn
@deffn {Scheme Syntax} write-c-struct bv offset @* ((field type) @dots{})
Write a C struct with fields @var{field}... of type @var{type}... to the bytevector
@var{bv}, at offset @var{offset}. Return zero values.
Like @code{write-c-struct} above, unless cross-compiling, the field
types are evaluated at macro-expansion time.
@end deffn
For example, to define a parser and serializer for the equivalent of a
@code{struct @{ int64_t a; uint8_t b; @}}, one might do this:
@example
(use-modules (system foreign) (rnrs bytevectors))
(define-syntax-rule
(define-serialization (reader writer) (field type) ...)
(begin
(define (reader bv offset)
(read-c-struct bv offset ((field type) ...) values))
(define (writer bv offset field ...)
(write-c-struct bv offset ((field type) ...)))))
(define-serialization (read-struct write-struct)
(a int64) (b uint8))
(define bv (make-bytevector (sizeof (list int64 uint8))))
(write-struct bv 0 300 43)
(call-with-values (lambda () (read-struct bv 0))
list)
@result{} (300 43)
@end example
There is also an older interface that is mostly equivalent to
@code{read-c-struct} and @code{write-c-struct}, but which uses run-time
dispatch, and operates on foreign pointers instead of bytevectors.
@deffn {Scheme Procedure} parse-c-struct foreign types
Parse a foreign pointer to a C struct, returning a list of values.
@code{types} should be a list of C types.
@end deffn
For example, to create and parse the equivalent of a @code{struct @{
int64_t a; uint8_t b; @}}:
Our parser and serializer example for @code{struct @{ int64_t a; uint8_t
b; @}} looks more like this:
@example
(parse-c-struct (make-c-struct (list int64 uint8)