1 /**
2  * Copyright: Copyright Jason White, 2014-2016
3  * License:   $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4  * Authors:   Jason White
5  */
6 module io.stream.traits;
7 
8 import io.stream.types : From;
9 
10 /**
11  * Checks if a type is a source. A source is a stream that can be read from and
12  * must define the member function $(D read). The stream can be either a class
13  * or a struct.
14  */
15 enum isSource(Stream) =
16     is(typeof({
17         Stream s = void;
18         ubyte[] buf;
19         ulong n = s.read(buf);
20     }));
21 
22 unittest
23 {
24     static struct A {}
25     static assert(!isSource!A);
26 
27     static struct B
28     {
29         size_t read(ubyte[] buf) { return buf.length; }
30     }
31 
32     static assert(isSource!B);
33 
34     static struct C
35     {
36         void read() {}
37     }
38 
39     static assert(!isSource!C);
40 }
41 
42 /**
43  * Checks if a type is a sink. A sink is a stream that can be written to and must
44  * define the member function $(D write). The stream can be either a class or a
45  * struct.
46  */
47 enum isSink(Stream) =
48     is(typeof({
49         Stream s = void;
50         immutable ubyte[] data;
51         ulong n = s.write(data);
52     }));
53 
54 unittest
55 {
56     static struct A {}
57     static assert(!isSink!A);
58 
59     static struct B
60     {
61         size_t write(in ubyte[] data) { return 0; }
62     }
63 
64     static assert(isSink!B);
65 
66     static struct C
67     {
68         void write() {}
69     }
70 
71     static assert(!isSink!C);
72 }
73 
74 /**
75  * Checks if a type is seekable. A seekable stream must define the member
76  * function $(D seek). The stream can be either a class or a struct.
77  */
78 enum isSeekable(Stream) =
79     is(typeof({
80         Stream s = void;
81         auto pos = s.seekTo(0, From.start);
82     }));
83 
84 unittest
85 {
86     static struct A {}
87     static assert(!isSeekable!A);
88 
89     static struct B {
90         long seekTo(long offset, From from) { return 0; }
91     }
92     static assert(isSeekable!B);
93 
94     static struct C {
95         // Should return the current position.
96         void seekTo(long offset, From from) {}
97     }
98     static assert(!isSeekable!C);
99 }
100 
101 /**
102  * Checks if the type is both a source and a sink.
103  */
104 enum isSourceSink(Stream) = isSource!Stream && isSink!Stream;
105 
106 unittest
107 {
108     static struct A
109     {
110         size_t write(in ubyte[] data) { return 0; }
111     }
112 
113     static assert(!isSourceSink!A);
114 
115     static struct B
116     {
117         size_t write(in ubyte[] data) { return 0; }
118         size_t read(ubyte[] buf) { return buf.length; }
119     }
120 
121     static assert(isSourceSink!B);
122 }
123 
124 /**
125  * Checks if the type is either a source or a sink (i.e., a stream).
126  */
127 enum isStream(Stream) = isSource!Stream || isSink!Stream;
128 
129 unittest
130 {
131     static struct A
132     {
133         size_t write(in ubyte[] data) { return 0; }
134     }
135 
136     static assert(isStream!A);
137 
138     static struct B
139     {
140         size_t read(ubyte[] buf) { return buf.length; }
141     }
142 
143     static assert(isStream!B);
144 
145     static struct C
146     {
147         long seekTo(long offset, From from) { return 0; }
148     }
149 
150     static assert(!isStream!C);
151 }