///|
/// Errors returned while constructing UUIDv6 values.
pub(all) enum V6Error {
  TimestampOutOfRange(UInt64)
  ClockSeqOutOfRange(UInt64)
  NodeOutOfRange(UInt64)
} derive(Eq)

///|
pub extend V6Error with Eq::{not_equal, equal}

///|
/// Construct an RFC 9562 UUIDv6 from UUIDv1-compatible fields.
///
/// `timestamp_100ns` is the 60-bit count of 100 ns intervals since
/// 1582-10-15 00:00:00 UTC. `clock_seq` is 14 bits and `node` is 48 bits.
pub fn v6_from_parts(
  timestamp_100ns : UInt64,
  clock_seq : UInt64,
  node : UInt64,
) -> Result[Uuid, V6Error] {
  if timestamp_100ns > 0x0FFFFFFFFFFFFFFFUL {
    return Err(TimestampOutOfRange(timestamp_100ns))
  }
  if clock_seq > 0x3FFFUL {
    return Err(ClockSeqOutOfRange(clock_seq))
  }
  if node > 0x0000FFFFFFFFFFFFUL {
    return Err(NodeOutOfRange(node))
  }

  let high = (timestamp_100ns >> 12 << 16) |
    0x6000UL |
    (timestamp_100ns & 0xFFFUL)
  let low = 0x8000000000000000UL | (clock_seq << 48) | node

  Ok({ high, low, })
}

///|
/// Extract the 60-bit Gregorian 100-ns timestamp from an RFC UUIDv6.
///
/// Returns None for non-v6 UUIDs.
pub fn gregorian_ts_100ns(uuid : Uuid) -> UInt64? {
  if version(uuid) == Some(6) {
    Some((uuid.high >> 16 << 12) | (uuid.high & 0xFFFUL))
  } else {
    None
  }
}

///|
/// Extract the 14-bit clock sequence from an RFC UUIDv6.
///
/// Returns None for non-v6 UUIDs.
pub fn v6_clock_seq(uuid : Uuid) -> UInt64? {
  if version(uuid) == Some(6) {
    Some((uuid.low >> 48) & 0x3FFFUL)
  } else {
    None
  }
}

///|
/// Extract the 48-bit node field from an RFC UUIDv6.
///
/// Returns None for non-v6 UUIDs.
pub fn v6_node(uuid : Uuid) -> UInt64? {
  if version(uuid) == Some(6) {
    Some(uuid.low & 0x0000FFFFFFFFFFFFUL)
  } else {
    None
  }
}