forked from Shinmera/cl-steamworks
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinterface.lisp
108 lines (84 loc) · 4.53 KB
/
interface.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#|
This file is a part of cl-steamworks
(c) 2019 Shirakumo http://tymoon.eu ([email protected])
Author: Nicolas Hafner <[email protected]>
|#
(in-package #:org.shirakumo.fraf.steamworks)
;; FIXME: go through interfaces and check we use the correct handle for merged interfaces
(defclass interface (c-object)
((steamworks :initarg :steamworks :initform (error "STEAMWORKS required.") :reader %steamworks)
(object-cache :initform (tg:make-weak-hash-table :weakness :value :test 'eql) :reader object-cache)))
(defun ensure-iface-obj (class &rest initargs &key handle interface &allow-other-keys)
(or (interface-object handle interface)
(setf (interface-object handle interface)
(apply #'make-instance class initargs))))
(defmethod interface ((name symbol) (interface interface))
(interface (%steamworks interface)))
(defmethod interface-object (handle (interface symbol))
(interface-object handle (interface interface T)))
(defmethod interface-object (handle (interface interface))
(gethash handle (object-cache interface)))
(defmethod (setf interface-object) (object handle (name symbol))
(setf (interface-object handle (interface name T)) object))
(defmethod (setf interface-object) (object handle (interface interface))
(setf (gethash handle (object-cache interface)) object))
(defmethod remove-interface-object (handle (name symbol))
(remove-interface-object handle (interface name T)))
(defmethod remove-interface-object (handle (interface interface))
(remhash handle (object-cache interface)))
(defmethod remove-interface-object ((all (eql T)) (interface interface))
(clrhash (object-cache interface)))
(defun get-interface-handle (steamworks function &rest args)
(let ((handle (apply function (handle (interface 'steamclient steamworks)) args)))
(when (cffi:null-pointer-p handle)
(error 'interface-creation-failed))
handle))
(defun get-interface-handle* (steamworks function version)
(get-interface-handle steamworks function (handle (user steamworks)) (handle (pipe steamworks)) version))
(defmethod call-with ((interface interface) function &rest args)
(apply function (handle interface) args))
(defmethod call-with ((handle integer) function &rest args)
(apply function handle args))
(defmethod call-with ((interface symbol) function &rest args)
(apply #'call-with (interface interface (steamworks)) function args))
(defmacro define-interface-method (interface method call &body transform)
(destructuring-bind (interface handle) (enlist interface 'handle)
(let ((function (find-if (lambda (a) (and (symbolp a) (eq (symbol-package a) (find-package '#:steam)))) call))
(method-args (copy-list call)))
(setf (nth (position function method-args) method-args) (list interface interface))
`(defmethod ,method ,method-args
(let ((result (,function (,handle ,interface) ,@(apply #'remove-all (mapcar #'delist call)
function LAMBDA-LIST-KEYWORDS))))
(declare (ignorable result))
,@(or transform
(when (listp method)
(list (delist (first call))))
`(result)))))))
(defmacro define-interface-submethod (sub method call &body transform)
(destructuring-bind (sub handle) (enlist sub 'handle)
(let ((function (find-if (lambda (a) (and (symbolp a) (eq (symbol-package a) (find-package '#:steam)))) call))
(method-args (copy-list call)))
(setf (nth (position function method-args) method-args) (list sub sub))
`(defmethod ,method ,method-args
(let ((result (,function (,handle (iface ,sub)) (handle ,sub)
,@(apply #'remove-all (mapcar #'delist call)
function LAMBDA-LIST-KEYWORDS))))
(declare (ignorable result))
,@(or transform
(when (listp method)
(list (delist (first call))))
`(result)))))))
(defclass interface-object (c-object)
((interface :reader iface)))
(defmethod initialize-instance ((object interface-object) &key interface steamworks)
(call-next-method)
(setf (slot-value object 'interface)
(etypecase interface
(interface interface)
((and symbol (not null)) (interface interface (or steamworks (steamworks)))))))
(defun iface* (object)
(handle (iface object)))
(defmethod %steamworks ((object interface-object))
(%steamworks (iface object)))
(defmethod interface ((name symbol) (object interface-object))
(interface (%steamworks object)))