1 /** File I/O pipes.
2  *
3  *  Authors: $(LINK2 https://github.com/epi, Adrian Matoga)
4  *  Copyright: © 2016 Adrian Matoga
5  *  License: $(LINK2 http://www.boost.org/users/license.html, BSL-1.0).
6  */
7 module flod.file;
8 
9 import std.stdio : File;
10 
11 import flod.traits : source, sink, Method;
12 import flod.pipeline : isSchema;
13 
14 @source!ubyte(Method.pull)
15 private struct FileReader(alias Context, A...) {
16 	mixin Context!A;
17 private:
18 	File file;
19 
20 public:
21 	this(in char[] name) { file = File(name, "rb"); }
22 
23 	size_t pull()(ubyte[] buf)
24 	{
25 		return file.rawRead(buf).length;
26 	}
27 }
28 
29 /// Returns a pipe that reads `ubyte`s from file `name`.
30 auto read(in char[] name)
31 {
32 	import flod.pipeline : pipe;
33 	return pipe!FileReader(name);
34 }
35 
36 @sink(Method.push)
37 private struct FileWriter(alias Context, A...) {
38 	mixin Context!A;
39 private:
40 	File file;
41 
42 public:
43 	this(File file) { this.file = file; }
44 	this(in char[] name) { file = File(name, "wb"); }
45 
46 	size_t push(const(InputElementType)[] buf)
47 	{
48 		file.rawWrite(buf);
49 		return buf.length;
50 	}
51 }
52 
53 /// Returns a pipe that writes to file `name`.
54 auto write(S)(S schema, in char[] name)
55 	if (isSchema!S)
56 {
57 	import flod.pipeline : pipe;
58 	return schema.pipe!FileWriter(name);
59 }
60 
61 /// Returns a pipe that writes to file `file`.
62 auto write(S)(S schema, File file)
63 	if (isSchema!S)
64 {
65 	import flod.pipeline : pipe;
66 	return schema.pipe!FileWriter(file);
67 }
68 
69 unittest {
70 	import std.file : remove, exists, stdread = read;
71 	scope(exit) {
72 		if (exists(".test"))
73 			remove(".test");
74 	}
75 	auto f1 = stdread("/etc/passwd");
76 
77 	read("/etc/passwd").write(".test");
78 	auto f2 = stdread(".test");
79 	assert(f1 == f2);
80 
81 	read("/etc/passwd").write(File(".test", "wb"));
82 	auto f3 = stdread(".test");
83 	assert(f1 == f3);
84 }