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