v/vlib/x/encoding/asn1/optional.v

80 lines
2.5 KiB
V

module asn1
// ASN.1 OPTIONAL Element.
//
// note: At the abstract ASN.1 level the absence of a DEFAULT value in an encoding is the same as its being present.
// Contrast this with OPTIONAL, where a value being present in the encoding is semantically distinct from its being absent.
// In some encoding rules (like BER/PER) it is at the whim of the sender whether a DEFAULT value is encoded or not
// (except for primitive type values in PER which are required by the PER standard to be absent in the encoding),
// while with others (like DER) the DEFAULT value is NEVER encoded. For all encoding rules,
// if the component that has a DEFAULT value is not encoded the receiving application must behave as though the DEFAULT value had been encoded.
pub struct Optional {
// underlying element marked as an optional
elem Element
mut:
// presence of this flag negates optionality of this elemeent.
// set to true when its should present, if not sure, just set to to false
present bool
}
// new creates and marked element as an Optional element.
pub fn Optional.new(el Element, with_present bool) !Optional {
if el is Optional {
return error('recursive optional is not allowed')
}
return Optional{
elem: el
present: with_present
}
}
// set_present_bit sets this Optional element with flag in present.
pub fn (mut opt Optional) set_present_bit(present bool) {
opt.present = present
}
// tag returns the tag of Optional element.
pub fn (opt Optional) tag() Tag {
return opt.elem.tag()
}
// payload the payload of Optional element.
pub fn (opt Optional) payload() ![]u8 {
return opt.elem.payload()!
}
// encode serializes this Optional element into bytes array.
pub fn (opt Optional) encode() ![]u8 {
return opt.encode_with_rule(.der)!
}
fn (opt Optional) encode_with_rule(rule EncodingRule) ![]u8 {
if opt.present {
// elem := opt.into_element()!
return encode_with_rule(opt, .der)!
}
// not present
return []u8{}
}
// into_element turns this optional into Element.
pub fn (opt Optional) into_element() !Element {
return parse_element(opt.tag(), opt.payload()!)!
}
// into_object tries to turns this optional into real underlying object T.
// Its return object T on success or error on fails.
pub fn (opt Optional) into_object[T]() !T {
$if T !is Element {
return error('T is not element')
}
$if T is Optional {
return error('T is optional')
}
elem := opt.into_element()!
if elem is Optional {
return error('elem is also optional')
}
return elem.into_object[T]()!
}