user
Given the RFC 1035 message diagram from Section 4.1.1 (Header section format) as a string:
http://www.ietf.org/rfc/rfc1035.txt

```
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      ID                       |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    QDCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ANCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    NSCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ARCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

```

Where (every column of the table is 1 bit):

```
ID is 16 bits
QR = Query (0) or Response (1)
Opcode = Four bits defining kind of query:
  0:    a standard query (QUERY)
  1:    an inverse query (IQUERY)
  2:    a server status request (STATUS)
  3-15: reserved for future use
AA = Authoritative Answer bit
TC = Truncation bit
RD = Recursion Desired bit
RA = Recursion Available bit
Z = Reserved
RCODE = Response code
QC = Question Count
ANC = Answer Count
AUC = Authority Count
ADC = Additional Count

```

Write a function, member function, class or template that accepts a similar multi-line string as input to define a data structure or something else able to decode or store a header with that specified bit structure.

If your language has macros, introspection, code generation, or powerful enough templates, then accept such string at compile-time to define the header data structure statically.

Such "Header" function or template should accept a table with 8, 16, 32 or 64 columns, and any number of rows. For simplicity the only allowed symbols to define the table are + - | (plus, minus, pipe), and whitespace. Lines of the input string composed just of whitespace should be ignored. Leading and trailing whitespace in the input string should be ignored, as well as before and after each table row. The box for each bit of the diagram takes four chars "+--+". The code should perform a little of validation of the input string, but for brevity a full validation is not required.

Bonus: perform a thoroughly validation of the input string.
assistant
(formerly Perl 6)

**Works with**: Rakudo version 2018.05

```
grammar RFC1025 {
    rule  TOP {  <.line-separator> [<line> <.line-separator>]+ }
    rule  line-separator { <.ws> '+--'+ '+' }
    token line  { <.ws> '|' +%% <field>  }
    token field  { \s* <label> \s* }
    token label { \w+[\s+\w+]* }
}

sub bits ($item) { ($item.chars + 1) div 3 }

sub deconstruct ($bits, %struct) {
    map { $bits.substr(.<from>, .<bits>) }, @(%struct<fields>);
}

sub interpret ($header) {
    my $datagram = RFC1025.parse($header);
    my %struct;
    for $datagram.<line> -> $line {
        FIRST %struct<line-width> = $line.&bits;
        state $from = 0;
        %struct<fields>.push: %(:bits(.&bits), :ID(.<label>.Str), :from($from.clone), :to(($from+=.&bits)-1))
          for $line<field>;
    }
    %struct
}

use experimental :pack;

my $diagram = q:to/END/;

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                      ID                       |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    QDCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    ANCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    NSCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    ARCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

END

my %structure = interpret($diagram);

say 'Line width: ', %structure<line-width>, ' bits';
printf("Name: %7s, bit count: %2d, bit %2d to bit %2d\n", .<ID>, .<bits>, .<from>, .<to>) for @(%structure<fields>);
say "\nGenerate a random 12 byte \"header\"";
say my $buf = Buf.new((^0xFF .roll) xx 12);
say "\nShow it converted to a bit string";
say my $bitstr = $buf.unpack('C*')».fmt("%08b").join;
say "\nAnd unpack it";
printf("%7s, %02d bits: %s\n", %structure<fields>[$_]<ID>,  %structure<fields>[$_]<bits>,
  deconstruct($bitstr, %structure)[$_]) for ^@(%structure<fields>);

```

Output:

```
Line width: 16 bits
Name:      ID, bit count: 16, bit  0 to bit 15
Name:      QR, bit count:  1, bit 16 to bit 16
Name:  Opcode, bit count:  4, bit 17 to bit 20
Name:      AA, bit count:  1, bit 21 to bit 21
Name:      TC, bit count:  1, bit 22 to bit 22
Name:      RD, bit count:  1, bit 23 to bit 23
Name:      RA, bit count:  1, bit 24 to bit 24
Name:       Z, bit count:  3, bit 25 to bit 27
Name:   RCODE, bit count:  4, bit 28 to bit 31
Name: QDCOUNT, bit count: 16, bit 32 to bit 47
Name: ANCOUNT, bit count: 16, bit 48 to bit 63
Name: NSCOUNT, bit count: 16, bit 64 to bit 79
Name: ARCOUNT, bit count: 16, bit 80 to bit 95

Generate a random 12 byte "header"
Buf:0x<78 47 7b bf 54 96 e1 2e 1b f1 69 a4>

Show it converted to a bit string
011110000100011101111011101111110101010010010110111000010010111000011011111100010110100110100100

And unpack it
     ID, 16 bits: 0111100001000111
     QR, 01 bits: 0
 Opcode, 04 bits: 1111
     AA, 01 bits: 0
     TC, 01 bits: 1
     RD, 01 bits: 1
     RA, 01 bits: 1
      Z, 03 bits: 011
  RCODE, 04 bits: 1111
QDCOUNT, 16 bits: 0101010010010110
ANCOUNT, 16 bits: 1110000100101110
NSCOUNT, 16 bits: 0001101111110001
ARCOUNT, 16 bits: 0110100110100100
```