Start working on support for Real numbers.
This commit is contained in:
@@ -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!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ extern crate alloc;
|
||||
mod ber;
|
||||
mod bitstring;
|
||||
mod number;
|
||||
mod real;
|
||||
mod util;
|
||||
|
||||
use chrono::{DateTime, TimeZone, Utc};
|
||||
|
||||
@@ -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
23
src/real.rs
Normal 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,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user