unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* wayland client in Guile without libwayland-client
@ 2022-11-18 16:54 Matt Wette
  2022-11-18 17:03 ` Matt Wette
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Matt Wette @ 2022-11-18 16:54 UTC (permalink / raw)
  To: Guile User

Hi All,

Just for fun, I'm working on an "all" Guile client-side program
to use with Wayland.   I'm just getting started, but I thought you
all might be interested to see what I'm doing.

Wayland is the apparent replacement for X11.  My reading is that
it provides a client software tighter intergration with the GPUs.
In Wayland the display is managed by the "compositor".  Applications
communicate with the compositor via UNIX domain sockets.   Messages
have an eight byte header that provides object id, object code and
message size.  An object id is mapped to an interface, and the object
code is mapped to an interface method.  The interfaces and their
methods are specified in the protocol file "wayland.xml".

ref:https://wayland-book.com
ref:https://github.com/wayland-project/wayland/blob/main/protocol/wayland.xml

The above implies that one could write a client application for
Wayland in Guile using a socket interface and procedures generated
from wayland.xml.  I have started working on just that.  One issue
is that clients operate on buffers and surfaces directly.  To
negotiate buffer sharing, file descriptors are transferred over
the socket connection.  This means we need sendmsg() and recvmsg()
in Guile.  I have coded prototypes for those.  In addition, I have
generated an auto-coder to translate wayland.xml to Guile Scheme.

Socket extension procedures are:

   (sendmsg sock iobuf ix length cm-buf flags) => n-sent
   (recvmsg! sock iobuf ix cmsg-list flags) => (n-sent cm-buf)

cm-buf is a bytevector of control messages (`man cmsg`).  To deal
with control messages I have generated these procedures:

   (cmsg-list->bytevector cmsg-list) => bytevector
   (bytevector->cmsg-list bytevector) => cmsg-list

Here is an example of auto-coded request (client->server), from
wayland.xml to Guile Scheme:

(define-public encode-wl_display:get_registry
   (lambda (obj-id bv ix registry)
     (define (encode-body)
       (bytevector-u32-native-set! bv (+ ix 8) registry)
       (values (+ ix 12) #f))
     (call-with-values
       encode-body
       (lambda (msg-size control)
         (bytevector-u32-native-set! bv ix obj-id)
         (bytevector-u16-native-set! bv (+ ix 6) msg-size)
         (bytevector-u16-native-set! bv (+ ix 4) 1)
         (values msg-size control)))))

Here is an example of an auto-coded event decoder:

       (lambda (obj-id bv ix cm)
         "event decoder for global"
         (let*-values
           (((name ix) (dec-u32 bv ix))
            ((interface ix) (dec-string bv ix))
            ((version ix) (dec-u32 bv ix)))
           (values obj-id name interface version)))

With the event decoder and user-supplied handler I have this dispatch:

(define (dispatch obj-id opcode bv ix cm)
   (let* ((decoder (vector-ref (vector-ref object-decoders-vec obj-id) opcode))
          (handler (vector-ref (vector-ref object-handlers-vec obj-id) opcode)))
     (call-with-values
         (lambda () (decoder obj-id bv ix cm))
       handler)))


The code below sets up the interface with the compositor and obtains
the list of global objects and prints them.  The output is as follows:

global: 1	wl_compositor
global: 2	wl_drm
global: 3	wl_shm
global: 4	wl_output
global: 5	zxdg_output_manager_v1
global: 6	wl_data_device_manager
global: 7	zwp_primary_selection_device_manager_v1
global: 8	gtk_primary_selection_device_manager
global: 9	wl_subcompositor
global: 10	xdg_wm_base
global: 11	zxdg_shell_v6
global: 12	gtk_shell1
global: 13	wp_viewporter
global: 14	zwp_pointer_gestures_v1
global: 15	zwp_tablet_manager_v2
global: 16	wl_seat
global: 17	zwp_relative_pointer_manager_v1
global: 18	zwp_pointer_constraints_v1
global: 19	zxdg_exporter_v1
global: 20	zxdg_importer_v1
global: 21	zwp_linux_dmabuf_v1
global: 22	zwp_keyboard_shortcuts_inhibit_manager_v1
global: 23	zwp_text_input_manager_v3
global: 24	wp_presentation
global: 25	xdg_activation_v1


CODE:

;; per-interface vectors of handlers by opcode
(define wl-handler-vec-vec (make-wl-handler-vec-vec))

;; number of objects
(define user-obj-count (make-parameter 0))
(define (incr-obj-count) (user-obj-count (1+ (user-obj-count))))

;; vector of object-id => ref into wl-handler-vec (handler by opcode)
(define object-decoders-vec (make-vector 1000))

;; vector of object-id => ref into wl-handler-vec (handler by opcode)
(define object-handlers-vec (make-vector 1000))

;; vector of objec-id => user-defined value
(define object-value-vec (make-vector 1000))

;; set-event-handler 'wl_displaly 'get_registry proc => prev-proc
(define (set-event-handler interface event proc)
   (let* ((if-indx (assq-ref wayland-index-dict interface))
          (opcode (assq-ref (vector-ref wayland-opcode-dict-vec if-indx) event))
          (if-handlers (vector-ref wl-handler-vec-vec if-indx))
          (evt-handler (vector-ref if-handlers opcode)))
     (vector-set! if-handlers opcode proc)
     evt-handler))

(define (dispatch obj-id opcode bv ix cm)
   (let* ((decoder (vector-ref (vector-ref object-decoders-vec obj-id) opcode))
          (handler (vector-ref (vector-ref object-handlers-vec obj-id) opcode)))
     (call-with-values
         (lambda () (decoder obj-id bv ix cm))
       handler)))

(define null-id 0)
(define display-id 1)
(define registry-id 2)

;; wl_display:error
(define (handle-error obj-id code message)
   (sf "error: ~S\n" message))

;; wl_display:delete_id
(define (handle-delete_id obj-id id)
   (sf "delete-id: ~S\n" id))

(define (handle-global obj-id name interface version)
   (sf "global: ~A\t~A\n" name interface)
   #f)

(define (setup)

   (set-event-handler 'wl_display 'error handle-error)
   (set-event-handler 'wl_display 'delete_id handle-delete_id)
   (set-event-handler 'wl_registry 'global handle-global)
   
   ;; display
   (set! display-id 1)
   (let* ((ob-indx display-id)
          (if-indx (assq-ref wayland-index-dict 'wl_display))
          (if-decoders (vector-ref wl-decoder-vec-vec if-indx))
          (if-handlers (vector-ref wl-handler-vec-vec if-indx)))
     (vector-set! object-decoders-vec ob-indx if-decoders)
     (vector-set! object-handlers-vec ob-indx if-handlers))

   ;; registry object
   (set! registry-id 2)
   (let* ((ob-indx registry-id)
          (if-indx (assq-ref wayland-index-dict 'wl_registry))
          (if-decoders (vector-ref wl-decoder-vec-vec if-indx))
          (if-handlers (vector-ref wl-handler-vec-vec if-indx)))
     (vector-set! object-decoders-vec ob-indx if-decoders)
     (vector-set! object-handlers-vec ob-indx if-handlers))
   
   (user-obj-count 3))


(define socket-path
   (let ((dir (getenv "XDG_RUNTIME_DIR"))
	(dpy (getenv "WAYLAND_DISPLAY")))
     (and dir dpy (string-append dir "/" dpy))))

(define wl-display-id 1)
(define wl-registry-id 2)

(define (main)
   (let* ((path socket-path)
          (style (logior SOCK_STREAM SOCK_CLOEXEC))
          (sock (socket PF_UNIX SOCK_STREAM 0))
          (conn (connect sock AF_UNIX path))
          (iobuf (make-bytevector 72)))

     (setvbuf sock 'none)
     (setup)
     
     ;; request: wl_display:get_registry 2
     (call-with-values
         (lambda () (encode-wl_display:get_registry 1 iobuf 0 2))
       (lambda (ln ctl)
         (sendmsg sock iobuf 0 ln ctl)))
     
     (let loop ((n-have 0) (object-id #f) (msg-size 8) (opcode #f) (control #f))
       (usleep 20000)
       (cond
        ((< n-have msg-size)
         (let* ((res (recvmsg! sock iobuf n-have))
                (n-have (+ n-have (vector-ref res 0)))
                (control (or control (vector-ref res 1))))
           (loop n-have object-id msg-size opcode control)))
        ((not object-id)
         (let* ((object-id (bytevector-u32-native-ref iobuf 0))
                (word1 (bytevector-u32-native-ref iobuf 4))
                (msg-size (bytevector-u16-native-ref iobuf msg-size-offset))
                (opcode (bytevector-u16-native-ref iobuf opcode-offset)))
           (loop n-have object-id msg-size opcode control)))
        (else
         (dispatch object-id opcode iobuf 8 control)
         (if (> n-have msg-size)
             (bytevector-copy! iobuf msg-size iobuf 0 (- n-have msg-size)))
         (loop (- n-have msg-size) #f 8 opcode control))))

     0))

(main)



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: wayland client in Guile without libwayland-client
  2022-11-18 16:54 wayland client in Guile without libwayland-client Matt Wette
@ 2022-11-18 17:03 ` Matt Wette
  2022-11-18 22:34 ` Maxime Devos
  2022-11-19  4:26 ` Damien Mattei
  2 siblings, 0 replies; 6+ messages in thread
