I was interested in converting the following Haskell code, that does decoding of CBOR into Rust:
module Main where
import Data.Word
import Data.Bits
import Control.Monad.Trans.Except
data Value = I Int deriving (Show)
read_int xs size =
f xs size 0
where
f _ 0 acc = return (I acc)
f [] _ acc = throwE ()
f (x:xs) n acc = f xs (n - 1) (acc `shiftL` 8 .|. fromIntegral x)
cbor_decode (x:xs)
| x >= 0x00 && x <= 0x17 = return (I (fromIntegral x))
| x >= 0x18 && x <= 0x1b = let v = fromIntegral x - 0x17 in read_int xs v
| otherwise = throwE ()
main :: IO ()
main = do
let x = [0x1a, 1, 0, 0] :: [Word8]
let y = runExcept (cbor_decode x) :: Either () Value
putStrLn $ show $ y
I ended up with the following:
use Value::*;
#[derive(Debug)]
enum Value {
I(i64),
}
fn read_int(buf: &[u8], size: usize) -> Result<Value, ()> {
fn f(buf: &[u8], size: usize, acc: i64) -> Result<Value, ()> {
if size == 0 {
Ok(I(acc))
} else if buf.len() == 0 {
Err(())
} else {
f(&buf[1..], size - 1, acc << 8 | buf[0] as i64)
}
}
f(buf, size, 0)
}
fn cbor_decode(buf: &[u8]) -> Result<Value, ()> {
match buf[0] {
0x00 ... 0x17 => Ok(I(buf[0] as i64)),
0x18 ... 0x1b => read_int(&buf[1..], (buf[0] - 0x17) as usize),
_ => Err(()),
}
}
fn main() {
let x = vec!(0x1a, 1, 0, 0);
let y = cbor_decode(&x);
println!("{:?}", y);
}
Is this considered good Rust?