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