dochy_diff 0.10.1

Calculates Dochy Diff.
use crate::imp::read::reader::Reader;
use crate::diff_error::{DiffError, OptToErr};
use crate::imp::structs_read::{ListItemDiffEnumR, ListItemDiffR, CS, ListDiffR};
use crate::imp::read::read_params::read_params;
use dochy_core::structs::{MetaTables, MetaValue};
use crate::imp::read::read_lists::read_lists;
use crate::imp::read::read_refs::read_refs;
use crate::imp::read::read_store_ids::read_stored_ids;
use crate::imp::write::store_ids::StoredIDs;
use crate::imp::read::read_param::read_param;
use crate::imp::read::read_lists_numbers::read_lists_numbers;
use with_capacity_safe::vec_with_capacity_safe;

pub(crate) fn read_list(r : &mut Reader, meta : &MetaTables)
    -> Result<ListDiffR, DiffError>{

    let len = r.read()?.ast_i64()? as usize;
    let next_id = r.read()?.ast_i64()? as u64;
    let mut vec : Vec<(u64, ListItemDiffEnumR)> = vec_with_capacity_safe(len)?;
    for _ in 0..len{
        let id = r.read()?.ast_i64()?;
        vec.push((id as u64, read_list_item(r, meta)?));
    }
    Ok(ListDiffR::new(vec, next_id))
}

fn read_list_item(r : &mut Reader, meta : &MetaTables) -> Result<ListItemDiffEnumR, DiffError>{
    if r.read()?.ast_bool()?{
        Ok(ListItemDiffEnumR::Modify(read_list_item2(r, meta)?))
    } else if r.read()?.ast_bool()?{
        Ok(ListItemDiffEnumR::Create(read_cs(r, meta)?))
    } else{
        Ok(ListItemDiffEnumR::Delete)
    }
}

fn read_cs(r : &mut Reader, meta : &MetaTables) -> Result<CS, DiffError>{
    let mut prev_id = None;
    if r.read()?.ast_bool()?{
        prev_id = Some(r.read()?.ast_i64()? as u64);
    }
    let diff = read_list_item2(r, meta)?;
    Ok(CS{ prev_id, diff })
}

fn read_list_item2(r : &mut Reader, meta : &MetaTables) -> Result<ListItemDiffR, DiffError>{
    let ids = read_stored_ids(r)?;
    match ids {
        StoredIDs::Zero => {
            let params = Vec::new();
            let lists = Vec::new();
            let mut refs = Vec::new();
            read_refs(r, meta.refs(), &mut refs)?;
            Ok(ListItemDiffR::new(params, lists, refs))
        }
        StoredIDs::U64(bits) => {
            let mut params = Vec::new();
            let mut lists = Vec::new();
            let mut refs = Vec::new();
            read_params(r, bits, meta.items(), 0, &mut params)?;
            read_lists(r, bits, meta.items(), 0, &mut lists)?;
            read_refs(r, meta.refs(), &mut refs)?;
            Ok(ListItemDiffR::new(params, lists, refs))
        },
        StoredIDs::Bits(bits) => {
            let mut params = Vec::new();
            let mut lists = Vec::new();
            let mut refs = Vec::new();
            let mut offset = 0;
            for &b in &bits {
                read_params(r, b, meta.items(), offset, &mut params)?;
                offset += 64;
            }
            offset = 0;
            for &b in &bits {
                read_lists(r, b, meta.items(), offset, &mut lists)?;
                offset += 64;
            }
            read_refs(r, meta.refs(), &mut refs)?;
            Ok(ListItemDiffR::new(params, lists, refs))
        },
        StoredIDs::Numbers(n) => {
            let mut params = Vec::new();
            let mut lists = Vec::new();
            let mut refs = Vec::new();

            for &id in &n{
                if let Some((_,MetaValue::Param(p))) = meta.items().get(id){
                    params.push((id, read_param(p, r)?));
                } else {
                    Err("invalid meta read_list_item2")?
                }
            }
            read_lists_numbers(r, meta.items(), &n, &mut lists)?;
            read_refs(r, meta.refs(), &mut refs)?;
            Ok(ListItemDiffR::new(params, lists, refs))
        }
    }
}