@@ -68,13 +68,13 @@ typealias IPv4CIDRString = String(matches(Regex(#"\#(net.ipv4String)/\d{1,2}"#))
68
68
typealias IPv6CIDRString = String(matches(Regex(#"\#(net.ipv6String) / \d{1 ,3 }"#)))
69
69
70
70
/// Creates an [IPAddress] from an [IPAddressString].
71
- const function IP (ip : IPAddressString ): IPAddress =
71
+ function IP (ip : IPAddressString ): IPAddress =
72
72
if (ip is IPv6AddressString) IPv6Address(ip)
73
73
else if (ip is IPv4AddressString) IPv4Address(ip)
74
74
else throw ("Invalid IP: \(ip) " )
75
75
76
76
/// Creates an [IPv4Address] from an [IPv4AddressString].
77
- const function IPv4Address (ip : IPv4AddressString ): IPv4Address = new {
77
+ function IPv4Address (ip : IPv4AddressString ): IPv4Address = new {
78
78
local parts = ip.split("." )
79
79
repr = parts[0 ].toInt().shl(24 )
80
80
.or(parts[1 ].toInt().shl(16 ))
@@ -98,7 +98,10 @@ class IPv4Address {
98
98
function reverse (): String = new IPv4Network { base = self; prefix = self.bitWidth }.reverse()
99
99
100
100
/// return the ip address immediately after this one
101
- function next (): IPv4Address = new { repr = self.repr + 1 }
101
+ function next (): IPv4Address = add(1 )
102
+
103
+ /// return the ip address [n] after this one
104
+ function add (n : UInt32 ): IPv4Address = new { repr = self.repr + n }
102
105
103
106
function toString (): IPv4AddressString = new Listing<String> {
104
107
repr.ushr(24 ).and(math.maxUInt8).toString()
@@ -109,7 +112,7 @@ class IPv4Address {
109
112
}
110
113
111
114
/// Creates an [IPv6Address] from an [IPv6AddressString].
112
- const function IPv6Address (ip : IPv6AddressString ): IPv6Address =
115
+ function IPv6Address (ip : IPv6AddressString ): IPv6Address =
113
116
let (_ip = expandIPv6AddressString(ip).toLowerCase().split(":" ))
114
117
new {
115
118
repr = u128.UInt128(
@@ -144,7 +147,10 @@ class IPv6Address {
144
147
function reverse (): String = new IPv6Network { base = self; prefix = self.bitWidth }.reverse()
145
148
146
149
/// return the ip address immediately after this one
147
- function next (): IPv6Address = new { repr = self.repr.add(u128.one) }
150
+ function next (): IPv6Address = add(1 )
151
+
152
+ /// return the ip address [n] after this one
153
+ function add (n : UInt32 ): IPv6Address = new { repr = self.repr.add(u128.UInt128(0 , 0 , 0 , n)) }
148
154
149
155
function toString (): IPv6AddressString = expandIPv6AddressString(new Listing {
150
156
repr.hihi.ushr(16 ).toRadixString(16 )
@@ -159,13 +165,13 @@ class IPv6Address {
159
165
}
160
166
161
167
/// Creates an [IPNetwork] from an IPv4 or IPv6 CIDR block string
162
- const function IPNetwork (cidr : String ): IPNetwork =
168
+ function IPNetwork (cidr : String ): IPNetwork =
163
169
if (cidr.split("/" ).first is IPv4AddressString) IPv4Network(cidr)
164
170
else if (cidr.split("/" ).first is IPv6AddressString) IPv6Network(cidr)
165
171
else throw ("Invalid network CIDR: \(cidr) " )
166
172
167
173
/// Creates an [IPv4Network] from an IPv4 CIDR block string
168
- const function IPv4Network (cidr : String ): IPv4Network = new {
174
+ function IPv4Network (cidr : String ): IPv4Network = new {
169
175
base = IPv4Address(cidr.split("/" ).first)
170
176
prefix = cidr.split("/" ).last.toInt()
171
177
}
@@ -209,14 +215,14 @@ class IPv4Network {
209
215
}
210
216
211
217
/// Produces a listing of IPv4 addresses between [start] and [end], inclusive.
212
- const function IPv4Range (start : IPv4Address , end : IPv4Address ): Listing<IPv4Address> = new {
218
+ function IPv4Range (start : IPv4Address , end : IPv4Address ): Listing<IPv4Address> = new {
213
219
for (ipu in IntSeq(start.repr, end.repr)) {
214
220
new { repr = ipu }
215
221
}
216
222
}
217
223
218
224
/// Creates an [IPv6Network] from an IPv6 CIDR block string
219
- const function IPv6Network (cidr : String ): IPv6Network = new {
225
+ function IPv6Network (cidr : String ): IPv6Network = new {
220
226
base = IPv6Address(cidr.split("/" ).first)
221
227
prefix = cidr.split("/" ).last.toInt()
222
228
}
@@ -257,7 +263,7 @@ class IPv6Network {
257
263
}
258
264
259
265
/// Produces a listing of IPv6 addresses between [start] and [end], inclusive.
260
- const function IPv6Range (start : IPv6Address , end : IPv6Address ): Listing<IPv6Address> = new {
266
+ function IPv6Range (start : IPv6Address , end : IPv6Address ): Listing<IPv6Address> = new {
261
267
for (ipu in start.repr.seq(end.repr)) {
262
268
new { repr = ipu }
263
269
}
@@ -284,22 +290,51 @@ const function compressIPv6AddressString(ip: IPv6AddressString): IPv6AddressStri
284
290
).join(":" ))
285
291
trimmed.replaceFirst(Regex("(:|^)(0:)+0(:|$)" ), "::" )
286
292
293
+ function MACAddress (mac : MACAddressString ): MACAddress = new {
294
+ repr = mac.split(Regex("[.:-]" )).map((octet) -> parseHexOctet(octet))
295
+ }
296
+
297
+ class MACAddress {
298
+ hidden repr : List<UInt8>(length == 6)
299
+
300
+ local self = this
301
+
302
+ function toString (): MACAddressString = repr.map((octet) -> octet.toRadixString(16 ).padStart(2 , "0" )).join(":" )
303
+
304
+ function eui64 (addr : IPv6Address ): IPv6Address = new {
305
+ repr = u128.UInt128(
306
+ addr.repr.hihi,
307
+ addr.repr.hilo,
308
+ uint32FromBytes(self.repr[0 ].xor(0x02 ), self.repr[1 ], self.repr[2 ], 0xff ),
309
+ uint32FromBytes(0xfe , self.repr[3 ], self.repr[4 ], self.repr[5 ])
310
+ )
311
+ }
312
+ }
313
+
287
314
/// parseHex tranforms a single hexadecimal character into its unsigned integer representation.
288
- const function parseHex (digit : Char ): UInt8 =
315
+ function parseHex (digit : Char ): UInt8 =
289
316
let (d = digit.toLowerCase())
290
317
"0123456789abcdef" .chars.findIndexOrNull((it) -> it == d) ??
291
318
throw ("Unrecognized hex digit: \(d) " )
292
319
320
+ /// parseHexOctet tranforms a two hexadecimal characters into its unsigned integer representation.
321
+ function parseHexOctet (octet : String(length == 2) ): UInt8 = byteLut[octet.toLowerCase()]
322
+
293
323
/// parseHex32 transforms an 8 character hexidecimal string into its UInt32 representation.
294
- const function parseHex32 (s : String(this. length == 8) ): UInt32 =
324
+ function parseHex32 (s : String(length == 8) ): UInt32 =
295
325
IntSeq(0 , 7 )
296
326
.step(2 )
297
327
.map((it) -> s.substring(it, it + 2 ))
298
- .fold(0 , (acc, it) -> acc.shl(8 ) + byteLut[it.toLowerCase()] )
328
+ .fold(0 , (acc, it) -> acc.shl(8 ) + parseHexOctet(it) )
299
329
330
+ /// byteLut is a lookup table mapping a string of two lowercase hex digits (zero-padded) to the UInt8 value.
300
331
const local byteLut = IntSeq(0 , 255 ).map((it) -> it).toMap((it) -> it.toRadixString(16 ).padStart(2 , "0" ), (it) -> it)
301
332
302
333
/// mask32Hi generates a mask of 1s in the top [prefix] bits of a [UInt32].
303
- const function mask32Hi (prefix : UInt(this. isBetween(0, 32) )): UInt32 = math.maxUInt32.ushr(32 - prefix).shl(32 - prefix)
334
+ const function mask32Hi (prefix : UInt(isBetween(0, 32) )): UInt32 = math.maxUInt32.ushr(32 - prefix).shl(32 - prefix)
304
335
/// mask32Lo generates a mask of 1s in the bottom [suffix] bits of a [UInt32].
305
- const function mask32Lo (suffix : UInt(this.isBetween(0, 32) )): UInt32 = math.maxUInt32.ushr(32 - suffix)
336
+ const function mask32Lo (suffix : UInt(isBetween(0, 32) )): UInt32 = math.maxUInt32.ushr(32 - suffix)
337
+
338
+ /// uint32FromBytes constructs a [UInt32] from four [UInt8] values.
339
+ const function uint32FromBytes (hihi : UInt8 , hilo : UInt8 , lohi : UInt8 , lolo : UInt8 ): UInt32 =
340
+ hihi.shl(24 ).or(hilo.shl(16 )).or(lohi.shl(8 )).or(lolo)
0 commit comments