#decoding bit arrays

1 messages · Page 1 of 1 (latest)

final spruce
#

I'm thinking of such API, however, I'm struggling to implement it. I can't think on how I can implement the decode and the primitive decoders (dec_int8, dec_int16, dec_int32). The return of decode is supposed to be a Result(#(Foo, BitArray), DecodeError) where the 2nd element of the tuple is the remaining BitArray after applying the decoders. It's not so easy to list/explain what I tried and I hope that it's okay not to list them to ask your opinions on how to implement it.

PS: I do have already a way for the decoding but I'm finding the listed API here to be elegant. Much like what lpil did recently in the dynamic module.

#

Here's the text in the attached code screenshot:


pub type Int8 {
  Int8(value: Int)
}

pub type Int16 {
  Int16(value: Int)
}

pub type Int32 {
  Int32(value: Int)
}

pub type Foo {
  Foo(a: Int8, b: Int16, c: Int32)
}

pub fn main() {
  let assert Ok(#(Foo(Int8(-1), Int16(2), Int32(-100)), <<1>>)) =
    decode(<<-1:8, 2:16, -100:32, 1:8>>, with: {
      use i <- dec_int8
      use u <- dec_uint16
      use s <- dec_string
      Foo(i, u, s)
    })
}
bitter radish
#

Why wouldn't you use pattern matching here?

#

This functionality is built into the language, no?

final spruce
#

I'd like to come up with a more generic solution. I have a list of basic types (string, float64, etc) and a more complex types as combinations of the basic types.

#

And yes, the implementation I have at the moment involves pattern matching to decode the bits and convert them to gleam types.

final spruce
#

My main problem is decoding the complex types and how can I combine the basic decoders to decode the complex types.

bitter radish
#

Pattern matching is the most generic form of flow control in the language

#

Do you mean more specific?

#

Is there some problem you're looking to solve?

final spruce
#

Not really a problem. I just want to have a more generic/elegant decoder. Take a look at what I have at the moment vs what would be nice to have:


type Foo {
  Foo(a: base.Int8, b: base.Int16, c: base.Int32)
}

fn main() {
  let data = <<-1:8, 2:16, -100:32, 0:8>>

  // This is the one I have at the moment.
  let decode_foo = fn(data: BitArray) -> Result(#(Foo, BitArray), DecodeError) {
    use #(a, rem) <- result.try(int8(data))
    use #(b, rem) <- result.try(int16(rem))
    use #(c, rem) <- result.try(int32(rem))
    Ok(#(Foo(a, b, c), rem))
  }
  let foo = decode_foo(data)

  // I'm thinking that this version looks better than creating a separate decoder to decode Foo.
  let foo2 =
    decode(data, with: {
      use a <- dec_int8
      use b <- dec_int16
      use c <- dec_int32
      Foo(a, b, c)
    })
}
#

I'm just wondering what would be the potential types of decode and dec_int8 in the "would-be-nice-to-have" version.

bitter radish
#

This is less generic, not more

final spruce
#

Oh, I see. I'm thinking too hard for nothing. I'm stalling from things I need to do for this. Thank you, I can now proceed to the next problems. 🙂