0 | module System.UV.File
4 | import System.UV.Loop
5 | import System.UV.Pointer
6 | import System.UV.Util
8 | import public Data.Buffer.Indexed
9 | import public Data.ByteString
11 | import public System.UV.Raw.File
37 | fsClose : HasIO io => (l : UVLoop) => File -> io ()
38 | fsClose f = ignore . sync $
uv_fs_close l.loop f.file
41 | UVLoop => Resource File where
49 | data UVFileError : Type where
50 | OpenError : String -> UVError -> UVFileError
51 | ReadError : String -> UVError -> UVFileError
52 | WriteError : String -> UVError -> UVFileError
55 | Interpolation UVFileError where
56 | interpolate (OpenError s x) = "Error when opening \{s}: \{errorMsg x}"
57 | interpolate (ReadError s x) = "Error when reading \{s}: \{errorMsg x}"
58 | interpolate (WriteError s x) = "Error when writing to \{s}: \{errorMsg x}"
61 | {auto has : Has UVFileError es}
62 | -> (UVError -> UVFileError)
63 | -> Async [UVError] a
65 | toFileError f = handleErrors (throw . f . project1)
71 | parameters {auto l : UVLoop}
72 | {auto has : Has UVError es}
74 | fsOutcome : (Outcome es Int32 -> IO ()) -> Ptr Fs -> IO ()
76 | n <- uv_fs_get_result p
78 | then cb (Error . inject $
fromCode n)
79 | else cb (Succeeded n)
81 | fileOutcome : (Outcome es File -> IO ()) -> Ptr Fs -> IO ()
82 | fileOutcome cb = fsOutcome (cb . map MkFile)
84 | parameters {auto l : UVLoop}
85 | {auto has : Has UVFileError es}
89 | fsOpen : String -> Flags -> Mode -> Async es File
91 | toFileError (OpenError path) $
uvAsync $
92 | async (uv_fs_open l.loop path f.flags m.mode) . fileOutcome
95 | readOpen : String -> Async es File
96 | readOpen s = fsOpen s RDONLY 0
99 | writeOpen : String -> Async es File
100 | writeOpen s = fsOpen s (WRONLY <+> CREAT) 0o644
103 | appendOpen : String -> Async es File
104 | appendOpen s = fsOpen s (WRONLY <+> CREAT <+> APPEND) 0o644
110 | parameters {auto l : UVLoop}
111 | {auto has : Has UVError es}
113 | writeOutcome : (Outcome es () -> IO ()) -> Ptr Fs -> IO ()
114 | writeOutcome cb = fsOutcome (cb . ignore)
117 | writeBytesAt : File -> (offset : Int64) -> ByteString -> Async es ()
118 | writeBytesAt h offset bs =
119 | use1 (fromByteString bs) $
\cs =>
120 | uvAsync $
\cb => do
122 | (uv_fs_write l.loop h.file cs (cast bs.size) offset)
126 | writeBytes : File -> ByteString -> Async es ()
127 | writeBytes h = writeBytesAt h (-
1)
131 | bytesOut : ByteString -> Async es ()
132 | bytesOut = writeBytes stdout
136 | putOut : String -> Async es ()
137 | putOut = bytesOut . fromString
142 | putOutLn : String -> Async es ()
143 | putOutLn = putOut . (++ "\n")
148 | printOut : Show a => a -> Async es ()
149 | printOut = putOut . show
154 | printOutLn : Show a => a -> Async es ()
155 | printOutLn = putOutLn . show
159 | bytesErr : ByteString -> Async es ()
160 | bytesErr = writeBytes stderr
164 | putErr : String -> Async es ()
165 | putErr = bytesErr . fromString
170 | putErrLn : String -> Async es ()
171 | putErrLn = putErr . (++ "\n")
176 | printErr : Show a => a -> Async es ()
177 | printErr = putErr . show
182 | printErrLn : Show a => a -> Async es ()
183 | printErrLn = putErrLn . show
185 | parameters {auto l : UVLoop}
186 | {auto has : Has UVFileError es}
189 | writeFile : (path : String) -> Flags -> Mode -> ByteString -> Async es ()
190 | writeFile p fs m bs =
191 | use1 (fsOpen p (WRONLY <+> fs) m) $
\h =>
192 | toFileError (WriteError p) (writeBytes h bs)
195 | toFile : (path : String) -> ByteString -> Async es ()
196 | toFile p = writeFile p CREAT 0o644
199 | appendToFile : (path : String) -> ByteString -> Async es ()
200 | appendToFile p = writeFile p (CREAT <+> APPEND) 0o644
206 | parameters {auto l : UVLoop}
207 | {auto has : Has UVError es}
209 | readOutcome : Ptr Bits8 -> (Outcome es ByteString -> IO ()) -> Ptr Fs -> IO ()
210 | readOutcome cs cb =
211 | fsOutcome {es} $
\case
212 | Succeeded res => toByteString cs (cast res) >>= cb . Succeeded
213 | Error err => cb (Error err)
214 | Canceled => cb Canceled
217 | readBytes : File -> Bits32 -> Async es ByteString
219 | use1 (mallocPtrs Bits8 size) $
\cs =>
220 | uvAsync $
\cb => do
221 | async (uv_fs_read l.loop f.file cs size (-
1)) (readOutcome cs cb)
224 | readStdIn : Async es ByteString
225 | readStdIn = readBytes stdin 4096
227 | parameters {auto l : UVLoop}
228 | {auto has : Has UVFileError es}
231 | readFile : (path : String) -> Bits32 -> Async es ByteString
233 | use1 (readOpen path) $
\h =>
234 | toFileError (ReadError path) (readBytes h n)
240 | -> (ByteString -> Async es (Maybe b))
241 | -> Async es (Maybe b)
242 | streamFileUntil {b} path size fun = use1 (readOpen path) go
244 | go : File -> Async es (Maybe b)
246 | v <- toFileError (ReadError path) (readBytes h size)
249 | else fun v >>= maybe (go h) (pure . Just)
255 | -> (ByteString -> Async es ())
257 | streamFile path n fun =
258 | ignore $
streamFileUntil {b = ()} path n (\x => fun x $> Nothing)
264 | -> (List ByteString -> Async es (Maybe b))
265 | -> Async es (Maybe b)
266 | streamLinesUntil {b} path size fun = use1 (readOpen path) (go empty)
268 | go : ByteString -> File -> Async es (Maybe b)
270 | v <- toFileError (ReadError path) (readBytes h size)
272 | then fun $
if null rem then [] else [rem]
274 | let (ls,rem2) := accumLines rem v
275 | in fun ls >>= maybe (go rem2 h) (pure . Just)
281 | -> (List ByteString -> Async es ())
283 | streamLines path size fun =
284 | ignore $
streamLinesUntil {b = ()} path size (\xs => fun xs $> Nothing)
290 | -> (s -> ByteString -> s)
293 | foldBytes {s} path size acc ini =
294 | use1 (readOpen path) (go ini)
297 | go : s -> File -> Async es s
299 | v <- toFileError (ReadError path) (readBytes h size)
300 | if null v then pure cur else go (acc cur v) h
306 | -> (s -> ByteString -> s)
309 | foldLines {s} path size acc ini =
310 | term <$> foldBytes path size accB (empty,ini)
313 | term : (ByteString, s) -> s
314 | term (bs,s) = if null bs then s else acc s bs
316 | accB : (ByteString, s) -> ByteString -> (ByteString,s)
318 | let (ls,rem2) := accumLines rem v
319 | in (rem2, foldl acc cur ls)