///|
/// ASN.1 tag class, carried in the two most significant bits of an identifier
/// octet (X.690, 8.1.2.2).
pub(all) enum TagClass {
  Universal
  Application
  ContextSpecific
  Private
} derive(Eq, @debug.Debug)

///|
/// A decoded ASN.1 tag: its class, whether the value is constructed, and the
/// tag number.
pub struct Tag {
  cls : TagClass
  constructed : Bool
  number : Int
} derive(Eq, @debug.Debug)

///|
/// Creates a tag. `constructed` defaults to `false`.
pub fn Tag::new(
  cls : TagClass,
  number : Int,
  constructed? : Bool = false,
) -> Tag {
  { cls, constructed, number, }
}

///|
/// Renders the tag in a compact, human readable form such as
/// `[CONTEXT 0 constructed]`.
pub fn Tag::to_string(self : Tag) -> String {
  let cls = match self.cls {
    Universal => "UNIVERSAL"
    Application => "APPLICATION"
    ContextSpecific => "CONTEXT"
    Private => "PRIVATE"
  }
  let form = if self.constructed { "constructed" } else { "primitive" }
  "[" + cls + " " + self.number.to_string() + " " + form + "]"
}

///|
/// Universal tag numbers defined by X.680 that are used by the encoder and
/// decoder.
pub const TAG_BOOLEAN : Int = 0x01

///|
pub const TAG_INTEGER : Int = 0x02

///|
pub const TAG_BIT_STRING : Int = 0x03

///|
pub const TAG_OCTET_STRING : Int = 0x04

///|
pub const TAG_NULL : Int = 0x05

///|
pub const TAG_OBJECT_IDENTIFIER : Int = 0x06

///|
pub const TAG_ENUMERATED : Int = 0x0A

///|
pub const TAG_UTF8_STRING : Int = 0x0C

///|
pub const TAG_SEQUENCE : Int = 0x10

///|
pub const TAG_SET : Int = 0x11

///|
pub const TAG_NUMERIC_STRING : Int = 0x12

///|
pub const TAG_PRINTABLE_STRING : Int = 0x13

///|
pub const TAG_T61_STRING : Int = 0x14

///|
pub const TAG_IA5_STRING : Int = 0x16

///|
pub const TAG_UTC_TIME : Int = 0x17

///|
pub const TAG_GENERALIZED_TIME : Int = 0x18

///|
pub const TAG_VISIBLE_STRING : Int = 0x1A

///|
pub const TAG_UNIVERSAL_STRING : Int = 0x1C

///|
pub const TAG_BMP_STRING : Int = 0x1E