1use crate::ev_formats::dataframe_builder::EventDataFrameBuilder;
17use crate::ev_formats::{EventFormat, LoadConfig};
18use polars::prelude::*;
19use std::fs::File;
20use std::io::Read;
21use std::path::Path;
22#[derive(Debug, Clone)]
24pub struct AerConfig {
25 pub big_endian: bool,
27 pub validate_coordinates: bool,
29 pub max_x: u16,
31 pub max_y: u16,
33 pub skip_invalid_events: bool,
35 pub generate_timestamps: bool,
37 pub timestamp_mode: TimestampMode,
39 pub start_timestamp: f64,
41 pub time_increment: f64,
43 pub max_events: Option<usize>,
45 pub bytes_per_event: usize,
47}
48#[derive(Debug, Clone, PartialEq)]
50pub enum TimestampMode {
51 Sequential,
53 Uniform,
55 Exponential,
57 Custom(Vec<f64>),
59}
60#[derive(Debug)]
62pub enum AerError {
63 Io(std::io::Error),
64 InvalidFileSize(u64, usize),
65 InvalidCoordinate(u16, u16, u16, u16),
66 InvalidEventData(usize, Vec<u8>),
67 InsufficientData(usize, usize),
68 InvalidBytesPerEvent(usize),
69 EmptyFile,
70 ValidationFailed(String),
71}
72impl std::fmt::Display for AerError {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 match self {
75 AerError::Io(e) => write!(f, "I/O error: {e}"),
76 AerError::InvalidFileSize(size, expected) => write!(
77 f,
78 "Invalid file size: {size} bytes, expected multiple of {expected}"
79 ),
80 AerError::InvalidCoordinate(x, y, max_x, max_y) => write!(
81 f,
82 "Invalid coordinate: x={x}, y={y}, max_x={max_x}, max_y={max_y}"
83 ),
84 AerError::InvalidEventData(offset, data) => {
85 write!(f, "Invalid event data at byte {offset}: {data:02X?}")
86 }
87 AerError::InsufficientData(expected, actual) => write!(
88 f,
89 "Insufficient data: expected {expected} bytes, got {actual}"
90 ),
91 AerError::InvalidBytesPerEvent(bytes) => {
92 write!(f, "Invalid bytes per event: {bytes}, expected 2 or 4")
93 }
94 AerError::EmptyFile => write!(f, "File is empty"),
95 AerError::ValidationFailed(msg) => write!(f, "Event validation failed: {msg}"),
96 }
97 }
98}
99impl std::error::Error for AerError {
100 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
101 match self {
102 AerError::Io(e) => Some(e),
103 _ => None,
104 }
105 }
106}
107impl From<std::io::Error> for AerError {
108 fn from(error: std::io::Error) -> Self {
109 AerError::Io(error)
110 }
111}
112pub type AerResult<T> = Result<T, AerError>;
114#[derive(Debug, Clone)]
116pub struct AerMetadata {
117 pub file_size: u64,
119 pub event_count: usize,
121 pub bytes_per_event: usize,
123 pub endianness: String,
125 pub coordinate_bounds: Option<(u16, u16, u16, u16)>, pub timestamp_range: Option<(f64, f64)>,
129 pub polarity_distribution: Option<(usize, usize)>,
131}
132impl Default for AerConfig {
133 fn default() -> Self {
134 Self {
135 big_endian: false,
136 validate_coordinates: true,
137 max_x: 511, max_y: 511, skip_invalid_events: false,
140 generate_timestamps: true,
141 timestamp_mode: TimestampMode::Sequential,
142 start_timestamp: 0.0,
143 time_increment: 1e-6, max_events: None,
145 bytes_per_event: 4, }
147 }
148}
149impl AerConfig {
150 pub fn new() -> Self {
152 Self::default()
153 }
154 pub fn with_endianness(mut self, big_endian: bool) -> Self {
156 self.big_endian = big_endian;
157 self
158 }
159 pub fn with_coordinate_bounds(mut self, max_x: u16, max_y: u16) -> Self {
161 self.max_x = max_x;
162 self.max_y = max_y;
163 self
164 }
165 pub fn with_timestamp_generation(
167 mut self,
168 generate: bool,
169 mode: TimestampMode,
170 start: f64,
171 increment: f64,
172 ) -> Self {
173 self.generate_timestamps = generate;
174 self.timestamp_mode = mode;
175 self.start_timestamp = start;
176 self.time_increment = increment;
177 self
178 }
179 pub fn with_bytes_per_event(mut self, bytes: usize) -> Self {
181 self.bytes_per_event = bytes;
182 self
183 }
184 pub fn with_validation(mut self, validate: bool, skip_invalid: bool) -> Self {
186 self.validate_coordinates = validate;
187 self.skip_invalid_events = skip_invalid;
188 self
189 }
190 pub fn with_max_events(mut self, max_events: Option<usize>) -> Self {
192 self.max_events = max_events;
193 self
194 }
195}
196pub struct AerReader {
198 config: AerConfig,
199}
200impl AerReader {
201 pub fn new() -> Self {
203 Self {
204 config: AerConfig::default(),
205 }
206 }
207 pub fn with_config(config: AerConfig) -> Self {
209 Self { config }
210 }
211 pub fn read_file<P: AsRef<Path>>(&self, path: P) -> AerResult<(DataFrame, AerMetadata)> {
213 let mut file = File::open(path.as_ref())?;
214 let file_size = file.metadata()?.len();
215 if file_size == 0 {
216 return Err(AerError::EmptyFile);
217 }
218 if file_size % self.config.bytes_per_event as u64 != 0 {
220 return Err(AerError::InvalidFileSize(
221 file_size,
222 self.config.bytes_per_event,
223 ));
224 }
225 let expected_event_count = (file_size / self.config.bytes_per_event as u64) as usize;
226 let event_count = match self.config.max_events {
227 Some(max) => expected_event_count.min(max),
228 None => expected_event_count,
229 };
230 let mut buffer = vec![0u8; event_count * self.config.bytes_per_event];
232 file.read_exact(&mut buffer)?;
233 let (events, metadata) = self.parse_events(&buffer, file_size)?;
235 Ok((events, metadata))
236 }
237 fn parse_events(&self, data: &[u8], file_size: u64) -> AerResult<(DataFrame, AerMetadata)> {
239 if self.config.bytes_per_event != 2 && self.config.bytes_per_event != 4 {
240 return Err(AerError::InvalidBytesPerEvent(self.config.bytes_per_event));
241 }
242 {
243 let event_count = data.len() / self.config.bytes_per_event;
244 let mut builder = EventDataFrameBuilder::new(EventFormat::AER, event_count);
245 let mut min_x = u16::MAX;
247 let mut min_y = u16::MAX;
248 let mut max_x = 0u16;
249 let mut max_y = 0u16;
250 let mut positive_count = 0;
251 let mut negative_count = 0;
252 let mut valid_events = 0;
253 let mut parsed_events = Vec::with_capacity(event_count);
255 for i in 0..event_count {
257 let offset = i * self.config.bytes_per_event;
258 match self
259 .parse_single_event(&data[offset..offset + self.config.bytes_per_event], i)
260 {
261 Ok((x, y, t, polarity)) => {
262 min_x = min_x.min(x);
264 min_y = min_y.min(y);
265 max_x = max_x.max(x);
266 max_y = max_y.max(y);
267 if polarity {
268 positive_count += 1;
269 } else {
270 negative_count += 1;
271 }
272 parsed_events.push((x, y, t, polarity));
273 valid_events += 1;
274 }
275 Err(e) => {
276 if self.config.skip_invalid_events {
277 continue;
278 } else {
279 return Err(e);
280 }
281 }
282 }
283 }
284 if self.config.generate_timestamps {
286 self.generate_timestamps_for_parsed_events(&mut parsed_events)?;
287 }
288 for (x, y, timestamp, polarity) in &parsed_events {
297 let microseconds = (*timestamp * 1_000_000.0).round() as i64;
298 builder.add_event_microseconds(*x, *y, microseconds, *polarity);
299 }
300 let events = builder.build().map_err(|e| {
301 AerError::Io(std::io::Error::new(
302 std::io::ErrorKind::InvalidData,
303 format!("Failed to build DataFrame: {}", e),
304 ))
305 })?;
306 let timestamp_range = if !parsed_events.is_empty() {
307 Some((parsed_events[0].2, parsed_events[parsed_events.len() - 1].2))
308 } else {
309 None
310 };
311 let coordinate_bounds = if valid_events > 0 {
312 Some((min_x, min_y, max_x, max_y))
313 } else {
314 None
315 };
316 let metadata = AerMetadata {
317 file_size,
318 event_count: valid_events,
319 bytes_per_event: self.config.bytes_per_event,
320 endianness: if self.config.big_endian {
321 "big".to_string()
322 } else {
323 "little".to_string()
324 },
325 coordinate_bounds,
326 timestamp_range,
327 polarity_distribution: Some((positive_count, negative_count)),
328 };
329 Ok((events, metadata))
330 }
331 }
332 fn parse_single_event(
334 &self,
335 data: &[u8],
336 _event_index: usize,
337 ) -> AerResult<(u16, u16, f64, bool)> {
338 if data.len() < self.config.bytes_per_event {
339 return Err(AerError::InsufficientData(
340 self.config.bytes_per_event,
341 data.len(),
342 ));
343 }
344 let raw_event = match self.config.bytes_per_event {
345 2 => {
346 if self.config.big_endian {
348 u16::from_be_bytes([data[0], data[1]]) as u32
349 } else {
350 u16::from_le_bytes([data[0], data[1]]) as u32
351 }
352 }
353 4 => {
354 if self.config.big_endian {
356 u32::from_be_bytes([data[0], data[1], data[2], data[3]])
357 } else {
358 u32::from_le_bytes([data[0], data[1], data[2], data[3]])
359 }
360 }
361 _ => {
362 return Err(AerError::InvalidBytesPerEvent(self.config.bytes_per_event));
363 }
364 };
365 let polarity_bit = (raw_event & 0x1) as u8;
367 let x = ((raw_event >> 1) & 0x1FF) as u16; let y = ((raw_event >> 10) & 0x1FF) as u16; let polarity = polarity_bit == 1;
371 if self.config.validate_coordinates && (x > self.config.max_x || y > self.config.max_y) {
373 return Err(AerError::InvalidCoordinate(
374 x,
375 y,
376 self.config.max_x,
377 self.config.max_y,
378 ));
379 }
380 Ok((x, y, 0.0, polarity))
382 }
383 fn generate_timestamps_for_parsed_events(
385 &self,
386 events: &mut [(u16, u16, f64, bool)],
387 ) -> AerResult<()> {
388 if events.is_empty() {
389 return Ok(());
390 }
391 match &self.config.timestamp_mode {
392 TimestampMode::Sequential => {
393 for (i, event) in events.iter_mut().enumerate() {
394 event.2 = self.config.start_timestamp + (i as f64 * self.config.time_increment);
395 }
396 }
397 TimestampMode::Uniform => {
398 let total_time = events.len() as f64 * self.config.time_increment;
399 let event_count = events.len();
400 for (i, event) in events.iter_mut().enumerate() {
401 event.2 =
402 self.config.start_timestamp + (i as f64 / event_count as f64) * total_time;
403 }
404 }
405 TimestampMode::Exponential => {
406 let mut current_time = self.config.start_timestamp;
408 let lambda = 1.0 / self.config.time_increment; for event in events.iter_mut() {
410 let u: f64 = (fastrand::f64() + 1e-10).ln(); let interval = -u / lambda;
413 current_time += interval;
414 event.2 = current_time;
415 }
416 }
417 TimestampMode::Custom(timestamps) => {
418 if timestamps.len() != events.len() {
419 let timestamp_count = timestamps.len();
420 let event_count = events.len();
421 return Err(AerError::ValidationFailed(format!(
422 "Custom timestamp count ({timestamp_count}) doesn't match event count ({event_count})"
423 )));
424 }
425 for (event, ×tamp) in events.iter_mut().zip(timestamps.iter()) {
426 event.2 = timestamp;
427 }
428 }
429 }
430 Ok(())
431 }
432 pub fn read_with_config<P: AsRef<Path>>(
434 &self,
435 path: P,
436 load_config: &LoadConfig,
437 ) -> AerResult<DataFrame> {
438 let (events, _metadata) = self.read_file(path)?;
439 {
440 let mut df = events.lazy();
442 if load_config.sort {
446 df = df.sort(["t"], Default::default());
447 }
448 df.collect().map_err(|e| {
449 AerError::Io(std::io::Error::new(
450 std::io::ErrorKind::InvalidData,
451 format!("Failed to process DataFrame: {}", e),
452 ))
453 })
454 }
455 }
456 pub fn config(&self) -> &AerConfig {
458 &self.config
459 }
460}
461impl Default for AerReader {
462 fn default() -> Self {
463 Self::new()
464 }
465}
466pub fn read_aer_file<P: AsRef<Path>>(path: P) -> AerResult<(DataFrame, AerMetadata)> {
468 let reader = AerReader::new();
469 reader.read_file(path)
470}
471pub fn read_aer_file_with_config<P: AsRef<Path>>(
473 path: P,
474 config: AerConfig,
475) -> AerResult<(DataFrame, AerMetadata)> {
476 let reader = AerReader::with_config(config);
477 reader.read_file(path)
478}
479pub fn is_aer_format<P: AsRef<Path>>(path: P) -> bool {
481 let file = match File::open(path.as_ref()) {
482 Ok(f) => f,
483 Err(_) => return false,
484 };
485 let file_size = match file.metadata() {
486 Ok(m) => m.len(),
487 Err(_) => return false,
488 };
489 if file_size % 4 != 0 && file_size % 2 != 0 {
491 return false;
492 }
493 let bytes_to_read = std::cmp::min(32, file_size as usize);
495 let mut buffer = vec![0u8; bytes_to_read];
496 let mut file = file;
497 if file.read_exact(&mut buffer).is_err() {
498 return false;
499 }
500 let config = AerConfig::default();
502 let reader = AerReader::with_config(config);
503 for i in 0..8 {
504 let offset = i * 4;
505 if offset + 4 > buffer.len() {
506 break;
507 }
508 if reader
509 .parse_single_event(&buffer[offset..offset + 4], i)
510 .is_err()
511 {
512 return false;
513 }
514 }
515 true
516}
517#[cfg(test)]
518mod tests {
519 use super::*;
520 use std::io::Write;
521 use tempfile::NamedTempFile;
522
523 #[derive(Debug, Clone, Copy)]
525 struct EventRow {
526 t: f64, x: u16,
528 y: u16,
529 polarity: i8, }
531
532 fn dataframe_to_rows(df: &polars::prelude::DataFrame) -> Vec<EventRow> {
533 let x = df.column("x").unwrap().i16().unwrap();
534 let y = df.column("y").unwrap().i16().unwrap();
535 let t = df.column("t").unwrap().duration().unwrap();
536 let p = df.column("polarity").unwrap().i8().unwrap();
537 (0..df.height())
538 .map(|i| EventRow {
539 t: t.get(i).unwrap() as f64 / 1_000_000.0,
540 x: x.get(i).unwrap() as u16,
541 y: y.get(i).unwrap() as u16,
542 polarity: p.get(i).unwrap(),
543 })
544 .collect()
545 }
546
547 #[test]
548 fn test_aer_config_default() {
549 let config = AerConfig::default();
550 assert!(!config.big_endian);
551 assert!(config.validate_coordinates);
552 assert_eq!(config.max_x, 511);
553 assert_eq!(config.max_y, 511);
554 assert_eq!(config.bytes_per_event, 4);
555 assert!(config.generate_timestamps);
556 assert_eq!(config.timestamp_mode, TimestampMode::Sequential);
557 }
558 #[test]
559 fn test_aer_config_builder() {
560 let config = AerConfig::new()
561 .with_endianness(true)
562 .with_coordinate_bounds(1023, 1023)
563 .with_bytes_per_event(2)
564 .with_validation(true, true);
565 assert!(config.big_endian);
566 assert_eq!(config.max_x, 1023);
567 assert_eq!(config.max_y, 1023);
568 assert_eq!(config.bytes_per_event, 2);
569 assert!(config.skip_invalid_events);
570 }
571 #[test]
572 fn test_parse_18bit_aer_event() {
573 let config = AerConfig::default();
574 let reader = AerReader::with_config(config);
575 let raw_event = 205001u32;
578 let data = raw_event.to_le_bytes();
579 let event = reader.parse_single_event(&data, 0).unwrap();
580 assert_eq!(event.0, 100); assert_eq!(event.1, 200); assert!(event.3); }
584 #[test]
585 fn test_parse_negative_polarity() {
586 let config = AerConfig::default();
587 let reader = AerReader::with_config(config);
588 let raw_event = 76900u32;
591 let data = raw_event.to_le_bytes();
592 let event = reader.parse_single_event(&data, 0).unwrap();
593 assert_eq!(event.0, 50); assert_eq!(event.1, 75); assert!(!event.3); }
597 #[test]
598 fn test_coordinate_validation() {
599 let config = AerConfig::default().with_coordinate_bounds(100, 100);
600 let reader = AerReader::with_config(config);
601 let raw_event = (200u32 << 10) | (150u32 << 1) | 1; let data = raw_event.to_le_bytes();
604 let result = reader.parse_single_event(&data, 0);
605 assert!(result.is_err());
606 assert!(matches!(
607 result.unwrap_err(),
608 AerError::InvalidCoordinate(_, _, _, _)
609 ));
610 }
611 #[test]
612 fn test_skip_invalid_events() {
613 let config = AerConfig::default()
614 .with_coordinate_bounds(100, 100)
615 .with_validation(true, true); let reader = AerReader::with_config(config);
617 let mut data = Vec::new();
619 let valid_event = (75u32 << 10) | (50u32 << 1) | 1;
621 data.extend_from_slice(&valid_event.to_le_bytes());
622 let invalid_event = (200u32 << 10) | (150u32 << 1);
624 data.extend_from_slice(&invalid_event.to_le_bytes());
625 let valid_event2 = (30u32 << 10) | (25u32 << 1);
627 data.extend_from_slice(&valid_event2.to_le_bytes());
628 let (events, metadata) = reader.parse_events(&data, data.len() as u64).unwrap();
629 assert_eq!(events.height(), 2); assert_eq!(metadata.event_count, 2);
631 let rows = dataframe_to_rows(&events);
632 assert_eq!(rows[0].x, 50);
633 assert_eq!(rows[0].y, 75);
634 assert_eq!(rows[1].x, 25);
635 assert_eq!(rows[1].y, 30);
636 }
637 #[test]
638 fn test_timestamp_generation_sequential() {
639 let config = AerConfig::default().with_timestamp_generation(
640 true,
641 TimestampMode::Sequential,
642 1.0,
643 0.001,
644 );
645 let reader = AerReader::with_config(config);
646 let events_data = vec![
648 ((100u32 << 10) | (50u32 << 1) | 1).to_le_bytes(),
649 ((200u32 << 10) | (150u32 << 1)).to_le_bytes(),
650 ((300u32 << 10) | (250u32 << 1) | 1).to_le_bytes(),
651 ];
652 let data: Vec<u8> = events_data.into_iter().flatten().collect();
653 let (events, _) = reader.parse_events(&data, data.len() as u64).unwrap();
654 assert_eq!(events.height(), 3);
655 let t = events.column("t").unwrap().duration().unwrap();
661 assert_eq!(t.get(0).unwrap(), 1_000_000); assert_eq!(t.get(1).unwrap(), 1_001_000); assert_eq!(t.get(2).unwrap(), 1_002_000); }
665 #[test]
666 fn test_timestamp_generation_uniform() {
667 let config = AerConfig::default().with_timestamp_generation(
668 true,
669 TimestampMode::Uniform,
670 0.0,
671 0.003,
672 );
673 let reader = AerReader::with_config(config);
674 let events_data = vec![
676 ((100u32 << 10) | (50u32 << 1) | 1).to_le_bytes(),
677 ((200u32 << 10) | (150u32 << 1)).to_le_bytes(),
678 ((300u32 << 10) | (250u32 << 1) | 1).to_le_bytes(),
679 ];
680 let data: Vec<u8> = events_data.into_iter().flatten().collect();
681 let (events, _) = reader.parse_events(&data, data.len() as u64).unwrap();
682 assert_eq!(events.height(), 3);
683 let rows = dataframe_to_rows(&events);
684 assert_eq!(rows[0].t, 0.0);
685 assert_eq!(rows[1].t, 0.003);
686 assert_eq!(rows[2].t, 0.006);
687 }
688 #[test]
689 fn test_big_endian_parsing() {
690 let config = AerConfig::default().with_endianness(true);
691 let reader = AerReader::with_config(config);
692 let raw_event = 205001u32;
694 let data = raw_event.to_be_bytes(); let event = reader.parse_single_event(&data, 0).unwrap();
696 assert_eq!(event.0, 100); assert_eq!(event.1, 200); assert!(event.3); }
700 #[test]
701 fn test_16bit_format() {
702 let config = AerConfig::default().with_bytes_per_event(2);
703 let reader = AerReader::with_config(config);
704 let raw_event = (75u16 << 8) | (50u16 << 1) | 1; let data = raw_event.to_le_bytes();
709 let event = reader.parse_single_event(&data, 0).unwrap();
710 assert!(event.3); }
713 #[test]
714 fn test_read_aer_file() {
715 let config = AerConfig::default();
716 let reader = AerReader::with_config(config);
717 let mut temp_file = NamedTempFile::new().unwrap();
719 let events_data = vec![
721 ((100u32 << 10) | (50u32 << 1) | 1).to_le_bytes(),
722 ((200u32 << 10) | (150u32 << 1)).to_le_bytes(),
723 ((300u32 << 10) | (250u32 << 1) | 1).to_le_bytes(),
724 ];
725 for event_bytes in events_data {
726 temp_file.write_all(&event_bytes).unwrap();
727 }
728 let (events, metadata) = reader.read_file(temp_file.path()).unwrap();
729 assert_eq!(events.height(), 3);
730 assert_eq!(metadata.event_count, 3);
731 assert_eq!(metadata.bytes_per_event, 4);
732 assert_eq!(metadata.file_size, 12);
733 let rows = dataframe_to_rows(&events);
735 assert_eq!(rows[0].x, 50);
736 assert_eq!(rows[0].y, 100);
737 assert_eq!(rows[0].polarity, 1); assert!(metadata.coordinate_bounds.is_some());
740 assert!(metadata.polarity_distribution.is_some());
741 let (pos_count, neg_count) = metadata.polarity_distribution.unwrap();
742 assert_eq!(pos_count, 2);
743 assert_eq!(neg_count, 1);
744 }
745 #[test]
746 fn test_empty_file() {
747 let config = AerConfig::default();
748 let reader = AerReader::with_config(config);
749 let temp_file = NamedTempFile::new().unwrap();
750 let result = reader.read_file(temp_file.path());
751 assert!(result.is_err());
752 assert!(matches!(result.unwrap_err(), AerError::EmptyFile));
753 }
754 #[test]
755 fn test_invalid_file_size() {
756 let config = AerConfig::default();
757 let reader = AerReader::with_config(config);
758 let mut temp_file = NamedTempFile::new().unwrap();
759 temp_file.write_all(&[1, 2, 3]).unwrap(); let result = reader.read_file(temp_file.path());
761 assert!(result.is_err());
762 assert!(matches!(
763 result.unwrap_err(),
764 AerError::InvalidFileSize(_, _)
765 ));
766 }
767 #[test]
768 fn test_custom_timestamps() {
769 let custom_timestamps = vec![0.1, 0.5, 1.2];
770 let config = AerConfig::default().with_timestamp_generation(
771 true,
772 TimestampMode::Custom(custom_timestamps.clone()),
773 0.0,
774 0.001,
775 );
776 let reader = AerReader::with_config(config);
777 let events_data = vec![
779 ((100u32 << 10) | (50u32 << 1) | 1).to_le_bytes(),
780 ((200u32 << 10) | (150u32 << 1)).to_le_bytes(),
781 ((300u32 << 10) | (250u32 << 1) | 1).to_le_bytes(),
782 ];
783 let data: Vec<u8> = events_data.into_iter().flatten().collect();
784 let (events, _) = reader.parse_events(&data, data.len() as u64).unwrap();
785 assert_eq!(events.height(), 3);
786 let rows = dataframe_to_rows(&events);
787 assert_eq!(rows[0].t, 0.1);
788 assert_eq!(rows[1].t, 0.5);
789 assert_eq!(rows[2].t, 1.2);
790 }
791 #[test]
792 fn test_is_aer_format() {
793 let mut temp_file = NamedTempFile::new().unwrap();
795 let events_data = vec![
796 ((100u32 << 10) | (50u32 << 1) | 1).to_le_bytes(),
797 ((200u32 << 10) | (150u32 << 1)).to_le_bytes(),
798 ];
799 for event_bytes in events_data {
800 temp_file.write_all(&event_bytes).unwrap();
801 }
802 assert!(is_aer_format(temp_file.path()));
803 }
804 #[test]
805 fn test_max_events_limit() {
806 let config = AerConfig::default().with_max_events(Some(2));
807 let reader = AerReader::with_config(config);
808 let mut temp_file = NamedTempFile::new().unwrap();
809 let events_data = vec![
811 ((100u32 << 10) | (50u32 << 1) | 1).to_le_bytes(),
812 ((200u32 << 10) | (150u32 << 1)).to_le_bytes(),
813 ((300u32 << 10) | (250u32 << 1) | 1).to_le_bytes(),
814 ];
815 for event_bytes in events_data {
816 temp_file.write_all(&event_bytes).unwrap();
817 }
818 let (events, metadata) = reader.read_file(temp_file.path()).unwrap();
819 assert_eq!(events.height(), 2);
820 assert_eq!(metadata.event_count, 2);
821 }
822}