| 1 | module asn1 |
| 2 | |
| 3 | // ASN.1 OPTIONAL Element. |
| 4 | // |
| 5 | // note: At the abstract ASN.1 level the absence of a DEFAULT value in an encoding is the same as its being present. |
| 6 | // Contrast this with OPTIONAL, where a value being present in the encoding is semantically distinct from its being absent. |
| 7 | // In some encoding rules (like BER/PER) it is at the whim of the sender whether a DEFAULT value is encoded or not |
| 8 | // (except for primitive type values in PER which are required by the PER standard to be absent in the encoding), |
| 9 | // while with others (like DER) the DEFAULT value is NEVER encoded. For all encoding rules, |
| 10 | // if the component that has a DEFAULT value is not encoded the receiving application must behave as though the DEFAULT value had been encoded. |
| 11 | pub struct Optional { |
| 12 | // underlying element marked as an optional |
| 13 | elem Element |
| 14 | mut: |
| 15 | // presence of this flag negates optionality of this elemeent. |
| 16 | // set to true when its should present, if not sure, just set to to false |
| 17 | present bool |
| 18 | } |
| 19 | |
| 20 | // new creates and marked element as an Optional element. |
| 21 | pub fn Optional.new(el Element, with_present bool) !Optional { |
| 22 | if el is Optional { |
| 23 | return error('recursive optional is not allowed') |
| 24 | } |
| 25 | return Optional{ |
| 26 | elem: el |
| 27 | present: with_present |
| 28 | } |
| 29 | } |
| 30 | |
| 31 | // set_present_bit sets this Optional element with flag in present. |
| 32 | pub fn (mut opt Optional) set_present_bit(present bool) { |
| 33 | opt.present = present |
| 34 | } |
| 35 | |
| 36 | // tag returns the tag of Optional element. |
| 37 | pub fn (opt Optional) tag() Tag { |
| 38 | return opt.elem.tag() |
| 39 | } |
| 40 | |
| 41 | // payload the payload of Optional element. |
| 42 | pub fn (opt Optional) payload() ![]u8 { |
| 43 | return opt.elem.payload()! |
| 44 | } |
| 45 | |
| 46 | // encode serializes this Optional element into bytes array. |
| 47 | pub fn (opt Optional) encode() ![]u8 { |
| 48 | return opt.encode_with_rule(.der)! |
| 49 | } |
| 50 | |
| 51 | fn (opt Optional) encode_with_rule(_rule EncodingRule) ![]u8 { |
| 52 | if opt.present { |
| 53 | // elem := opt.into_element()! |
| 54 | return encode_with_rule(opt, .der)! |
| 55 | } |
| 56 | // not present |
| 57 | return []u8{} |
| 58 | } |
| 59 | |
| 60 | // into_element turns this optional into Element. |
| 61 | pub fn (opt Optional) into_element() !Element { |
| 62 | return parse_element(opt.tag(), opt.payload()!)! |
| 63 | } |
| 64 | |
| 65 | // into_object tries to turns this optional into real underlying object T. |
| 66 | // Its return object T on success or error on fails. |
| 67 | pub fn (opt Optional) into_object[T]() !T { |
| 68 | $if T !is Element { |
| 69 | return error('T is not element') |
| 70 | } |
| 71 | $if T is Optional { |
| 72 | return error('T is optional') |
| 73 | } |
| 74 | elem := opt.into_element()! |
| 75 | if elem is Optional { |
| 76 | return error('elem is also optional') |
| 77 | } |
| 78 | return elem.into_object[T]()! |
| 79 | } |
| 80 | |