1 module nxt.string_ex;
2 
3 /** Call `dg` with `src` as input.
4  *
5  * See_Also: https://youtu.be/V6KFtzF2Hx8
6  */
7 auto toCStringThen(alias dg, uint smallSize = 512)(const(char)[] src)
8 if (is(typeof(dg((char[]).init)))) // TODO: assert that dg takes its parameter by scope
9 {
10     import core.memory : pureMalloc, pureFree;
11     const srcLength = src.length + 1;
12     char[smallSize] stackBuf = void;
13 
14 	const useHeap = srcLength > stackBuf.length;
15 	scope char* ptr;
16 	() @trusted {
17 		if (useHeap)
18 			ptr = cast(typeof(ptr))pureMalloc(src.length + 1);
19 		else
20 			ptr = stackBuf.ptr;
21 		ptr[0 .. src.length] = src[];
22 		ptr[src.length] = '\0';
23 	} ();
24 	scope(exit)
25 		if (useHeap)
26 			() @trusted { pureFree(ptr); } ();
27 
28 	scope char[] buf;
29 	() @trusted {
30 		buf = ptr[0 .. srcLength];
31 	} ();
32 
33     return dg(buf);
34 }
35 
36 ///
37 @safe pure nothrow @nogc unittest
38 {
39 	enum smallSize = 4;
40 	const src = "42";
41 	scope char[src.length + 1] y;
42 	@safe void f(in char[] x) { y = x; }
43 	src.toCStringThen!(f, smallSize)(); // uses stack
44 	assert(y[0 .. $ - 1] == src);
45 	assert(y[$ - 1 .. $] == "\0");
46 }
47 
48 ///
49 @safe pure nothrow @nogc unittest
50 {
51 	enum smallSize = 4;
52 	const src = "4200";
53 	scope char[src.length + 1] y;
54 	@safe void f(in char[] x) { y = x; }
55 	src.toCStringThen!(f, smallSize)(); // uses heap
56 	assert(y[0 .. $ - 1] == src);
57 	assert(y[$ - 1 .. $] == "\0");
58 }
59 
60 /** https://discord.com/channels/242094594181955585/625407836473524246/1018276401142575188
61  */
62 struct Stringz
63 {
64     this(string s) @safe pure nothrow @nogc
65 	in (s.length >= 1 &&
66 		s[$ - 1] == '\0')
67 	{
68         this._data = s[0 .. $ - 1];
69     }
70     string toString() const @property @safe pure nothrow @nogc { return _data; }
71     private string _data;
72 }
73 
74 enum stringz(string literal) = () {
75     Stringz result;
76     result._data = literal; // ok - literals are 0-terminated
77     return result;
78 }();
79 
80 ///
81 @safe pure unittest {
82 	enum _ = stringz!("42");
83 	assert(_.toString == "42");
84 }