Merge commit '5d971db802eaa8038db17e1aa5b4c69452739744'
[bpt/guile.git] / module / system / foreign-object.scm
CommitLineData
a7ee7f7c
AW
1;;; Wrapping foreign objects in Scheme
2
3;;; Copyright (C) 2014 Free Software Foundation, Inc.
4;;;
5;;; This library is free software; you can redistribute it and/or
6;;; modify it under the terms of the GNU Lesser General Public
7;;; License as published by the Free Software Foundation; either
8;;; version 3 of the License, or (at your option) any later version.
9;;;
10;;; This library is distributed in the hope that it will be useful,
11;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13;;; Lesser General Public License for more details.
14;;;
15;;; You should have received a copy of the GNU Lesser General Public
16;;; License along with this library; if not, write to the Free Software
17;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18;;;
19
20;;; Commentary:
21;;
22;;
23;;; Code:
24
25(define-module (system foreign-object)
26 #:use-module (oop goops)
27 #:export (make-foreign-object-type
28 define-foreign-object-type))
29
30(eval-when (eval load expand)
31 (load-extension (string-append "libguile-" (effective-version))
32 "scm_init_foreign_object"))
33
34(define-class <finalizer-class> (<class>)
35 (finalizer #:init-keyword #:finalizer #:init-value #f
36 #:getter finalizer))
37
38(define-method (allocate-instance (class <finalizer-class>) initargs)
39 (let ((instance (next-method))
40 (finalizer (finalizer class)))
41 (when finalizer
42 (%add-finalizer! instance finalizer))
43 instance))
44
45(define (getter-method class slot-name existing)
46 (let ((getter (ensure-generic existing slot-name))
47 (slot-def (or (assq slot-name (slot-ref class 'getters-n-setters))
48 (slot-missing class slot-name))))
49 (add-method! getter (compute-getter-method class slot-def))
50 getter))
51
52(define* (make-foreign-object-type name slots #:key finalizer)
53 (unless (symbol? name)
54 (error "type name should be a symbol" name))
55 (unless (or (not finalizer) (procedure? finalizer))
56 (error "finalizer should be a procedure" finalizer))
57 (let ((dslots (map (lambda (slot)
58 (unless (symbol? slot)
59 (error "slot name should be a symbol" slot))
60 (list slot #:class <foreign-slot>
61 #:init-keyword (symbol->keyword slot)
62 #:init-value 0))
63 slots)))
64 (if finalizer
65 (make-class '() dslots #:name name
66 #:finalizer finalizer #:metaclass <finalizer-class>)
67 (make-class '() dslots #:name name))))
68
69(define-syntax define-foreign-object-type
70 (lambda (x)
71 (define (kw-apply slots)
72 (syntax-case slots ()
73 (() #'())
74 ((slot . slots)
75 (let ((kw (symbol->keyword (syntax->datum #'slot))))
76 #`(#,kw slot . #,(kw-apply #'slots))))))
77
78 (syntax-case x ()
79 ((_ name constructor (slot ...) kwarg ...)
80 #`(begin
81 (define name
82 (make-foreign-object-type 'name '(slot ...) kwarg ...))
83 (define slot
84 (getter-method name 'slot (and (defined? 'slot) slot)))
85 ...
86 (define constructor
87 (lambda (slot ...)
88 (make name #,@(kw-apply #'(slot ...))))))))))