-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathio.lisp
125 lines (108 loc) · 3.76 KB
/
io.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
(in-package #:org.shirakumo.zippy)
(deftype io ()
`(or stream vector-input directory-input))
(defstruct (vector-input (:constructor make-vector-input (vector index start end)))
(vector NIL :type (simple-array (unsigned-byte 8) (*)) :read-only T)
(start 0 :type fixnum :read-only T)
(end 0 :type fixnum :read-only T)
(index 0 :type fixnum))
(defstruct directory-input)
(defun seek (io target)
(etypecase io
(vector-input
(if (<= (vector-input-start io) target (1- (vector-input-end io)))
(setf (vector-input-index io) target)
(error 'out-of-bounds-seek :target target)))
(stream
(file-position io target))))
(defun has-more (io)
(etypecase io
(vector-input
(< (vector-input-index io) (vector-input-end io)))
(stream
(< (file-position io) (file-length io)))))
(defun index (io)
(etypecase io
(vector-input
(vector-input-index io))
(stream ; works for e.g. flexi-stream:in-memory-*-stream
(file-position io))))
(defun start (io)
(etypecase io
(vector-input
(vector-input-start io))
(stream
0)))
(defun end (io)
(etypecase io
(vector-input
(vector-input-end io))
(stream
(file-length io))))
(defmethod size ((io vector-input))
(- (vector-input-end io) (vector-input-start io)))
(defmethod size ((io stream))
(file-length io))
(defun ub32 (io)
(etypecase io
(vector-input
(prog1 (nibbles:ub32ref/le (vector-input-vector io) (vector-input-index io))
(incf (vector-input-index io) 4)))
(stream
(nibbles:read-ub32/le io))))
(defun output (io array start end)
(etypecase io
(vector-input
(when (<= (vector-input-end io) (+ (vector-input-index io) (- end start)))
(error 'out-of-bounds-seek :target (+ (vector-input-index io) (- end start))))
(loop with vector = (vector-input-vector io)
for i from start below end
for j from (vector-input-index io)
do (setf (aref vector j) (aref array i)))
(incf (vector-input-index io) (- end start)))
(stream
(write-sequence array io :start start :end end))))
(defun parse-structure* (io)
(etypecase io
(vector-input
(multiple-value-bind (value index)
(decode-structure (vector-input-vector io) (vector-input-index io))
(setf (vector-input-index io) index)
value))
(stream
(read-structure io))))
(defun write-structure* (structure io)
(etypecase io
(vector-input
(setf (vector-input-index io)
(encode-structure structure (vector-input-vector io) (vector-input-index io))))
(stream
(write-structure structure io)))
io)
(defmacro parse-structure (structure-type io-var)
(let ((io (gensym "IO")))
`(let ((,io ,io-var))
(etypecase ,io
(vector-input
(multiple-value-bind (value index)
(,(intern (format NIL "~a-~a" 'decode structure-type))
(vector-input-vector ,io) (vector-input-index ,io))
(setf (vector-input-index ,io) index)
value))
(stream
(,(intern (format NIL "~a-~a" 'read structure-type)) ,io))))))
(defun call-with-io (function io &key (start 0) end (if-exists :error) (direction :input))
(etypecase io
((or string pathname)
(if (pathname-utils:directory-p io)
(funcall function (make-directory-input))
(with-open-file (stream io :direction direction
:element-type '(unsigned-byte 8)
:if-exists if-exists)
(funcall function stream))))
(io
(funcall function io))
(vector
(funcall function (make-vector-input io start start (or end (length io)))))))
(defmacro with-io ((io target &rest args) &body body)
`(call-with-io (lambda (,io) ,@body) ,target ,@args))