1 /**
2     Endianess Helpers
3 
4     Copyright:
5         Copyright © 2023-2025, Kitsunebi Games
6         Copyright © 2023-2025, Inochi2D Project
7     
8     License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9     Authors:   Luna Nielsen
10 */
11 module nulib.memory.endian;
12 import numem.core.traits;
13 
14 /**
15     Endianness
16 */
17 enum Endianess {
18     bigEndian = 0,
19     littleEndian = 1
20 }
21 
22 /**
23     The endianness of the target system being compiled for.
24 */
25 version(BigEndian) enum NATIVE_ENDIAN = Endianess.bigEndian;
26 else enum NATIVE_ENDIAN = Endianess.littleEndian;
27 
28 /**
29     The opposite endianness of what the system being compiled for
30     has.
31 */
32 enum Endianess ALT_ENDIAN = cast(Endianess)!NATIVE_ENDIAN;
33 
34 /**
35     Network order endianness.
36 
37     Networking gear generally uses a big-endian memory order.
38 */
39 enum Endianess NETWORK_ORDER = Endianess.bigEndian;
40 
41 /**
42     Flips the endianness of the given value.
43 
44     Params:
45         in_ = the bytes to flip.
46 
47     Returns:
48         The input with the byte order reversed.
49 */
50 T nu_flip_bytes(T)(T in_) @system @nogc nothrow {
51     ubyte swapTmp; // temp byte for swapping.
52 
53     ubyte[T.sizeof] bytes = *(cast(ubyte[T.sizeof]*)&in_);
54     static foreach(i; 0..T.sizeof/2) {
55         
56         swapTmp = bytes[i];
57         bytes[i] = bytes[$-(i+1)];
58         bytes[$-(i+1)] = swapTmp;
59     }
60     return *(cast(T*)&bytes);
61 }
62 
63 /**
64     Converts big endian type to system endianness.
65 */
66 T nu_betoh(T)(T in_) @trusted @nogc nothrow {
67     return etoh!(T, Endianess.bigEndian)(in_);
68 }
69 
70 /**
71     Converts a range of big endian values to the system
72     endianness.
73 
74     Params:
75         in_ = the range to flip the individual values within.
76 
77     Returns:
78         A slice of the input, pointing to the same memory.
79 */
80 T[] nu_betoh(T)(T[] in_) @trusted @nogc nothrow {
81     foreach_reverse(ref element; in_)
82         element = nu_betoh(element);
83     
84     return in_;
85 }
86 
87 /**
88     Converts little endian type to system endianness.
89 */
90 T nu_letoh(T)(T in_) @trusted @nogc nothrow {
91     return etoh!(T, Endianess.littleEndian)(in_);
92 }
93 
94 /**
95     Converts a slice of little endian values to the system
96     endianness.
97 
98     Params:
99         in_ = the range to flip the individual values within.
100 
101     Returns:
102         A slice of the input, pointing to the same memory.
103 */
104 T[] nu_letoh(T)(T[] in_) @trusted @nogc nothrow {
105     foreach_reverse(ref element; in_)
106         element = nu_letoh(element);
107     
108     return in_;
109 }
110 
111 /**
112     Converts bytes between system and the given endianness.
113 
114     This essentially flips the byte-order within the type if
115     the given endianness does not match the system endiannes.
116 
117     Params:
118         in_ = the range to flip the individual values within.
119         endian = The endianness to convert between.
120 
121     Returns:
122         A slice of the input, pointing to the same memory.
123 */
124 T[] nu_etoh(T)(T[] in_, Endianess endian) @trusted @nogc nothrow {
125     if (endian != NATIVE_ENDIAN) 
126         foreach_reverse(ref element; in_)
127             element = nu_flip_bytes!T(element);
128     
129     return in_;
130 }
131 
132 /**
133     Converts bytes between system and the given endianness.
134 
135     This essentially flips the byte-order within the type if
136     the given endianness does not match the system endiannes.
137 
138     Params:
139         in_ = the range to flip the individual values within.
140 
141     Returns:
142         A slice of the input, pointing to the same memory.
143 */
144 T[] nu_etoh(T, Endianess endian)(T[] in_) @trusted @nogc nothrow {
145     static if (endian != NATIVE_ENDIAN) 
146         foreach_reverse(ref element; in_)
147             element = nu_flip_bytes!T(element);
148     
149     return in_;
150 }
151 
152 /**
153     Converts bytes between system and the given endianness.
154 
155     This essentially flips the byte-order within the type if
156     the given endianness does not match the system endiannes.
157 
158     Params:
159         in_ = The value to potentially flip.
160 
161     Returns:
162         If $(D endian) does not match $(D NATIVE_ENDIAN),
163         returns the input with the byte order reversed,
164         otherwise returns the original value.
165 */
166 T nu_etoh(T, Endianess endian)(T in_) @system @nogc nothrow {
167     static if (endian != NATIVE_ENDIAN)
168         return nu_flip_bytes!T(in_);
169     else
170         return in_;
171 }
172 
173 /**
174     Converts bytes between system and the given endianness.
175 
176     This essentially flips the byte-order within the type if
177     the given endianness does not match the system endiannes.
178 
179     Params:
180         in_ = The value to potentially flip.
181         endian = The endianness to convert between.
182 
183     Returns:
184         If $(D endian) does not match $(D NATIVE_ENDIAN),
185         returns the input with the byte order reversed,
186         otherwise returns the original value.
187 */
188 T nu_etoh(T)(T in_, Endianess endian) @system @nogc nothrow {
189     if (endian != NATIVE_ENDIAN)
190         return nu_flip_bytes!T(in_);
191     else
192         return in_;
193 }
194 
195 /**
196     Converts between network order endianness and the system endiannes.
197 
198     Params:
199         in_ = The value to potentially flip.
200 
201     Returns:
202         If $(D NATIVE_ENDIAN) does not match $(D NETWORK_ORDER),
203         returns the input with the byte order reversed,
204         otherwise returns the original value.
205 */
206 pragma(inline, true)
207 T nu_ntoh(T)(T in_) @trusted @nogc nothrow
208 if (__traits(isScalar, T)) {
209     return nu_etoh!(T, NETWORK_ORDER)(in_);
210 }