Pack / Unpack methods

I’m looking for Crystal’s equivalent of Ruby’s Array#pack method.

This thread explains why Crystal doesn’t have it, but I’m wondering if anything has been added since this time to maybe support doing it a different way.

irb(main):001:0> [5].pack('e*').bytes
=> [0, 0, 160, 64]
1 Like

Here’s the way it’s done in JavaScript. Maybe someone has an idea of how to replicate it this way in Crystal?

const buf = Buffer.allocUnsafe(4);
buf.writeFloatLE(5, 0);
Uint8Array.from(buf);

Alright! Thanks to some help from @straight-shoota if anyone else comes looking for answers, here we go:

# Unpack
numbers = [5]
 
io = IO::Memory.new
 
numbers.each do |n|
  io.write_bytes n.to_f32, IO::ByteFormat::LittleEndian
end
 
io.rewind
io.to_s.bytes
#=> [0, 0, 160, 64]
# Pack
n = [65, 66, 67]

# Ruby
n.pack("ccc") #=> "ABC"

# Crystal
String.build do |io|
  n.each do |number|
    io.write_byte number.to_u8
  end
end #=> "ABC"

Yes, it’s a bit more verbose, but if you take a look at the closed issue on Crystal, it’ll make a little sense as to why. For me, the pack/unpack methods in ruby always seemed a little mysterious. Seeing that it’s just writing some bytes to some IO really clears it up for me.

4 Likes

Thanks, this helped me! I wonder if examples like these are present in the documentation?