getBigint getter = do
  len   <- fromIntegral <$> getter
  sign  <- get8u
  bytes <- getL len
  multiplier <-
    case sign of
      0 -> return 1
      1 -> return (-1)
      _ -> fail "Invalid sign byte"
  return $ (*) multiplier
         $ foldl (\s (n, d) -> s + d*(256^n)) 0
         $ zip [0..len-1] (map fromIntegral $ B.unpack bytes)

-- Note about put32s/get32s:
--
-- When dealing with 32-bit signed ints, we first convert between Int and
-- Int32, and only then cast to Word32. This is to ensure put and get are
-- as close to inverse as possible. Coercing word types to and from
-- integer types using 'fromIntegral' is guaranteed to preserve
-- representation (see Notes in "Data.Int").
--
-- For an example of what can go wrong, see
-- https://github.com/feuerbach/bert/issues/6
getBigint getter = do
  len   <- fromIntegral <$> getter
  sign  <- get8u
  bytes <- getL len
  multiplier <-
    case sign of
      0 -> return 1
      1 -> return (-1)
      _ -> fail "Invalid sign byte"
  return $ (*) multiplier
         $ foldl (\s (n, d) -> s + d*(256^n)) 0
         $ zip [0..len-1] (map fromIntegral $ B.unpack bytes)

-- Note about put32s/get32s:
--
-- When dealing with 32-bit signed ints, we first convert between Int and
-- Int32, and only then cast to Word32. This is to ensure put and get are
-- as close to inverse as possible. Coercing word types to and from
-- integer types using 'fromIntegral' is guaranteed to preserve
-- representation (see Notes in "Data.Int").
--
-- For an example of what can go wrong, see
-- https://github.com/feuerbach/bert/issues/6
getBigint getter = do
  len   <- fromIntegral <$> getter
  sign  <- get8u
  bytes <- getL len
  multiplier <-
    case sign of
      0 -> return 1
      1 -> return (-1)
      _ -> fail "Invalid sign byte"
  return $ (*) multiplier
         $ foldl (\s (n, d) -> s + d*(256^n)) 0
         $ zip [0..len-1] (map fromIntegral $ B.unpack bytes)

-- Note about put32s/get32s:
--
-- When dealing with 32-bit signed ints, we first convert between Int and
-- Int32, and only then cast to Word32. This is to ensure put and get are
-- as close to inverse as possible. Coercing word types to and from
-- integer types using 'fromIntegral' is guaranteed to preserve
-- representation (see Notes in "Data.Int").
--
-- For an example of what can go wrong, see
-- https://github.com/feuerbach/bert/issues/6