From: Matt Wette @ 2022-11-18 17:03 UTC (permalink / raw)
  To: guile-user

Oops: Please substitute "object code" with "opcode".

On 11/18/22 8:54 AM, Matt Wette wrote:
> Hi All,
>
> Just for fun, I'm working on an "all" Guile client-side program
> to use with Wayland.   I'm just getting started, but I thought you
> all might be interested to see what I'm doing.
>
> Wayland is the apparent replacement for X11.  My reading is that
> it provides a client software tighter intergration with the GPUs.
> In Wayland the display is managed by the "compositor". Applications
> communicate with the compositor via UNIX domain sockets. Messages
> have an eight byte header that provides object id, object code and
> message size.  An object id is mapped to an interface, and the object
> code is mapped to an interface method.  The interfaces and their
> methods are specified in the protocol file "wayland.xml".
>
> ref:https://wayland-book.com
> ref:https://github.com/wayland-project/wayland/blob/main/protocol/wayland.xml 
>
>
> The above implies that one could write a client application for
> Wayland in Guile using a socket interface and procedures generated
> from wayland.xml.  I have started working on just that.  One issue
> is that clients operate on buffers and surfaces directly.  To
> negotiate buffer sharing, file descriptors are transferred over
> the socket connection.  This means we need sendmsg() and recvmsg()
> in Guile.  I have coded prototypes for those.  In addition, I have
> generated an auto-coder to translate wayland.xml to Guile Scheme.
>
> Socket extension procedures are:
>
>   (sendmsg sock iobuf ix length cm-buf flags) => n-sent
>   (recvmsg! sock iobuf ix cmsg-list flags) => (n-sent cm-buf)
>
> cm-buf is a bytevector of control messages (`man cmsg`).  To deal
> with control messages I have generated these procedures:
>
>   (cmsg-list->bytevector cmsg-list) => bytevector
>   (bytevector->cmsg-list bytevector) => cmsg-list
>
> Here is an example of auto-coded request (client->server), from
> wayland.xml to Guile Scheme:
>
> (define-public encode-wl_display:get_registry
>   (lambda (obj-id bv ix registry)
>     (define (encode-body)
>       (bytevector-u32-native-set! bv (+ ix 8) registry)
>       (values (+ ix 12) #f))
>     (call-with-values
>       encode-body
>       (lambda (msg-size control)
>         (bytevector-u32-native-set! bv ix obj-id)
>         (bytevector-u16-native-set! bv (+ ix 6) msg-size)
>         (bytevector-u16-native-set! bv (+ ix 4) 1)
>         (values msg-size control)))))
>
> Here is an example of an auto-coded event decoder:
>
>       (lambda (obj-id bv ix cm)
>         "event decoder for global"
>         (let*-values
>           (((name ix) (dec-u32 bv ix))
>            ((interface ix) (dec-string bv ix))
>            ((version ix) (dec-u32 bv ix)))
>           (values obj-id name interface version)))
>
> With the event decoder and user-supplied handler I have this dispatch:
>
> (define (dispatch obj-id opcode bv ix cm)
>   (let* ((decoder (vector-ref (vector-ref object-decoders-vec obj-id) 
> opcode))
>          (handler (vector-ref (vector-ref object-handlers-vec obj-id) 
> opcode)))
>     (call-with-values
>         (lambda () (decoder obj-id bv ix cm))
>       handler)))
>
>
> The code below sets up the interface with the compositor and obtains
> the list of global objects and prints them.  The output is as follows:
>
> global: 1    wl_compositor
> global: 2    wl_drm
> global: 3    wl_shm
> global: 4    wl_output
> global: 5    zxdg_output_manager_v1
> global: 6    wl_data_device_manager
> global: 7    zwp_primary_selection_device_manager_v1
> global: 8    gtk_primary_selection_device_manager
> global: 9    wl_subcompositor
> global: 10    xdg_wm_base
> global: 11    zxdg_shell_v6
> global: 12    gtk_shell1
> global: 13    wp_viewporter
> global: 14    zwp_pointer_gestures_v1
> global: 15    zwp_tablet_manager_v2
> global: 16    wl_seat
> global: 17    zwp_relative_pointer_manager_v1
> global: 18    zwp_pointer_constraints_v1
> global: 19    zxdg_exporter_v1
> global: 20    zxdg_importer_v1
> global: 21    zwp_linux_dmabuf_v1
> global: 22    zwp_keyboard_shortcuts_inhibit_manager_v1
> global: 23    zwp_text_input_manager_v3
> global: 24    wp_presentation
> global: 25    xdg_activation_v1
>
>
> CODE:
>
> ;; per-interface vectors of handlers by opcode
> (define wl-handler-vec-vec (make-wl-handler-vec-vec))
>
> ;; number of objects
> (define user-obj-count (make-parameter 0))
> (define (incr-obj-count) (user-obj-count (1+ (user-obj-count))))
>
> ;; vector of object-id => ref into wl-handler-vec (handler by opcode)
> (define object-decoders-vec (make-vector 1000))
>
> ;; vector of object-id => ref into wl-handler-vec (handler by opcode)
> (define object-handlers-vec (make-vector 1000))
>
> ;; vector of objec-id => user-defined value
> (define object-value-vec (make-vector 1000))
>
> ;; set-event-handler 'wl_displaly 'get_registry proc => prev-proc
> (define (set-event-handler interface event proc)
>   (let* ((if-indx (assq-ref wayland-index-dict interface))
>          (opcode (assq-ref (vector-ref wayland-opcode-dict-vec 
> if-indx) event))
>          (if-handlers (vector-ref wl-handler-vec-vec if-indx))
>          (evt-handler (vector-ref if-handlers opcode)))
>     (vector-set! if-handlers opcode proc)
>     evt-handler))
>
> (define (dispatch obj-id opcode bv ix cm)
>   (let* ((decoder (vector-ref (vector-ref object-decoders-vec obj-id) 
> opcode))
>          (handler (vector-ref (vector-ref object-handlers-vec obj-id) 
> opcode)))
>     (call-with-values
>         (lambda () (decoder obj-id bv ix cm))
>       handler)))
>
> (define null-id 0)
> (define display-id 1)
> (define registry-id 2)
>
> ;; wl_display:error
> (define (handle-error obj-id code message)
>   (sf "error: ~S\n" message))
>
> ;; wl_display:delete_id
> (define (handle-delete_id obj-id id)
>   (sf "delete-id: ~S\n" id))
>
> (define (handle-global obj-id name interface version)
>   (sf "global: ~A\t~A\n" name interface)
>   #f)
>
> (define (setup)
>
>   (set-event-handler 'wl_display 'error handle-error)
>   (set-event-handler 'wl_display 'delete_id handle-delete_id)
>   (set-event-handler 'wl_registry 'global handle-global)
>     ;; display
>   (set! display-id 1)
>   (let* ((ob-indx display-id)
>          (if-indx (assq-ref wayland-index-dict 'wl_display))
>          (if-decoders (vector-ref wl-decoder-vec-vec if-indx))
>          (if-handlers (vector-ref wl-handler-vec-vec if-indx)))
>     (vector-set! object-decoders-vec ob-indx if-decoders)
>     (vector-set! object-handlers-vec ob-indx if-handlers))
>
>   ;; registry object
>   (set! registry-id 2)
>   (let* ((ob-indx registry-id)
>          (if-indx (assq-ref wayland-index-dict 'wl_registry))
>          (if-decoders (vector-ref wl-decoder-vec-vec if-indx))
>          (if-handlers (vector-ref wl-handler-vec-vec if-indx)))
>     (vector-set! object-decoders-vec ob-indx if-decoders)
>     (vector-set! object-handlers-vec ob-indx if-handlers))
>     (user-obj-count 3))
>
>
> (define socket-path
>   (let ((dir (getenv "XDG_RUNTIME_DIR"))
>     (dpy (getenv "WAYLAND_DISPLAY")))
>     (and dir dpy (string-append dir "/" dpy))))
>
> (define wl-display-id 1)
> (define wl-registry-id 2)
>
> (define (main)
>   (let* ((path socket-path)
>          (style (logior SOCK_STREAM SOCK_CLOEXEC))
>          (sock (socket PF_UNIX SOCK_STREAM 0))
>          (conn (connect sock AF_UNIX path))
>          (iobuf (make-bytevector 72)))
>
>     (setvbuf sock 'none)
>     (setup)
>         ;; request: wl_display:get_registry 2
>     (call-with-values
>         (lambda () (encode-wl_display:get_registry 1 iobuf 0 2))
>       (lambda (ln ctl)
>         (sendmsg sock iobuf 0 ln ctl)))
>         (let loop ((n-have 0) (object-id #f) (msg-size 8) (opcode #f) 
> (control #f))
>       (usleep 20000)
>       (cond
>        ((< n-have msg-size)
>         (let* ((res (recvmsg! sock iobuf n-have))
>                (n-have (+ n-have (vector-ref res 0)))
>                (control (or control (vector-ref res 1))))
>           (loop n-have object-id msg-size opcode control)))
>        ((not object-id)
>         (let* ((object-id (bytevector-u32-native-ref iobuf 0))
>                (word1 (bytevector-u32-native-ref iobuf 4))
>                (msg-size (bytevector-u16-native-ref iobuf 
> msg-size-offset))
>                (opcode (bytevector-u16-native-ref iobuf opcode-offset)))
>           (loop n-have object-id msg-size opcode control)))
>        (else
>         (dispatch object-id opcode iobuf 8 control)
>         (if (> n-have msg-size)
>             (bytevector-copy! iobuf msg-size iobuf 0 (- n-have 
> msg-size)))
>         (loop (- n-have msg-size) #f 8 opcode control))))
>
>     0))
>
> (main)
>




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: wayland client in Guile without libwayland-client
  2022-11-18 16:54 wayland client in Guile without libwayland-client Matt Wette
  2022-11-18 17:03 ` Matt Wette
@ 2022-11-18 22:34 ` Maxime Devos
  2022-11-18 22:58   ` Matt Wette
  2022-11-19  4:26 ` Damien Mattei
  2 siblings, 1 reply; 6+ messages in thread
From: Maxime Devos @ 2022-11-18 22:34 UTC (permalink / raw)
  To: Matt Wette, Guile User


[-- Attachment #1.1.1: Type: text/plain, Size: 736 bytes --]



On 18-11-2022 17:54, Matt Wette wrote:
> cm-buf is a bytevector of control messages (`man cmsg`).  To deal
> with control messages I have generated these procedures:
> 
>    (cmsg-list->bytevector cmsg-list) => bytevector
>    (bytevector->cmsg-list bytevector) => cmsg-list

I have previously written an implementation for encoding/decoding cmsg 
at 
<https://git.gnunet.org/gnunet-scheme.git/tree/gnu/gnunet/util/cmsg.scm>, 
with a bunch of tests at 
<https://git.gnunet.org/gnunet-scheme.git/tree/tests/cmsg.scm> (no 
bindings for sendmsg, recvmsg!, though).

To compare, could you share your implementation of cmsg-list->bytevector 
and bytevector->cmsg-list?.

Greetings,
Maxime.

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 929 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: wayland client in Guile without libwayland-client
  2022-11-18 22:34 ` Maxime Devos
@ 2022-11-18 22:58   ` Matt Wette
  0 siblings, 0 replies; 6+ messages in thread
From: Matt Wette @ 2022-11-18 22:58 UTC (permalink / raw)
  To: Maxime Devos, Guile User

On 11/18/22 2:34 PM, Maxime Devos wrote:

>
>
> On 18-11-2022 17:54, Matt Wette wrote:
>> cm-buf is a bytevector of control messages (`man cmsg`).  To deal
>> with control messages I have generated these procedures:
>>
>>    (cmsg-list->bytevector cmsg-list) => bytevector
>>    (bytevector->cmsg-list bytevector) => cmsg-list
>
> I have previously written an implementation for encoding/decoding cmsg 
> at 
> <https://git.gnunet.org/gnunet-scheme.git/tree/gnu/gnunet/util/cmsg.scm>, 
> with a bunch of tests at 
> <https://git.gnunet.org/gnunet-scheme.git/tree/tests/cmsg.scm> (no 
> bindings for sendmsg, recvmsg!, though).
>
> To compare, could you share your implementation of 
> cmsg-list->bytevector and bytevector->cmsg-list?.
>
> Greetings,
> Maxime.
OK.  I have not used yet.

And I want to mention, because my sendmsg() recvmsg() explanation was 
not clear,
those routines will accept a bytevector or vector of bytevectors for iobuf.

Here is the cmsg code.  I have not used it yet, so not really tested.
I will check your stuff out.
#define CMSG_SZ(cmsg) ((cmsg->cmsg_len) - sizeof(struct cmsghdr))

size_t
scm_c_cmsg_len (SCM cmsg)
{
   SCM bv;
   size_t ln;

   // SCM_ASSERT (scm_is_vector (cmsg), cmsg, 0, scm_c_cmsg_len);
   bv = scm_c_vector_ref (cmsg, 2);
   // SCM_ASSERT (scm_is_bytevector (bv), cmsg, 0, scm_c_cmsg_len);
   ln = CMSG_LEN (scm_c_bytevector_length (bv));
   return ln;
}

SCM_DEFINE(scm_cmsg_list_to_bytevector, "cmsg-list->bytevector", 1, 0, 0,
        (SCM cmsgl),
        "control message list to bytevector")
#define FUNC_NAME s_scm_cmsg_list_to_bytevector
{
   SCM ml, cm, bv, cb;
   size_t ln;
   struct cmsghdr *cmsg;

   for (ml = cmsgl, ln = 0; ml != SCM_EOL; ml = SCM_CDR (ml)) {
     cm = SCM_CAR (ml);
     ln += CMSG_ALIGN (scm_c_cmsg_len (cm));
   }

   bv = scm_c_make_bytevector (ln);

   cmsg = (struct cmsghdr *) SCM_BYTEVECTOR_CONTENTS (bv);
   memset(cmsg, 0, ln);
   for (ml = cmsgl, ln = 0; ml != SCM_EOL; ml = SCM_CDR (ml)) {
     cm = SCM_CAR (ml);
     cmsg->cmsg_len = scm_c_cmsg_len (cm);
     cmsg->cmsg_level = scm_to_int (scm_c_vector_ref (cm, 0));
     cmsg->cmsg_type = scm_to_int (scm_c_vector_ref (cm, 1));
     cb = scm_c_vector_ref (cm, 2);
     memcpy (CMSG_DATA(cmsg), SCM_BYTEVECTOR_CONTENTS (cb),
         scm_c_bytevector_length (cb));
     cmsg = (struct cmsghdr *)((unsigned char *) cmsg
                   + CMSG_ALIGN (cmsg->cmsg_len));
   }

   return bv;
}
#undef FUNC_NAME

SCM_DEFINE(scm_bytevector_to_cmsg_list, "bytevector->cmsg-list", 1, 0, 0,
        (SCM bv),
        "extract cmsg-list from bytevector")
#define FUNC_NAME s_scm_bytevector_to_cmsg_list
{
   SCM res, bv1, ctl;
   struct msghdr *mhp;
   struct cmsghdr *cmsg;
   union { struct msghdr mh; double d; } x;

   mhp = &x.mh;

   SCM_VALIDATE_BYTEVECTOR (1, bv);
   mhp->msg_control = (struct cmsghdr *) SCM_BYTEVECTOR_CONTENTS (bv);
   mhp->msg_controllen = SCM_BYTEVECTOR_LENGTH (bv);

   res = SCM_EOL;
   for (cmsg = CMSG_FIRSTHDR (mhp); cmsg != NULL;
        cmsg = CMSG_NXTHDR (mhp, cmsg)) {
     ctl = scm_c_make_vector (3, SCM_BOOL_F);
     scm_c_vector_set_x (ctl, 0, scm_from_int (cmsg->cmsg_level));
     scm_c_vector_set_x (ctl, 1, scm_from_int (cmsg->cmsg_type));
     bv1 = scm_c_make_bytevector (CMSG_SZ (cmsg));
     memcpy(SCM_BYTEVECTOR_CONTENTS (bv1), CMSG_DATA (cmsg), CMSG_SZ 
(cmsg));
     scm_c_vector_set_x (ctl, 2, bv1);
     res = scm_cons(ctl, res);
   }
   res = scm_reverse_x (res, SCM_UNDEFINED);
   return res;
}
#undef FUNC_NAME



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: wayland client in Guile without libwayland-client
  2022-11-18 16:54 wayland client in Guile without libwayland-client Matt Wette
  2022-11-18 17:03 ` Matt Wette
  2022-11-18 22:34 ` Maxime Devos
@ 2022-11-19  4:26 ` Damien Mattei
  2022-11-19 14:50   ` Matt Wette
  2 siblings, 1 reply; 6+ messages in thread
From: Damien Mattei @ 2022-11-19  4:26 UTC (permalink / raw)
  To: Matt Wette, Linus Björnstam; +Cc: Guile User

hello,

it is just a question about semantic and aside the subject of project, and
related to another subject of internal definitions that Linus is talking
about:

On Fri, Nov 18, 2022 at 5:55 PM Matt Wette <matt.wette@gmail.com> wrote:

>
> Here is an example of an auto-coded event decoder:
>
>        (lambda (obj-id bv ix cm)
>          "event decoder for global"
>          (let*-values
>            (((name ix) (dec-u32 bv ix))
>             ((interface ix) (dec-string bv ix))
>             ((version ix) (dec-u32 bv ix)))
>            (values obj-id name interface version)))
>
>
>
i was just thinking how i would write the procedure above in Scheme+ (
https://github.com/damien-mattei/Scheme-PLUS-for-Guile ) that has feature
for multiple values.
this code could be rewritten like that:
(lambda (obj-id bv ix cm)
         "event decoder for global"
         {(name ix) <+ (dec-u32 bv ix)}
         {(interface ix) <+ (dec-string bv ix)}
         {(version ix) <+ (dec-u32 bv ix)}
           (values obj-id name interface version))

note that <+ is an "operator" that allows multiple values definitions.

but it would fails to compile because of multiple redefinition of ix
variable:

scheme@(guile-user)> (use-modules (Scheme+))
scheme@(guile-user)> (lambda (obj-id bv ix cm)
         "event decoder for global"
         {(name ix) <+ (dec-u32 bv ix)}
         {(interface ix) <+ (dec-string bv ix)}
         {(version ix) <+ (dec-u32 bv ix)}
           (values obj-id name interface version))
While compiling expression:
Syntax error:
unknown file:7:0: invalid or duplicate identifier in definition in form
(lambda (obj-id bv ix cm) "event decoder for global" (<+ (name ix) (dec-u32
bv ix)) (<+ (interface ix) (dec-string bv ix)) (<+ (version ix) (dec-u32 bv
ix)) (values obj-id name interface version))

a longer and a bit unsightly solution could be:

(lambda (obj-id bv ix cm)
         "event decoder for global"
         (declare name interface version)
         {(name ix) <v (dec-u32 bv ix)}
         {(interface ix) <v (dec-string bv ix)}
         {(version ix) <v (dec-u32 bv ix)}
           (values obj-id name interface version))

that would be correct:

(note <v instead of <+ is a setter! for already defined values and declare
just define variables initialised by default with '() in Scheme+)

scheme@(guile-user)> (lambda (obj-id bv ix cm)
         "event decoder for global"
         (declare name interface version)
         {(name ix) <v (dec-u32 bv ix)}
         {(interface ix) <v (dec-string bv ix)}
         {(version ix) <v (dec-u32 bv ix)}
           (values obj-id name interface version))
;;; <stdin>:16:24: warning: possibly unbound variable `dec-u32'
;;; <stdin>:17:29: warning: possibly unbound variable `dec-string'
$3 = #<procedure 149009320 at <unknown port>:13:0 (obj-id bv ix cm)>

the first example fails not because of my Scheme+ language extension but
because in scheme redefinition is only allowed at toplevel or in the REPL.

Would it not be a good idea to allow redefinitions in Scheme and Guile not
only at toplevel or REPL but in procedure definitions and lambda, in their
bodies?

personaly i can not see any "bad" side effect or consequences... of course
it relax the possibility of code error by unchecking a redefinition of
variable but it is like in C++ where you can define private or protected
variables but even with protective language feature one can wrote bad
code...

Best regards,

Damien


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: wayland client in Guile without libwayland-client
  2022-11-19  4:26 ` Damien Mattei
@ 2022-11-19 14:50   ` Matt Wette
  0 siblings, 0 replies; 6+ messages in thread
From: Matt Wette @ 2022-11-19 14:50 UTC (permalink / raw)
  To: Damien Mattei, Linus Björnstam; +Cc: Guile User

On 11/18/22 8:26 PM, Damien Mattei wrote:
> hello,
>
> it is just a question about semantic and aside the subject of project, and
> related to another subject of internal definitions that Linus is talking
> about:
>
> On Fri, Nov 18, 2022 at 5:55 PM Matt Wette<matt.wette@gmail.com>  wrote:
>
>> Here is an example of an auto-coded event decoder:
>>
>>         (lambda (obj-id bv ix cm)
>>           "event decoder for global"
>>           (let*-values
>>             (((name ix) (dec-u32 bv ix))
>>              ((interface ix) (dec-string bv ix))
>>              ((version ix) (dec-u32 bv ix)))
>>             (values obj-id name interface version)))
>>
>>
>>
> i was just thinking how i would write the procedure above in Scheme+ (
> https://github.com/damien-mattei/Scheme-PLUS-for-Guile  ) that has feature
> for multiple values.
> this code could be rewritten like that:
> (lambda (obj-id bv ix cm)
>           "event decoder for global"
>           {(name ix) <+ (dec-u32 bv ix)}
>           {(interface ix) <+ (dec-string bv ix)}
>           {(version ix) <+ (dec-u32 bv ix)}
>             (values obj-id name interface version))
>
> note that <+ is an "operator" that allows multiple values definitions.
>
> but it would fails to compile because of multiple redefinition of ix
> variable:
>
> scheme@(guile-user)> (use-modules (Scheme+))
> scheme@(guile-user)> (lambda (obj-id bv ix cm)
>           "event decoder for global"
>           {(name ix) <+ (dec-u32 bv ix)}
>           {(interface ix) <+ (dec-string bv ix)}
>           {(version ix) <+ (dec-u32 bv ix)}
>             (values obj-id name interface version))
> While compiling expression:
> Syntax error:
> unknownfile:7:0: invalid or duplicate identifier in definition in form
> (lambda (obj-id bv ix cm) "event decoder for global" (<+ (name ix) (dec-u32
> bv ix)) (<+ (interface ix) (dec-string bv ix)) (<+ (version ix) (dec-u32 bv
> ix)) (values obj-id name interface version))
>
> a longer and a bit unsightly solution could be:
>
> (lambda (obj-id bv ix cm)
>           "event decoder for global"
>           (declare name interface version)
>           {(name ix) <v (dec-u32 bv ix)}
>           {(interface ix) <v (dec-string bv ix)}
>           {(version ix) <v (dec-u32 bv ix)}
>             (values obj-id name interface version))
>
> that would be correct:
>
> (note <v instead of <+ is a setter! for already defined values and declare
> just define variables initialised by default with '() in Scheme+)
>
> scheme@(guile-user)> (lambda (obj-id bv ix cm)
>           "event decoder for global"
>           (declare name interface version)
>           {(name ix) <v (dec-u32 bv ix)}
>           {(interface ix) <v (dec-string bv ix)}
>           {(version ix) <v (dec-u32 bv ix)}
>             (values obj-id name interface version))
> ;;; <stdin>:16:24: warning: possibly unbound variable `dec-u32'
> ;;; <stdin>:17:29: warning: possibly unbound variable `dec-string'
> $3 = #<procedure 149009320 at <unknown port>:13:0 (obj-id bv ix cm)>
>
> the first example fails not because of my Scheme+ language extension but
> because in scheme redefinition is only allowed at toplevel or in the REPL.
>
> Would it not be a good idea to allow redefinitions in Scheme and Guile not
> only at toplevel or REPL but in procedure definitions and lambda, in their
> bodies?
>
> personaly i can not see any "bad" side effect or consequences... of course
> it relax the possibility of code error by unchecking a redefinition of
> variable but it is like in C++ where you can define private or protected
> variables but even with protective language feature one can wrote bad
> code...
>
> Best regards,
>
> Damien

Another approach might be a state monad (guix has code for this).   I am not sure
about other implementations, but I am reasonably confident that the Guile compiler
can turn my values-heavy Scheme into efficient bytecode.  I'm also working to
keep allocations down also (e.g., reusing bytevector buffers).

Thanks for your interest.
Matt


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2022-11-19 14:50 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-18 16:54 wayland client in Guile without libwayland-client Matt Wette
2022-11-18 17:03 ` Matt Wette
2022-11-18 22:34 ` Maxime Devos
2022-11-18 22:58   ` Matt Wette
2022-11-19  4:26 ` Damien Mattei
2022-11-19 14:50   ` Matt Wette

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).