sqlx-sqlserver 0.0.3

Independent Microsoft SQL Server driver crate for SQLx.
Documentation
use sqlx_core::error::BoxDynError;

pub(crate) fn decode_money_bytes(bytes: &[u8]) -> Result<i64, BoxDynError> {
    let amount = match bytes {
        [a, b, c, d] => i64::from(i32::from_le_bytes([*a, *b, *c, *d])),
        [a, b, c, d, e, f, g, h] => {
            let amount_h = i64::from(i32::from_le_bytes([*a, *b, *c, *d]));
            let amount_l = i64::from(u32::from_le_bytes([*e, *f, *g, *h]));
            (amount_h << 32) | amount_l
        }
        _ => {
            return Err(format!("expected 8/4 bytes for Money, got {}", bytes.len()).into());
        }
    };

    Ok(amount)
}

pub(crate) fn decode_numeric_bytes(bytes: &[u8]) -> Result<(i8, u128), BoxDynError> {
    let Some((&sign, rest)) = bytes.split_first() else {
        return Err("numeric bytes cannot be empty".into());
    };

    let sign = match sign {
        0 => -1,
        1 => 1,
        other => return Err(format!("invalid sign byte: 0x{other:02x}").into()),
    };

    if rest.len() > 16 {
        return Err("numeric value exceeds 16 bytes".into());
    }

    let mut fixed_bytes = [0_u8; 16];
    fixed_bytes[..rest.len()].copy_from_slice(rest);

    Ok((sign, u128::from_le_bytes(fixed_bytes)))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn decode_money_bytes_rejects_bad_lengths() {
        assert_eq!(
            "expected 8/4 bytes for Money, got 0",
            decode_money_bytes(&[]).unwrap_err().to_string()
        );
        assert_eq!(
            "expected 8/4 bytes for Money, got 3",
            decode_money_bytes(&[0x01, 0x02, 0x03])
                .unwrap_err()
                .to_string()
        );
    }

    #[test]
    fn decode_money_bytes_handles_boundaries() {
        assert_eq!(
            1_234_561_234,
            decode_money_bytes(&[0xd2, 0xe8, 0x95, 0x49]).unwrap()
        );
        assert_eq!(
            -1_234_561_234,
            decode_money_bytes(&[0x2e, 0x17, 0x6a, 0xb6]).unwrap()
        );
        assert_eq!(
            1_234_567_891_234,
            decode_money_bytes(&[0x1f, 0x01, 0x00, 0x00, 0x22, 0x09, 0xfb, 0x71]).unwrap()
        );
        assert_eq!(
            -1_234_567_891_234,
            decode_money_bytes(&[0xe0, 0xfe, 0xff, 0xff, 0xde, 0xf6, 0x04, 0x8e]).unwrap()
        );
        assert_eq!(
            i64::MAX,
            decode_money_bytes(&[0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff]).unwrap()
        );
        assert_eq!(
            i64::MIN,
            decode_money_bytes(&[0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00]).unwrap()
        );
        assert_eq!(
            0,
            decode_money_bytes(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]).unwrap()
        );
    }

    #[test]
    fn decode_numeric_bytes_rejects_invalid_payloads() {
        assert_eq!(
            "numeric bytes cannot be empty",
            decode_numeric_bytes(&[]).unwrap_err().to_string()
        );
        assert_eq!(
            "invalid sign byte: 0x02",
            decode_numeric_bytes(&[0x02, 0x01, 0x02])
                .unwrap_err()
                .to_string()
        );
        assert_eq!(
            "numeric value exceeds 16 bytes",
            decode_numeric_bytes(&[0x01; 18]).unwrap_err().to_string()
        );
    }

    #[test]
    fn decode_numeric_bytes_decodes_sign_and_little_endian_amount() {
        assert_eq!(
            (1, 412_345),
            decode_numeric_bytes(&[0x01, 0xb9, 0x4a, 0x06, 0x00]).unwrap()
        );
        assert_eq!(
            (-1, 123_456_789_123_400),
            decode_numeric_bytes(&[0x00, 0x48, 0x91, 0x0f, 0x86, 0x48, 0x70, 0x00, 0x00]).unwrap()
        );
        assert_eq!(
            (1, 0),
            decode_numeric_bytes(&[0x01, 0x00, 0x00, 0x00, 0x00]).unwrap()
        );
        assert_eq!(
            (-1, 0),
            decode_numeric_bytes(&[0x00, 0x00, 0x00, 0x00, 0x00]).unwrap()
        );
        assert_eq!(
            (1, u128::MAX),
            decode_numeric_bytes(&[
                0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
                0xff, 0xff, 0xff,
            ])
            .unwrap()
        );
        assert_eq!(
            (1, 1 << 120),
            decode_numeric_bytes(&[
                0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x01,
            ])
            .unwrap()
        );
    }
}