/*
Copyright (c) 2025 WuJingrun(吴京润)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package f_util
import std.convert.Parsable
import std.fs.{File, Directory, OpenMode}
import std.io.{SeekPosition, StringReader}
import std.math.numeric.BigInt
import std.sync.{AtomicUInt16, AtomicInt64, Mutex}
import std.time.{TimeZone, DateTime}
import stdx.crypto.crypto.*
import stdx.crypto.digest.{MD5, SHA1}
import f_base.{HashBuilder, StringGenerator}
import f_data.*
import f_data.exception.DataException
import f_exception.UnreachableException
import f_random.*
import f_util.exception.UUIDException
/**
* reference https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-00.html
*/
public struct UUID <: Hashable & Comparable<UUID> & ToString & Parsable<UUID> & DataParsable<UUID> & DataFields<UUID> {
private let h: Int64
UUID(private let values!: Array<Byte> = Array<Byte>(16, repeat: 0)) {
h = HashBuilder().append<Byte, Array<Byte>>(values).build()
}
public func toData(): Data{
toString().toData()
}
public static func tryFromData(data: Data, flag: DataConversionFlag): Any {
match(data){
case x: DataString =>
match(UUID.tryParse(x.data)){
case Some(x) => x
case _ where (flag & IGNORE_FIELD_NOT_CONVERTABLE) > 0 => None<UUID>
case _ => throw DataException('data ${data} which type is ${TypeInfo.of(data)} cannot converted to UUID')
}
case _ where (flag & IGNORE_NONE) > 0 || (flag & IGNORE_FIELD_TYPE_NOT_MATCH) > 0 => None<UUID>
case _ => throw DataException('data ${data} which type is ${TypeInfo.of(data)} cannot converted to UUID')
}
}
public func hashCode(): Int64 {
h
}
public operator func ==(other: UUID): Bool {
h == other.h && values == other.values
}
public operator func !=(other: UUID): Bool {
!(this == other)
}
public func compare(other: UUID): Ordering {
let v1 = this.values
let v2 = other.values
for (i in 0..16) {
match (v1[i].compare(v2[i])) {
case EQ => continue
case x => return x
}
}
return EQ
}
public static let Nil = UUID()
public static let Max = UUID(values: Array<Byte>(16, repeat: 0xff))
private static let hex = [r'0', r'1', r'2', r'3', r'4', r'5', r'6', r'7', r'8', r'9', r'a', r'b', r'c', r'd', r'e',
r'f']
public func toString(): String {
toString(true)
}
private func toString(withDash: Bool) {
//00 00 00 00-00 00-00 00-00 00-00 00 00 00 00 00
//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
let builder = StringGenerator()
for (i in 0..values.size) {
let v = values[i]
builder.append(hex[Int64((v >> 4) & 0xf)])
builder.append(hex[Int64(v & 0xf)])
if (withDash && (i == 3 || i == 5 || i == 7 || i == 9)) {
builder.append(r'-')
}
}
builder.toString()
}
public func toString(radix: Int64) {
if (radix == 16) {
return toString(false)
}
BigInt(true, values).toString(radix: radix)
}
public func toHexString() {
toString(false)
}
public prop version: Int64 {
get() {
Int64(values[6] >> 4)
}
}
public prop timestampNanos: Int64 {
get() {
var n = 0
match (version) {
case 1 =>
n |= Int64(values[6] & 0xf)
n <<= 8
n |= Int64(values[7])
n <<= 8
n |= Int64(values[4])
n <<= 8
n |= Int64(values[5])
n <<= 8
n |= Int64(values[0])
n <<= 8
n |= Int64(values[1])
n <<= 8
n |= Int64(values[2])
n <<= 8
n |= Int64(values[3])
case 6 =>
n |= Int64(values[0])
n <<= 8
n |= Int64(values[1])
n <<= 8
n |= Int64(values[2])
n <<= 8
n |= Int64(values[3])
n <<= 8
n |= Int64(values[4])
n <<= 8
n |= Int64(values[5])
n <<= 8
n |= Int64(values[6] & 0xf)
n <<= 8
n |= Int64(values[7])
case 7 =>
n |= Int64(values[0])
n <<= 8
n |= Int64(values[1])
n <<= 8
n |= Int64(values[2])
n <<= 8
n |= Int64(values[3])
n <<= 8
n |= Int64(values[4])
n <<= 8
n |= Int64(values[5])
n <<= 8
n |= Int64(values[6] & 0xf)
n <<= 8
n |= Int64(values[7])
n * 10000
case _ => 0
}
n * 100
}
}
public prop timestamp: DateTime {
get() {
let v = version
match (v) {
case 7 => DateTime.UnixEpoch
case 1 | 6 => TimestampSequenceBuilder.timeStart
case _ => throw UUIDException("current version is without timestamp and version is ${v}")
} + timestampNanos * Duration.nanosecond
}
}
public prop variant: Int64 {
get() {
Int64(values[8] >> 6)
}
}
public static func parse(uuid: String): UUID {
tryParse(uuid).getOrThrow {IllegalArgumentException("error uuid ${uuid}")}
}
public static func tryParse(uuid: String): ?UUID {
if (uuid.size != 36) {
return None<UUID>
}
func doParse(c: Rune, i: Int64): UInt8 {
match (c) {
case r'0' => 0x0
case r'1' => 0x1
case r'2' => 0x2
case r'3' => 0x3
case r'4' => 0x4
case r'5' => 0x5
case r'6' => 0x6
case r'7' => 0x7
case r'8' => 0x8
case r'9' => 0x9
case r'a' => 0xa
case r'b' => 0xb
case r'c' => 0xc
case r'd' => 0xd
case r'e' => 0xe
case r'f' => 0xf
case r'-' where i == 4 || i == 6 || i == 8 || i == 10 => //i是按解析后的字节数组的索引
//00 00 00 00-00 00-00 00-00 00-00 00 00 00 00 00
//0 2 4 6 9 11 14 16 19 21 24 26 28 30 32 34 Rune
//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 array index
16
case _ => 17
}
}
var values = Array<Byte>(16, repeat: 0)
let iterator = uuid.runes()
var i = 0
while (i < 16) { //这里不能用for-in
var c = iterator.next()
let b1 = match (c) {
case Some(x) => doParse(x, i)
case _ => return None<UUID>
}
if (b1 == 16) {
continue
} else if (b1 == 17) {
return None<UUID>
}
c = iterator.next()
let b2 = match (c) {
case Some(x) => doParse(x, i)
case _ => return None<UUID>
}
if (b2 == 16 || b2 == 17) {
return None<UUID>
}
values[i] = (b1 << 4) | b2
i++
}
if(values[8] >> 6 != 2){
return None<UUID>
}
UUID(values: values)
}
/**
version 1
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_low |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_mid | ver | time_hi_and_version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|clk_seq_hi_res | clk_seq_low | node (0-1) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node (2-5) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
version 2
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_low |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_mid | ver | UID/GID_and_version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|clk_seq_hi_res | clk_seq_low | node (0-1) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node (2-5) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/**
version 6
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_high |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_mid | ver | time_low_and_version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|clk_seq_hi_res | clk_seq_low | node (0-1) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node (2-5) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public static func timeBased(timeLowFirst!: Bool = false): TimeBasedUUIDBuilder {
TimeBasedUUIDBuilder(timeLowFirst)
}
/**
version 3
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| md5_high |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| md5_high | ver | md5_mid |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| md5_low |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| md5_low |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public static func md5(value: String): UUID {
md5(value.unsafeBytes())
}
public static func randomMd5(bytes!: Int64 = 16): UUID {
md5(ThreadLocalRandom.current.nextBytes(bytes))
}
public static func md5(value: Array<Byte>): UUID {
let md5 = MD5()
md5.write(value)
var md = md5.finish()
md[6] &= 0xf
md[6] |= 3 << 4
md[8] &= 0x3f
md[8] |= 2 << 6
UUID(values: md)
}
/**
* version 4
*/
public static func random(): UUID {
let rand = ThreadLocalRandom.current.nextBytes(16)
rand[6] &= 0xf
rand[6] |= 4 << 4
rand[8] &= 0x3f
rand[8] |= 2 << 6
UUID(values: rand)
}
/**
version 5
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| sha_high |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| sha_high | ver | sha_mid |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| sha_low |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| sha_low |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
最后的sha_low在原文是md5_low,此处应该是一个错误
*/
public static func sha1(value: String): UUID {
sha1(value.unsafeBytes())
}
public static func randomSha1(bytes!: Int64 = 20): UUID {
sha1(ThreadLocalRandom.current.nextBytes(bytes))
}
public static func sha1(value: Array<Byte>): UUID {
let sha1 = SHA1()
sha1.write(value)
let sha = sha1.finish()
let values = Array<Byte>(16) {
i => if (i < 6) {
sha[i]
} else if (i == 6) {
(sha[18] & 0xf) | (5 << 4)
} else if (i == 7) {
sha[19]
} else if (i == 8) {
sha[8] & 0x3f | (2 << 6)
} else {
sha[i]
}
}
UUID(values: values)
}
/**
version 7
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms | ver | rand_a |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| rand_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rand_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public static func unixTimeBased(): UUID {
let millis = (DateTime.now() - DateTime.UnixEpoch).toMilliseconds()
let rand = ThreadLocalRandom.current.nextBytes(10)
let values = Array<Byte>(16) {
i => if (i < 6) {
UInt8((millis >> (7 - i) * 8) & 0xff)
} else if (i == 6) {
(rand[0] & 0xf) | (7 << 4)
} else if (i == 7) {
rand[1]
} else if (i == 8) {
(rand[2] & 0x3f) | (2 << 6)
} else {
rand[i - 6]
}
}
UUID(values: values)
}
/**
version 8
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| custom_a |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| custom_a | ver | custom_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var| custom_c |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| custom_c |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
只取参数的前16字节
*/
public static func custom(values: Array<Byte>): UUID {
let s = values.size
let val = Array<Byte>(16) {
i =>
let val = if (i < s) {
values[i]
} else {
0u8
}
if (i == 6) {
(val & 0xf) | (8 << 4)
} else if (i == 8) {
(val & 0x3f) | (2 << 6)
} else {
val
}
}
UUID(values: val)
}
}
public class TimeBasedUUIDBuilder <: Resource {
private let seqGen = TimestampSequenceBuilder()
private var version: Byte
private var timestamp: Int64 = 0
private var seq: UInt16 = 0
private var uid: UInt32 = 0
init(timeLowFirst: Bool) {
version = if (timeLowFirst) {
1
} else {
6
}
}
public func isClosed(): Bool {
seqGen.isClosed()
}
public func close(): Unit {
seqGen.close()
}
public func registerSequenceGenerator(generator: (Int64) -> UInt16): This {
seqGen.registerSequenceGenerator(generator)
this
}
public func registerSequenceGenerator(): This {
seqGen.registerSequenceGenerator()
this
}
public func registerFileSequenceGenerator(): This {
seqGen.registerFileSequenceGenerator()
this
}
public prop randomSeq: TimeBasedUUIDBuilder {
get() {
genTimestampAndSequence(true)
this
}
}
public prop serialSeq: TimeBasedUUIDBuilder {
get() {
genTimestampAndSequence(false)
this
}
}
public func UID(uid: UInt32): TimeBasedUUIDBuilder {
this.version = 2
this.uid = uid
this
}
public func GID(gid: UInt32): TimeBasedUUIDBuilder {
UID(gid)
}
private func genTimestampAndSequence(randomSeq: Bool) {
while (timestamp == 0 || seq == 0) {
(timestamp, seq) = seqGen.timestampAndSequence(randomSeq)
}
}
@When[os == 'Linux']
public func eth0(){
etherName('eth0')
}
@When[os == 'Linux']
public func etherName(name: String): UUID {
try(f = File('/sys/class/net/${name}/address', Read)){
return ether(StringReader(f).readToEnd())
}
throw UnreachableException()
}
public func ether(ether: String): UUID {
//00:00:00:00:00:00
//0 1 2 3 4 5
//0 3 6 9 12 15
let itr = ether.runes()
func parse(ch: ?Rune): Byte {
match (ch) {
case Some(c) => match (c) {
case r'0' => 0
case r'1' => 1
case r'2' => 2
case r'3' => 3
case r'4' => 4
case r'5' => 5
case r'6' => 6
case r'7' => 7
case r'8' => 8
case r'9' => 9
case r'a' | r'A' => 10
case r'b' | r'B' => 11
case r'c' | r'C' => 12
case r'd' | r'D' => 13
case r'e' | r'E' => 14
case r'f' | r'F' => 15
case _ => throw UnreachableException()
}
case _ => throw UnreachableException()
}
}
generate {
i =>
var b = (parse(itr.next()) << 4) | (parse(itr.next()))
if (i < 5) {
itr.next()
}
b
}
}
public func node(node: Int64): UUID {
generate {
i => UInt8((node >> (Int64(5 - i) * 8)) & 0xff)
}
}
public func node(node: UInt64): UUID {
generate {
i => UInt8((node >> (UInt64(5 - i) * 8)) & 0xff)
}
}
public func randomNode(): UUID {
node(ThreadLocalRandom.current.nextBytes(6))
}
public func node(node: Array<Byte>): UUID {
generate {i => node[i]}
}
private func generate(node: (Int64) -> Byte): UUID {
let timeFn = if (version == 1 || version == 2) {
timeLowFirst(timestamp)
} else {
timeHighFirst(timestamp)
}
UUID(
values: Array<UInt8>(16) {
i => if (i < 8) {
timeFn(i)
} else if (i == 8) {
UInt8((seq >> 8) & 0x3f) | (0x2 << 6)
} else if (i == 9) {
UInt8(seq & 0xff)
} else {
node(i - 10)
}
})
}
private func timeLowFirst(timestamp: Int64): (Int64) -> Byte {
{
idx => if (idx < 4) {
UInt8((timestamp >> ((3 - idx) * 8)) & 0xff)
} else if(version == 1){
match(idx){
case 4 => UInt8((timestamp >> 32) & 0xff)
case 5 => UInt8((timestamp >> 40) & 0xff)
case 6 => UInt8((timestamp >> 48) & 0xf) | (version << 4)
case 7 => UInt8((timestamp >> 56) & 0xff)
case _ => throw UnreachableException()
}
}else{
match(idx){
case 4 => UInt8((uid >> 24) & 0xff)
case 5 => UInt8((uid >> 16) & 0xff)
case 6 => UInt8(((uid >> 8) & 0xff)) | (version << 4)
case 7 => UInt8(uid & 0xff)
case _ => throw UnreachableException()
}
}
}
}
public func timeHighFirst(timestamp: Int64): (Int64) -> Byte {
{
idx => if (idx < 4) {
UInt8((timestamp >> ((7 - idx) * 8)) & 0xff)
} else {
match(idx){
case 4 => UInt8((timestamp >> 24) & 0xff)
case 5 => UInt8((timestamp >> 16) & 0xff)
case 6 => UInt8((timestamp >> 8) & 0xf) | (version << 4)
case 7 => UInt8(timestamp & 0xff)
case _ => throw UnreachableException()
}
}
}
}
}
public class TimestampSequenceBuilder <: Resource {
private var seqGen: (Int64) -> UInt16
private var closer: SequenceResource = SequenceResource.empty
~init(){
closer.close()
}
init() {
let seq = AtomicUInt16(0)
seqGen = {_: Int64 => seq.fetchAdd(1)}
}
public func isClosed(): Bool {
closer.isClosed()
}
public func close(): Unit {
closer.close()
}
private func emptyCloser(){
closer.close()
closer = SequenceResource.empty
}
public func registerSequenceGenerator(generator: (Int64) -> UInt16) {
emptyCloser()
seqGen = generator
}
public func registerFileSequenceGenerator() {
let dir = Directory.createTemp('/tmp')
let file = File("${dir}/${DateTime.now().format('yyyyMMddHHmmssSSS')}", OpenMode.ReadWrite)
closer.close()
closer = SequenceResource({=> file.close()}, {=> file.isClosed()})
seqGen = {
timestamp =>
let bytes = Array<Byte>(10, repeat: 0)
var storedNanos = 0
var seq = 0u16
if (file.read(bytes) > 0) {
for (i in 0..8) {
storedNanos |= Int64(bytes[i]) << ((7 - i) * 8)
}
seq = (UInt16(bytes[8]) << 8) | UInt16(bytes[9])
}
if (storedNanos >= timestamp) {
seq
} else {
for (i in 0..8) {
bytes[i] = UInt8((timestamp >> ((7 - i) * 8)) & 0xff)
}
@OverflowWrapping
func incr() {
seq++
}
incr()
bytes[8] = UInt8(seq >> 8)
bytes[9] = UInt8(seq & 0xff)
let pos: SeekPosition = Begin(0)
file.seek(pos)
file.write(bytes)
file.flush()
file.seek(pos)
seq
}
}
}
public func registerSequenceGenerator() {
let lastNanos = AtomicInt64(0)
let seq = AtomicUInt16(0)
emptyCloser()
seqGen = {
timestamp =>
let last = lastNanos.load()
if (last >= timestamp) {
seq.load()
} else if (lastNanos.compareAndSwap(last, timestamp)) {
seq.fetchAdd(1)
} else {
0
}
}
}
static let timeStart = DateTime.of(year: 1582, month: 10, dayOfMonth: 15, hour: 0, minute: 0, second: 0,
nanosecond: 0, timeZone: TimeZone.UTC)
private let mutex = Mutex()
func timestampAndSequence(randomSeq: Bool): (Int64, UInt16) {
synchronized(mutex) {
let timestamp = (DateTime.now() - timeStart).toNanoseconds() / 100
if (randomSeq) {
(timestamp, ThreadLocalRandom.current.nextUInt16())
} else {
(timestamp, seqGen(timestamp))
}
}
}
}
public struct SequenceResource <: Resource {
static let empty = SequenceResource({=>}, {=> false})
SequenceResource(
private let closer: () -> Unit,
private let isClosedFn: () -> Bool
){}
public func isClosed(): Bool {
isClosedFn()
}
public func close(): Unit {
if(!isClosedFn()){
closer()
}
}
}