wellen/
viewers.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Copyright 2023-2024 The Regents of the University of California
// released under BSD 3-Clause License
// author: Kevin Laeufer <laeufer@berkeley.edu>
//
// Interface for waveform viewers

use crate::{FileFormat, Hierarchy, LoadOptions, Result, SignalSource, TimeTable, WellenError};
use std::io::{BufRead, Seek};

impl From<crate::ghw::GhwParseError> for WellenError {
    fn from(value: crate::ghw::GhwParseError) -> Self {
        WellenError::FailedToLoad(FileFormat::Ghw, value.to_string())
    }
}

impl From<crate::vcd::VcdParseError> for WellenError {
    fn from(value: crate::vcd::VcdParseError) -> Self {
        WellenError::FailedToLoad(FileFormat::Vcd, value.to_string())
    }
}

impl From<fst_reader::ReaderError> for WellenError {
    fn from(value: fst_reader::ReaderError) -> Self {
        WellenError::FailedToLoad(FileFormat::Fst, value.to_string())
    }
}

pub struct HeaderResult {
    pub hierarchy: Hierarchy,
    pub file_format: FileFormat,
    /// Body length in bytes.
    pub body_len: u64,
    pub body: ReadBodyContinuation,
}

pub fn read_header<P: AsRef<std::path::Path>>(
    filename: P,
    options: &LoadOptions,
) -> Result<HeaderResult> {
    let file_format = open_and_detect_file_format(filename.as_ref());
    match file_format {
        FileFormat::Unknown => Err(WellenError::UnknownFileFormat),
        FileFormat::Vcd => {
            let (hierarchy, body, body_len) = crate::vcd::read_header(filename, options)?;
            let body = ReadBodyContinuation::new(ReadBodyData::Vcd(body));
            Ok(HeaderResult {
                hierarchy,
                file_format,
                body_len,
                body,
            })
        }
        FileFormat::Ghw => {
            let (hierarchy, body, body_len) = crate::ghw::read_header(filename, options)?;
            let body = ReadBodyContinuation::new(ReadBodyData::Ghw(body));
            Ok(HeaderResult {
                hierarchy,
                file_format,
                body_len,
                body,
            })
        }
        FileFormat::Fst => {
            let (hierarchy, body) = crate::fst::read_header(filename, options)?;
            let body = ReadBodyContinuation::new(ReadBodyData::Fst(body));
            Ok(HeaderResult {
                hierarchy,
                file_format,
                body_len: 0, // fst never reads the full body (unless all signals are displayed)
                body,
            })
        }
    }
}

pub fn read_header_from_bytes(bytes: Vec<u8>, options: &LoadOptions) -> Result<HeaderResult> {
    let file_format = {
        let mut cursor = &mut std::io::Cursor::new(&bytes);
        detect_file_format(&mut cursor)
    };
    match file_format {
        FileFormat::Unknown => Err(WellenError::UnknownFileFormat),
        FileFormat::Vcd => {
            let (hierarchy, body, body_len) = crate::vcd::read_header_from_bytes(bytes, options)?;
            let body = ReadBodyContinuation::new(ReadBodyData::Vcd(body));
            Ok(HeaderResult {
                hierarchy,
                file_format,
                body_len,
                body,
            })
        }
        FileFormat::Ghw => {
            let (hierarchy, body, body_len) = crate::ghw::read_header_from_bytes(bytes, options)?;
            let body = ReadBodyContinuation::new(ReadBodyData::Ghw(body));
            Ok(HeaderResult {
                hierarchy,
                file_format,
                body_len,
                body,
            })
        }
        FileFormat::Fst => {
            let (hierarchy, body) = crate::fst::read_header_from_bytes(bytes, options)?;
            let body = ReadBodyContinuation::new(ReadBodyData::Fst(body));
            Ok(HeaderResult {
                hierarchy,
                file_format,
                body_len: 0, // fst never reads the full body (unless all signals are displayed)
                body,
            })
        }
    }
}

pub struct ReadBodyContinuation {
    data: ReadBodyData,
}

impl ReadBodyContinuation {
    fn new(data: ReadBodyData) -> Self {
        Self { data }
    }
}

enum ReadBodyData {
    Vcd(crate::vcd::ReadBodyContinuation),
    Fst(crate::fst::ReadBodyContinuation),
    Ghw(crate::ghw::ReadBodyContinuation),
}

pub struct BodyResult {
    pub source: SignalSource,
    pub time_table: TimeTable,
}

pub type ProgressCount = std::sync::Arc<std::sync::atomic::AtomicU64>;

pub fn read_body(
    body: ReadBodyContinuation,
    hierarchy: &Hierarchy,
    progress: Option<ProgressCount>,
) -> Result<BodyResult> {
    match body.data {
        ReadBodyData::Vcd(data) => {
            let (source, time_table) = crate::vcd::read_body(data, hierarchy, progress)?;
            Ok(BodyResult { source, time_table })
        }
        ReadBodyData::Fst(data) => {
            // fst does not support a progress count since it is no actually reading the body
            let (source, time_table) = crate::fst::read_body(data)?;
            Ok(BodyResult { source, time_table })
        }
        ReadBodyData::Ghw(data) => {
            let (source, time_table) = crate::ghw::read_body(data, hierarchy, progress)?;
            Ok(BodyResult { source, time_table })
        }
    }
}

/// Tries to guess the format of the file.
pub fn open_and_detect_file_format<P: AsRef<std::path::Path>>(filename: P) -> FileFormat {
    let input_file = std::fs::File::open(filename).expect("failed to open input file!");
    let mut reader = std::io::BufReader::new(input_file);
    detect_file_format(&mut reader)
}

/// Tries to guess the file format used by the input.
fn detect_file_format(input: &mut (impl BufRead + Seek)) -> FileFormat {
    if crate::vcd::is_vcd(input) {
        FileFormat::Vcd
    } else if fst_reader::is_fst_file(input) {
        FileFormat::Fst
    } else if crate::ghw::is_ghw(input) {
        FileFormat::Ghw
    } else {
        FileFormat::Unknown
    }
}