use crate::api::cfb::Block;
use crate::records::pcb::PcbObjectId;
use crate::types::ParameterCollection;
use super::{BinaryRecord, GenericRecord};
#[derive(Debug, Clone)]
pub struct ParamsContainer {
source: String,
records: Vec<GenericRecord>,
}
impl ParamsContainer {
pub fn from_blocks(source: &str, blocks: &[Block]) -> Self {
let mut records = Vec::with_capacity(blocks.len());
for block in blocks {
if let Some(params) = block.as_params() {
records.push(GenericRecord::from_params(¶ms));
}
}
ParamsContainer {
source: source.to_string(),
records,
}
}
pub fn from_params_list(source: &str, params_list: Vec<ParameterCollection>) -> Self {
let records = params_list.iter().map(GenericRecord::from_params).collect();
ParamsContainer {
source: source.to_string(),
records,
}
}
pub fn source(&self) -> &str {
&self.source
}
pub fn len(&self) -> usize {
self.records.len()
}
pub fn is_empty(&self) -> bool {
self.records.is_empty()
}
pub fn get(&self, index: usize) -> Option<&GenericRecord> {
self.records.get(index)
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut GenericRecord> {
self.records.get_mut(index)
}
pub fn iter(&self) -> impl Iterator<Item = &GenericRecord> {
self.records.iter()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut GenericRecord> {
self.records.iter_mut()
}
pub fn filter_by_type(&self, record_id: i32) -> impl Iterator<Item = &GenericRecord> {
self.records
.iter()
.filter(move |r| r.record_id() == Some(record_id))
}
pub fn find<F>(&self, pred: F) -> Option<&GenericRecord>
where
F: Fn(&GenericRecord) -> bool,
{
self.records.iter().find(|r| pred(r))
}
pub fn find_all<F>(&self, pred: F) -> Vec<&GenericRecord>
where
F: Fn(&GenericRecord) -> bool,
{
self.records.iter().filter(|r| pred(r)).collect()
}
pub fn is_modified(&self) -> bool {
self.records.iter().any(|r| r.is_modified())
}
pub fn push(&mut self, record: GenericRecord) {
self.records.push(record);
}
pub fn remove(&mut self, index: usize) -> Option<GenericRecord> {
if index < self.records.len() {
Some(self.records.remove(index))
} else {
None
}
}
pub fn to_params_list(&self) -> Vec<ParameterCollection> {
self.records.iter().map(|r| r.to_params()).collect()
}
}
impl IntoIterator for ParamsContainer {
type Item = GenericRecord;
type IntoIter = std::vec::IntoIter<GenericRecord>;
fn into_iter(self) -> Self::IntoIter {
self.records.into_iter()
}
}
impl<'a> IntoIterator for &'a ParamsContainer {
type Item = &'a GenericRecord;
type IntoIter = std::slice::Iter<'a, GenericRecord>;
fn into_iter(self) -> Self::IntoIter {
self.records.iter()
}
}
#[derive(Debug, Clone)]
pub struct BinaryContainer {
source: String,
records: Vec<BinaryRecord>,
}
impl BinaryContainer {
pub fn from_blocks(source: &str, blocks: &[Block]) -> Self {
let mut records = Vec::with_capacity(blocks.len());
for block in blocks {
if block.data.is_empty() {
continue;
}
let object_id = PcbObjectId::from_byte(block.data[0]);
records.push(BinaryRecord::from_binary(object_id, block.data.clone()));
}
BinaryContainer {
source: source.to_string(),
records,
}
}
pub fn new(source: &str) -> Self {
BinaryContainer {
source: source.to_string(),
records: Vec::new(),
}
}
pub fn source(&self) -> &str {
&self.source
}
pub fn len(&self) -> usize {
self.records.len()
}
pub fn is_empty(&self) -> bool {
self.records.is_empty()
}
pub fn get(&self, index: usize) -> Option<&BinaryRecord> {
self.records.get(index)
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut BinaryRecord> {
self.records.get_mut(index)
}
pub fn iter(&self) -> impl Iterator<Item = &BinaryRecord> {
self.records.iter()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut BinaryRecord> {
self.records.iter_mut()
}
pub fn filter_by_type(&self, object_id: PcbObjectId) -> impl Iterator<Item = &BinaryRecord> {
self.records
.iter()
.filter(move |r| r.object_id() == object_id)
}
pub fn is_modified(&self) -> bool {
self.records.iter().any(|r| r.is_modified())
}
pub fn push(&mut self, record: BinaryRecord) {
self.records.push(record);
}
pub fn remove(&mut self, index: usize) -> Option<BinaryRecord> {
if index < self.records.len() {
Some(self.records.remove(index))
} else {
None
}
}
pub fn to_binary(&self) -> Vec<Vec<u8>> {
self.records.iter().map(|r| r.to_binary()).collect()
}
}
impl IntoIterator for BinaryContainer {
type Item = BinaryRecord;
type IntoIter = std::vec::IntoIter<BinaryRecord>;
fn into_iter(self) -> Self::IntoIter {
self.records.into_iter()
}
}
impl<'a> IntoIterator for &'a BinaryContainer {
type Item = &'a BinaryRecord;
type IntoIter = std::slice::Iter<'a, BinaryRecord>;
fn into_iter(self) -> Self::IntoIter {
self.records.iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::api::cfb::Block;
#[test]
fn test_params_container_from_blocks() {
let blocks = vec![
Block {
offset: 0,
size: 20,
flags: 0,
data: b"|RECORD=1|NAME=A|\0".to_vec(),
},
Block {
offset: 24,
size: 20,
flags: 0,
data: b"|RECORD=2|NAME=B|\0".to_vec(),
},
];
let container = ParamsContainer::from_blocks("/test", &blocks);
assert_eq!(container.len(), 2);
assert_eq!(container.get(0).unwrap().record_id(), Some(1));
assert_eq!(container.get(1).unwrap().record_id(), Some(2));
}
#[test]
fn test_filter_by_type() {
let params = vec![
ParameterCollection::from_string("|RECORD=1|"),
ParameterCollection::from_string("|RECORD=2|"),
ParameterCollection::from_string("|RECORD=1|"),
];
let container = ParamsContainer::from_params_list("/test", params);
let record1s: Vec<_> = container.filter_by_type(1).collect();
assert_eq!(record1s.len(), 2);
}
#[test]
fn test_modification_tracking() {
let params = vec![ParameterCollection::from_string("|RECORD=1|NAME=Test|")];
let mut container = ParamsContainer::from_params_list("/test", params);
assert!(!container.is_modified());
container.get_mut(0).unwrap().set("NAME", "Modified");
assert!(container.is_modified());
}
}