1 /** 2 Date: 2015-2017, Joakim Brännström 3 License: MPL-2, Mozilla Public License 2.0 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 */ 6 module dextool.type; 7 8 @safe: 9 10 enum ExitStatusType { 11 Ok, 12 Errors 13 } 14 15 /** Prefix used for prepending generated code with a unique string to avoid 16 * name collisions. 17 * See specific functions for how it is used. 18 */ 19 struct StubPrefix { 20 string payload; 21 alias payload this; 22 } 23 24 /// Prefix used for prepending generated files. 25 struct FilePrefix { 26 string payload; 27 alias payload this; 28 } 29 30 struct MainFileName { 31 string payload; 32 alias payload this; 33 } 34 35 struct MainName { 36 string payload; 37 alias payload this; 38 } 39 40 struct MainNs { 41 string payload; 42 alias payload this; 43 } 44 45 struct MainInterface { 46 string payload; 47 alias payload this; 48 } 49 50 struct DextoolVersion { 51 string payload; 52 alias payload this; 53 } 54 55 struct CustomHeader { 56 string payload; 57 alias payload this; 58 } 59 60 /// The raw arguments from the command line. 61 struct RawCliArguments { 62 string[] payload; 63 alias payload this; 64 } 65 66 /// Flags to exclude from the flags passed on to the clang parser. 67 struct FilterClangFlag { 68 string payload; 69 alias payload this; 70 71 enum Kind { 72 exclude 73 } 74 75 Kind kind; 76 } 77 78 /// Used when writing data to files on the filesystem. 79 enum WriteStrategy { 80 overwrite, 81 skip 82 } 83 84 //TODO remove FileNames 85 struct FileNames { 86 string[] payload; 87 alias payload this; 88 } 89 90 struct InFiles { 91 string[] payload; 92 alias payload this; 93 } 94 95 /// No guarantee regarding the path. May be absolute, relative, contain a '~'. 96 /// The user of this type must do all the safety checks to ensure that the 97 /// datacontained in valid. 98 struct Path { 99 string payload; 100 alias payload this; 101 } 102 103 /// ditto 104 struct DirName { 105 Path payload; 106 alias payload this; 107 108 pure nothrow @nogc this(string p) { 109 payload = Path(p); 110 } 111 } 112 113 /// ditto 114 struct FileName { 115 pure @nogc nothrow: 116 117 Path payload; 118 alias payload this; 119 120 this(Path p) { 121 payload = p; 122 } 123 124 pure nothrow @nogc this(string p) { 125 payload = Path(p); 126 } 127 } 128 129 /** The path is guaranteed to be the absolute path. 130 * 131 * TODO: change to using Path instead of FileName. 132 * 133 * The user of the type has to make an explicit judgment when using the 134 * assignment operator. Either a `FileName` and then pay the cost of the path 135 * expansion or an absolute which is already assured to be _ok_. 136 * This divides the domain in two, one unchecked and one checked. 137 */ 138 struct AbsolutePath { 139 import std.path : expandTilde, buildNormalizedPath, absolutePath, 140 asNormalizedPath, asAbsolutePath; 141 142 Path payload; 143 alias payload this; 144 145 invariant { 146 import std.path : isAbsolute; 147 148 assert(payload.length == 0 || payload.isAbsolute); 149 } 150 151 immutable this(AbsolutePath p) { 152 this.payload = p.payload; 153 } 154 155 this(FileName p) { 156 auto p_expand = () @trusted{ return p.expandTilde; }(); 157 // the second buildNormalizedPath is needed to correctly resolve "." 158 // otherwise it is resolved to /foo/bar/. 159 payload = buildNormalizedPath(p_expand).absolutePath.buildNormalizedPath.Path; 160 } 161 162 /// Build the normalised path from workdir. 163 this(FileName p, DirName workdir) { 164 auto p_expand = () @trusted{ return p.expandTilde; }(); 165 auto workdir_expand = () @trusted{ return workdir.expandTilde; }(); 166 // the second buildNormalizedPath is needed to correctly resolve "." 167 // otherwise it is resolved to /foo/bar/. 168 payload = buildNormalizedPath(workdir_expand, p_expand).absolutePath 169 .buildNormalizedPath.Path; 170 } 171 172 void opAssign(FileName p) { 173 payload = typeof(this)(p).payload; 174 } 175 176 pure nothrow @nogc void opAssign(AbsolutePath p) { 177 payload = p.payload; 178 } 179 180 pure nothrow const @nogc FileName opCast(T : FileName)() { 181 return FileName(payload); 182 } 183 184 pure nothrow const @nogc string opCast(T : string)() { 185 return payload; 186 } 187 } 188 189 struct AbsoluteFileName { 190 AbsolutePath payload; 191 alias payload this; 192 193 pure nothrow @nogc this(AbsolutePath p) { 194 payload = p; 195 } 196 } 197 198 struct AbsoluteDirectory { 199 AbsolutePath payload; 200 alias payload this; 201 202 pure nothrow @nogc this(AbsolutePath p) { 203 payload = p; 204 } 205 } 206 207 /** During construction checks that the file exists on the filesystem. 208 * 209 * If it doesn't exist it will throw an Exception. 210 */ 211 struct Exists(T) { 212 AbsolutePath payload; 213 alias payload this; 214 215 this(AbsolutePath p) { 216 import std.file : exists, FileException; 217 218 if (!exists(p)) { 219 throw new FileException("File do not exist: " ~ cast(string) p); 220 } 221 222 payload = p; 223 } 224 225 this(Exists!T p) { 226 payload = p.payload; 227 } 228 229 void opAssign(Exists!T p) pure nothrow @nogc { 230 payload = p; 231 } 232 } 233 234 auto makeExists(T)(T p) { 235 return Exists!T(p); 236 } 237 238 @("shall always be the absolute path") 239 unittest { 240 import std.algorithm : canFind; 241 import std.path; 242 import unit_threaded; 243 244 AbsolutePath(FileName("~/foo")).canFind('~').shouldEqual(false); 245 AbsolutePath(FileName("foo")).isAbsolute.shouldEqual(true); 246 } 247 248 @("shall expand . without any trailing /.") 249 unittest { 250 import std.algorithm : canFind; 251 import unit_threaded; 252 253 AbsolutePath(FileName(".")).canFind('.').shouldBeFalse; 254 AbsolutePath(FileName("."), DirName(".")).canFind('.').shouldBeFalse; 255 } 256 257 @("shall be an instantiation of Exists") 258 nothrow unittest { 259 // the file is not expected to exist. 260 261 try { 262 auto p = makeExists(AbsolutePath(FileName("foo"))); 263 } 264 catch (Exception e) { 265 } 266 }