Start working on support for Real numbers.

This commit is contained in:
2020-10-19 10:24:02 -07:00
parent d8e32f63a5
commit 3f98c8cd3b
4 changed files with 114 additions and 1 deletions

View File

@@ -2,18 +2,21 @@ use crate::ber::length::{Length, LengthReaderError, LengthWriterError};
use crate::ber::tag::{Tag, TagClass, TagForm, TagReaderError, TagSerializationError, BasicTagType};
use crate::lift_error;
use crate::number::Number;
use crate::real::Real;
use crate::util::BufferReader;
pub enum Value {
Boolean(TagClass, TagForm, bool),
Integer(TagClass, TagForm, Number),
Null(TagClass, TagForm),
Real(TagClass, TagForm, Real),
}
pub enum ValueReaderError {
LengthIncompatible,
LengthTooBig,
NotEnoughData,
InvalidFormat(BasicTagType),
TagReaderProblem(TagReaderError),
LengthReaderError(LengthReaderError),
}
@@ -34,7 +37,7 @@ impl Value {
pub fn read<I: Iterator<Item = u8>>(it: &mut I) -> Result<Value, ValueReaderError> {
let tag = Tag::read(it)?;
let length = Length::read(&tag, it)?;
let bytes: Vec<u8> = match length.read_buffer(it) {
let mut bytes: Vec<u8> = match length.read_buffer(it) {
None => return Err(ValueReaderError::NotEnoughData),
Some(x) => x,
};
@@ -56,6 +59,73 @@ impl Value {
Ok(Value::Integer(c, f, res))
}
Tag::Simple(c, f, BasicTagType::Real) => {
if bytes.len() == 0 {
return Err(ValueReaderError::InvalidFormat(BasicTagType::Real));
}
let leader = bytes.remove(0); // has the handy side-effect of making bytes by the
// actual value.
if leader == 0b01000000 {
return Ok(Value::Real(c, f, Real::PositiveInfinity));
}
if leader == 0b01000001 {
return Ok(Value::Real(c, f, Real::NegativeInfinity));
}
if leader >> 6 == 0b00 {
match String::from_utf8(bytes) {
Err(_) => return Err(ValueReaderError::InvalidFormat(BasicTagType::Real)),
Ok(v) => {
let has_e = v.chars().any(|c| (c == 'e') || (c == 'E'));
let has_p = v.chars().any(|c| (c == '.'));
let nr = leader & 0b00111111;
match nr {
0b01 if !has_e && !has_p => return Ok(Value::Real(c, f, Real::ISO6093(v))),
0b10 if !has_e && has_p => return Ok(Value::Real(c, f, Real::ISO6093(v))),
0b11 if has_e && has_p => return Ok(Value::Real(c, f, Real::ISO6093(v))),
_ => return Err(ValueReaderError::InvalidFormat(BasicTagType::Real)),
}
}
}
}
if (leader >> 7) == 0 {
return Err(ValueReaderError::InvalidFormat(BasicTagType::Real));
}
let positive = (leader >> 6) & 1 == 0;
let mant_shift = ((leader >> 2) & 0b11) as usize;
let exp_shift = match (leader >> 4) & 0b11 {
0b00 => 0,
0b01 => 2,
0b10 => 3,
_ => return Err(ValueReaderError::InvalidFormat(BasicTagType::Real)),
} as usize;
let explen = match leader & 0b11 {
0 => 1,
1 => 2,
2 => 3,
3 => bytes.remove(0),
_ => panic!("Mathematics has failed us.")
} as usize;
let mut exponent = Number::from_bytes(&bytes[0..explen]);
let mut mantissa = Number::from_bytes(&bytes[explen..]);
exponent <<= exp_shift;
mantissa <<= mant_shift;
if !positive {
mantissa = -mantissa;
}
Ok(Value::Real(c, f, Real::new(exponent, mantissa)))
}
_ =>
unimplemented!("Cannot parse tag {:?}", tag)
}
@@ -89,6 +159,10 @@ impl Value {
Tag::Simple(*c, *f, BasicTagType::Null).write(buffer)?;
Ok(())
}
Value::Real(c, f, r) => {
unimplemented!()
}
}
}
}

View File

@@ -30,6 +30,7 @@ extern crate alloc;
mod ber;
mod bitstring;
mod number;
mod real;
mod util;
use chrono::{DateTime, TimeZone, Utc};

View File

@@ -1,4 +1,5 @@
use core::convert::TryFrom;
use core::ops::{Neg, ShlAssign};
use crate::ber::length::ConversionError;
#[cfg(test)]
use quickcheck::{quickcheck, Arbitrary, Gen};
@@ -184,3 +185,17 @@ impl<'a> TryFrom<&'a Number> for usize {
}
}
}
impl ShlAssign<usize> for Number {
fn shl_assign(&mut self, amt: usize) {
unimplemented!()
}
}
impl Neg for Number {
type Output = Number;
fn neg(self) -> Number {
unimplemented!()
}
}

23
src/real.rs Normal file
View File

@@ -0,0 +1,23 @@
use crate::number::Number;
pub enum Real {
PositiveInfinity,
NegativeInfinity,
ISO6093(String),
Binary(RealNumber),
}
impl Real {
pub fn new(exponent: Number, mantissa: Number) -> Real {
Real::Binary(RealNumber{
exponent,
mantissa,
})
}
}
pub struct RealNumber {
exponent: Number,
mantissa: Number,
}