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 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
|
## Setting up the environment
```ocaml
# #require "eio_main";;
# #require "eio.mock";;
```
```ocaml
open Eio.Std
let run fn =
Eio_main.run @@ fun _ ->
fn ()
let mock_source =
let module X = struct
type t = Cstruct.t list ref
let read_methods = []
let single_read t buf =
match !t with
| [] -> raise End_of_file
| x :: xs ->
let len = min (Cstruct.length buf) (Cstruct.length x) in
Cstruct.blit x 0 buf 0 len;
t := Cstruct.shiftv (x :: xs) len;
len
end in
let ops = Eio.Flow.Pi.source (module X) in
fun items -> Eio.Resource.T (ref items, ops)
```
## read_exact
```ocaml
# run @@ fun () ->
let data = List.map Cstruct.of_string ["foo"; "bar"] in
let test n =
let buf = Cstruct.create n in
Eio.Flow.read_exact (mock_source data) buf;
traceln "Got %S" (Cstruct.to_string buf)
in
test 0;
test 3;
test 5;
test 6;
test 7;;
+Got ""
+Got "foo"
+Got "fooba"
+Got "foobar"
Exception: End_of_file.
```
## copy
```ocaml
# run @@ fun () ->
let src = Eio_mock.Flow.make "src" in
let dst = Eio_mock.Flow.make "dst" in
Eio_mock.Flow.on_read src [`Return "foo"; `Return "bar"];
Eio.Flow.copy src dst;;
+src: read "foo"
+dst: wrote "foo"
+src: read "bar"
+dst: wrote "bar"
- : unit = ()
```
Copying from a string src:
```ocaml
# run @@ fun () ->
let src = Eio.Flow.string_source "foobar" in
let dst = Eio_mock.Flow.make "dst" in
Eio_mock.Flow.on_copy_bytes dst [`Return 3; `Return 5];
Eio.Flow.copy src dst;;
+dst: wrote "foo"
+dst: wrote "bar"
- : unit = ()
```
Copying from src using a plain buffer (the default):
```ocaml
# run @@ fun () ->
let src = Eio.Flow.cstruct_source [Cstruct.of_string "foobar"] in
let dst = Eio_mock.Flow.make "dst" in
Eio_mock.Flow.on_copy_bytes dst [`Return 3; `Return 5];
Eio.Flow.copy src dst;;
+dst: wrote "foo"
+dst: wrote "bar"
- : unit = ()
```
Copying from src using `Read_source_buffer`:
```ocaml
# run @@ fun () ->
let src = Eio.Flow.cstruct_source [Cstruct.of_string "foobar"] in
let dst = Eio_mock.Flow.make "dst" in
Eio_mock.Flow.set_copy_method dst `Read_source_buffer;
Eio_mock.Flow.on_copy_bytes dst [`Return 3; `Return 5];
Eio.Flow.copy src dst;;
+dst: wrote (rsb) ["foo"]
+dst: wrote (rsb) ["bar"]
- : unit = ()
```
## read_all
```ocaml
# run @@ fun () ->
let each = String.init 256 Char.chr in
let data = List.init 40 (fun _ -> Cstruct.of_string each) in
let got = Eio.Flow.read_all (mock_source data) in
traceln "Input length: %d\nOutput length: %d\nEqual: %b"
(Cstruct.lenv data) (String.length got) (String.equal got (Cstruct.copyv data));
;;
+Input length: 10240
+Output length: 10240
+Equal: true
- : unit = ()
```
## write
```ocaml
# run @@ fun () ->
let dst = Eio_mock.Flow.make "dst" in
Eio_mock.Flow.on_copy_bytes dst [`Return 6];
Eio.Flow.write dst [Cstruct.of_string "foobar"];;
+dst: wrote "foobar"
- : unit = ()
```
## Pipes
Writing to and reading from a pipe.
```ocaml
# Eio_main.run @@ fun env ->
Switch.run @@ fun sw ->
let r, w = Eio_unix.pipe sw in
let msg = "Hello, world" in
Eio.Fiber.both
(fun () ->
let buf = Cstruct.create (String.length msg) in
let () = Eio.Flow.read_exact r buf in
traceln "Got: %s" (Cstruct.to_string buf)
)
(fun () ->
Eio.Flow.copy_string msg w;
Eio.Flow.close w
);;
+Got: Hello, world
- : unit = ()
```
Make sure we don't crash on SIGPIPE:
```ocaml
# Eio_main.run @@ fun env ->
Switch.run @@ fun sw ->
let r, w = Eio_unix.pipe sw in
Eio.Flow.close r;
try
Eio.Flow.copy_string "Test" w;
assert false
with Eio.Io (Eio.Net.E Connection_reset _, _) ->
traceln "Connection_reset (good)";;
+Connection_reset (good)
- : unit = ()
```
## IO_MAX
Sending a very long vector over a flow should just send it in chunks, not fail:
```ocaml
# Eio_main.run @@ fun env ->
Switch.run @@ fun sw ->
let r, w = Eio_unix.pipe sw in
let a = Cstruct.of_string "abc" in
let vecs = List.init 10_000 (Fun.const a) in
Fiber.both
(fun () ->
Eio.Flow.write w vecs;
Eio.Flow.close w
)
(fun () ->
let got = Eio.Flow.read_all r in
traceln "Read %d bytes" (String.length got);
assert (got = Cstruct.to_string (Cstruct.concat vecs))
)
+Read 30000 bytes
- : unit = ()
```
## Starvation
Even if a fiber is already ready to run, we still perform IO from time to time:
```ocaml
# run @@ fun _ ->
Switch.run @@ fun sw ->
let r, w = Eio_unix.pipe sw in
let rec spin () = Fiber.yield (); spin () in
Fiber.fork_daemon ~sw spin;
Fiber.both
(fun () ->
let buf = Cstruct.create 3 in
Eio.Flow.read_exact r buf;
traceln "Got %S" (Cstruct.to_string buf)
)
(fun () ->
Eio.Flow.write w [Cstruct.of_string "msg"]
)
+Got "msg"
- : unit = ()
```
|