@@ -40,86 +40,163 @@ add_loader
40
40
" `add_saver(fmt, :Package)` triggers `using Package` before saving format `fmt`"
41
41
add_saver
42
42
43
-
44
43
"""
45
44
- `load(filename)` loads the contents of a formatted file, trying to infer
46
45
the format from `filename` and/or magic bytes in the file.
47
46
- `load(strm)` loads from an `IOStream` or similar object. In this case,
48
- the magic bytes are essential.
49
- - `load(File(format"PNG",filename))` specifies the format directly, and bypasses inference.
47
+ there is no filename extension, so we rely on the magic bytes for format
48
+ identification.
49
+ - `load(File(format"PNG", filename))` specifies the format directly, and bypasses inference.
50
+ - `load(Stream(format"PNG", io))` specifies the format directly, and bypasses inference.
50
51
- `load(f; options...)` passes keyword arguments on to the loader.
51
52
"""
52
- load (s:: Union{AbstractString,IO} , args... ; options... ) =
53
- load (query (s), args... ; options... )
53
+ load
54
+
55
+ """
56
+ Some packages may implement a streaming API, where the contents of the file can
57
+ be read in chunks and processed, rather than all at once. Reading from these
58
+ higher-level streams should return a formatted object, like an image or chunk of
59
+ video or audio.
60
+
61
+ - `loadstreaming(filename)` loads the contents of a formatted file, trying to infer
62
+ the format from `filename` and/or magic bytes in the file. It returns a streaming
63
+ type that can be read from in chunks, rather than loading the whole contents all
64
+ at once
65
+ - `loadstreaming(strm)` loads the stream from an `IOStream` or similar object.
66
+ In this case, there is no filename extension, so we rely on the magic bytes
67
+ for format identification.
68
+ - `loadstreaming(File(format"WAV",filename))` specifies the format directly, and
69
+ bypasses inference.
70
+ - `loadstreaming(Stream(format"WAV", io))` specifies the format directly, and
71
+ bypasses inference.
72
+ - `loadstreaming(f; options...)` passes keyword arguments on to the loader.
73
+ """
74
+ loadstreaming
54
75
55
76
"""
56
77
- `save(filename, data...)` saves the contents of a formatted file,
57
78
trying to infer the format from `filename`.
58
79
- `save(Stream(format"PNG",io), data...)` specifies the format directly, and bypasses inference.
80
+ - `save(File(format"PNG",filename), data...)` specifies the format directly, and bypasses inference.
59
81
- `save(f, data...; options...)` passes keyword arguments on to the saver.
60
82
"""
61
- save (s:: Union{AbstractString,IO} , data... ; options... ) =
62
- save (query (s), data... ; options... )
83
+ save
84
+
85
+ """
86
+ Some packages may implement a streaming API, where the contents of the file can
87
+ be written in chunks, rather than all at once. These higher-level streams should
88
+ accept formatted objects, like an image or chunk of video or audio.
89
+
90
+ - `savestreaming(filename, data...)` saves the contents of a formatted file,
91
+ trying to infer the format from `filename`.
92
+ - `savestreaming(File(format"WAV",filename))` specifies the format directly, and
93
+ bypasses inference.
94
+ - `savestreaming(Stream(format"WAV", io))` specifies the format directly, and
95
+ bypasses inference.
96
+ - `savestreaming(f, data...; options...)` passes keyword arguments on to the saver.
97
+ """
98
+ savestreaming
99
+
100
+ # if a bare filename or IO stream are given, query for the format and dispatch
101
+ # to the formatted handlers below
102
+ for fn in (:load , :loadstreaming , :save , :savestreaming )
103
+ @eval $ fn (s:: Union{AbstractString,IO} , args... ; options... ) =
104
+ $ fn (query (s), args... ; options... )
105
+ end
63
106
107
+ # return a save function, so you can do `thing_to_save |> save("filename.ext")`
64
108
function save (s:: Union{AbstractString,IO} ; options... )
65
109
data -> save (s, data; options... )
66
110
end
67
111
68
- # Forced format
112
+ # Allow format to be overridden with first argument
69
113
function save {sym} (df:: Type{DataFormat{sym}} , f:: AbstractString , data... ; options... )
70
114
libraries = applicable_savers (df)
71
115
checked_import (libraries[1 ])
72
116
eval (Main, :($ save ($ File ($ (DataFormat{sym}), $ f),
73
117
$ data... ; $ options... )))
74
118
end
75
119
120
+ function savestreaming {sym} (df:: Type{DataFormat{sym}} , s:: IO , data... ; options... )
121
+ libraries = applicable_savers (df)
122
+ checked_import (libraries[1 ])
123
+ eval (Main, :($ savestreaming ($ Stream ($ (DataFormat{sym}), $ s),
124
+ $ data... ; $ options... )))
125
+ end
126
+
76
127
function save {sym} (df:: Type{DataFormat{sym}} , s:: IO , data... ; options... )
77
128
libraries = applicable_savers (df)
78
129
checked_import (libraries[1 ])
79
130
eval (Main, :($ save ($ Stream ($ (DataFormat{sym}), $ s),
80
131
$ data... ; $ options... )))
81
132
end
82
133
134
+ function savestreaming {sym} (df:: Type{DataFormat{sym}} , f:: AbstractString , data... ; options... )
135
+ libraries = applicable_savers (df)
136
+ checked_import (libraries[1 ])
137
+ eval (Main, :($ savestreaming ($ File ($ (DataFormat{sym}), $ f),
138
+ $ data... ; $ options... )))
139
+ end
83
140
84
- # Fallbacks
85
- function load {F} (q:: Formatted{F} , args... ; options... )
86
- if unknown (q)
87
- isfile (filename (q)) || open (filename (q)) # force systemerror
88
- throw (UnknownFormat (q))
89
- end
90
- libraries = applicable_loaders (q)
91
- failures = Any[]
92
- for library in libraries
141
+ # do-syntax for streaming IO
142
+ for fn in (:loadstreaming , :savestreaming )
143
+ @eval function $fn (f:: Function , args... ; kwargs... )
144
+ str = $ fn (args... ; kwargs... )
93
145
try
94
- Library = checked_import (library)
95
- if ! has_method_from (methods (Library. load), Library)
96
- throw (LoaderError (string (library), " load not defined" ))
146
+ f (str)
147
+ finally
148
+ close (str)
149
+ end
150
+ end
151
+ end
152
+
153
+ # Handlers for formatted files/streams
154
+
155
+ for fn in (:load , :loadstreaming )
156
+ @eval function $fn {F} (q:: Formatted{F} , args... ; options... )
157
+ if unknown (q)
158
+ isfile (filename (q)) || open (filename (q)) # force systemerror
159
+ throw (UnknownFormat (q))
160
+ end
161
+ libraries = applicable_loaders (q)
162
+ failures = Any[]
163
+ for library in libraries
164
+ try
165
+ Library = checked_import (library)
166
+ if ! has_method_from (methods (Library.$ fn), Library)
167
+ throw (LoaderError (string (library), " $($ fn) not defined" ))
168
+ end
169
+ return eval (Main, :($ (Library.$ fn)($ q, $ args... ; $ options... )))
170
+ catch e
171
+ push! (failures, (e, q))
97
172
end
98
- return eval (Main, :($ (Library. load)($ q, $ args... ; $ options... )))
99
- catch e
100
- push! (failures, (e, q))
101
173
end
174
+ handle_exceptions (failures, " loading \" $(filename (q)) \" " )
102
175
end
103
- handle_exceptions (failures, " loading \" $(filename (q)) \" " )
104
176
end
105
- function save {F} (q:: Formatted{F} , data... ; options... )
106
- unknown (q) && throw (UnknownFormat (q))
107
- libraries = applicable_savers (q)
108
- failures = Any[]
109
- for library in libraries
110
- try
111
- Library = checked_import (library)
112
- if ! has_method_from (methods (Library. save), Library)
113
- throw (WriterError (string (library), " save not defined" ))
177
+
178
+ for fn in (:save , :savestreaming )
179
+ @eval function $fn {F} (q:: Formatted{F} , data... ; options... )
180
+ unknown (q) && throw (UnknownFormat (q))
181
+ libraries = applicable_savers (q)
182
+ failures = Any[]
183
+ for library in libraries
184
+ try
185
+ Library = checked_import (library)
186
+ if ! has_method_from (methods (Library.$ fn), Library)
187
+ throw (WriterError (string (library), " $($ fn) not defined" ))
188
+ end
189
+ return eval (Main, :($ (Library.$ fn)($ q, $ data... ; $ options... )))
190
+ catch e
191
+ push! (failures, (e, q))
114
192
end
115
- return eval (Main, :($ (Library. save)($ q, $ data... ; $ options... )))
116
- catch e
117
- push! (failures, (e, q))
118
193
end
194
+ handle_exceptions (failures, " saving \" $(filename (q)) \" " )
119
195
end
120
- handle_exceptions (failures, " saving \" $(filename (q)) \" " )
121
196
end
122
197
198
+ # returns true if the given method table includes a method defined by the given
199
+ # module, false otherwise
123
200
function has_method_from (mt, Library)
124
201
for m in mt
125
202
if getmodule (m) == Library
0 commit comments