Compare commits
No commits in common. "main" and "name_width_separation" have entirely different histories.
main
...
name_width
|
@ -1,4 +1,4 @@
|
||||||
Copyright(2023) - Yehowshua Immanuel
|
Copyright - Yehowshua Immanuel
|
||||||
|
|
||||||
# Vision
|
# Vision
|
||||||
Imagine being able to visualize a CPU pipeline diagram by merely loading a simulation waveform dump, sprinkling in a bit of code, and dragging and dropping some diagram blocks into the visualizer. This project aims to offer such an experience.
|
Imagine being able to visualize a CPU pipeline diagram by merely loading a simulation waveform dump, sprinkling in a bit of code, and dragging and dropping some diagram blocks into the visualizer. This project aims to offer such an experience.
|
||||||
|
@ -6,7 +6,10 @@ Imagine being able to visualize a CPU pipeline diagram by merely loading a simul
|
||||||
Since this project is written in Rust, it should also be able to run in the browser via web-assembly.
|
Since this project is written in Rust, it should also be able to run in the browser via web-assembly.
|
||||||
|
|
||||||
# Status
|
# Status
|
||||||
As of January 2024, work on the Fastwave Backend is stalled. It has been a fun journey watching Fastwave enable the first iterations of the [surfer waveform viewer](https://surfer-project.org). Now surfer uses an even better backend called [Wellen](https://github.com/ekiwi/wellen?tab=readme-ov-file). Go check it out! I hear it's really good. Perhaps I will soon archive the Fastwave Backend.
|
I hope to work on this more actively again soon.
|
||||||
|
|
||||||
|
The Zoq is is working on an excellent frontend call the Surfer. Check it out
|
||||||
|
[here](https://gitlab.com/surfer-project/surfer)!
|
||||||
|
|
||||||
Browser demo: https://app.surfer-project.org/
|
Browser demo: https://app.surfer-project.org/
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
mod vcd;
|
mod vcd;
|
||||||
pub use vcd::parse::parse_vcd;
|
pub use vcd::parse::parse_vcd;
|
||||||
pub use vcd::signal::{Signal, SignalType, SignalValue, SignalErrors};
|
pub use vcd::signal::{Signal, SignalType, SignalValue};
|
||||||
pub use vcd::types::{Metadata, Timescale, Version};
|
pub use vcd::types::{Metadata, Timescale, Version};
|
||||||
pub use vcd::types::{ScopeIdx, SignalIdx, VCD};
|
pub use vcd::types::{ScopeIdx, SignalIdx, VCD};
|
||||||
|
|
||||||
|
|
|
@ -289,10 +289,7 @@ fn parse_scopes_inner<R: std::io::Read>(
|
||||||
// $scope module reg_mag_i $end
|
// $scope module reg_mag_i $end
|
||||||
// ^^^^^^^^^ - scope name
|
// ^^^^^^^^^ - scope name
|
||||||
let (scope_name, _) = next_word!(word_reader)?;
|
let (scope_name, _) = next_word!(word_reader)?;
|
||||||
// In some cases there are VCD files which have scopes without names.
|
|
||||||
// since these occur in the wild, we'll tolerate them even if it is unclear
|
|
||||||
// if it is supported or not by the spec.
|
|
||||||
if scope_name != "$end" {
|
|
||||||
let mut path = path.clone();
|
let mut path = path.clone();
|
||||||
path.push(scope_name.to_string());
|
path.push(scope_name.to_string());
|
||||||
|
|
||||||
|
@ -376,70 +373,6 @@ fn parse_scopes_inner<R: std::io::Read>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// We'll be conservative and only allow new scopes in this case, and make the nameless
|
|
||||||
// scope completely transparent. I.e.
|
|
||||||
// $scope module a $end
|
|
||||||
// $scope module $end
|
|
||||||
// $scope module b $end
|
|
||||||
// ...
|
|
||||||
// $upscope
|
|
||||||
// $upscope
|
|
||||||
// $upscope
|
|
||||||
// will create `a.b`
|
|
||||||
loop {
|
|
||||||
let (word, cursor) = next_word!(word_reader)?;
|
|
||||||
let ParseResult { matched, residual } = tag(word, "$");
|
|
||||||
match matched {
|
|
||||||
// we hope that this word starts with a `$`
|
|
||||||
"$" => {
|
|
||||||
match residual {
|
|
||||||
"scope" => {
|
|
||||||
// recursive - parse inside of current scope tree
|
|
||||||
parse_scopes_inner(
|
|
||||||
word_reader,
|
|
||||||
parent_scope_idx,
|
|
||||||
vcd,
|
|
||||||
signal_map,
|
|
||||||
&path,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
"upscope" => {
|
|
||||||
ident(word_reader, "$end")?;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// we ignore comments
|
|
||||||
"comment" => loop {
|
|
||||||
if ident(word_reader, "$end").is_ok() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
let err = format!(
|
|
||||||
"Error near {}:{}. \
|
|
||||||
found keyword `{residual}` in annonyoums scope but expected \
|
|
||||||
`$scope`, `$comment`, or `$upscope` \
|
|
||||||
on {cursor:?}",
|
|
||||||
file!(),
|
|
||||||
line!()
|
|
||||||
);
|
|
||||||
return Err(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let err = format!(
|
|
||||||
"Error near {}:{}. \
|
|
||||||
found keyword `{matched}` but \
|
|
||||||
expected `$` on {cursor:?}",
|
|
||||||
file!(),
|
|
||||||
line!()
|
|
||||||
);
|
|
||||||
return Err(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use num::BigUint;
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct LsbIdxOfTmstmpValOnTmln(pub(super) u32);
|
pub struct LsbIdxOfTmstmpValOnTmln(pub(super) u32);
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub enum SignalType {
|
pub enum SignalType {
|
||||||
Event,
|
Event,
|
||||||
Integer,
|
Integer,
|
||||||
|
@ -40,11 +40,6 @@ pub enum SignalValue {
|
||||||
String(String),
|
String(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct QueryResult<T> {
|
|
||||||
pub current: Option<(TimeStamp, T)>,
|
|
||||||
pub next: Option<TimeStamp>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Signal<'a>(pub(super) &'a SignalEnum);
|
pub struct Signal<'a>(pub(super) &'a SignalEnum);
|
||||||
|
|
||||||
impl<'a> Signal<'a> {
|
impl<'a> Signal<'a> {
|
||||||
|
@ -53,16 +48,11 @@ impl<'a> Signal<'a> {
|
||||||
signal_enum.name()
|
signal_enum.name()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name_with_index(&self) -> String {
|
pub fn name_with_size(&self) -> String {
|
||||||
let Signal(signal_enum) = &self;
|
let Signal(signal_enum) = &self;
|
||||||
signal_enum.name_with_index()
|
signal_enum.name_with_index()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn index(&self) -> Option<String> {
|
|
||||||
let Signal(signal_enum) = &self;
|
|
||||||
signal_enum.index()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn path(&self) -> &[String] {
|
pub fn path(&self) -> &[String] {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
SignalEnum::Data { path, .. } => path,
|
SignalEnum::Data { path, .. } => path,
|
||||||
|
@ -87,9 +77,6 @@ impl<'a> Signal<'a> {
|
||||||
signal_enum.bits_required()
|
signal_enum.bits_required()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: (zoq) I am removing thse because they aren't used in Surfer so I can't test them
|
|
||||||
// properly
|
|
||||||
/*
|
|
||||||
pub fn query_string_val_on_tmln(
|
pub fn query_string_val_on_tmln(
|
||||||
&self,
|
&self,
|
||||||
desired_time: &BigUint,
|
desired_time: &BigUint,
|
||||||
|
@ -98,33 +85,32 @@ impl<'a> Signal<'a> {
|
||||||
let Signal(signal_enum) = &self;
|
let Signal(signal_enum) = &self;
|
||||||
signal_enum
|
signal_enum
|
||||||
.query_string_val_on_tmln(desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals)
|
.query_string_val_on_tmln(desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals)
|
||||||
.map(|QueryResult{current, next: _}| current.map(|c| c.1))
|
.map(|(val, _)| val)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn query_num_val_on_tmln(
|
pub fn query_num_val_on_tmln(
|
||||||
&self,
|
&self,
|
||||||
desired_time: &BigUint,
|
desired_time: &BigUint,
|
||||||
vcd: &types::VCD,
|
vcd: &types::VCD,
|
||||||
) -> Result<Option<BigUint>, SignalErrors> {
|
) -> Result<BigUint, SignalErrors> {
|
||||||
let Signal(signal_enum) = &self;
|
let Signal(signal_enum) = &self;
|
||||||
signal_enum
|
signal_enum
|
||||||
.query_num_val_on_tmln(desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals)
|
.query_num_val_on_tmln(desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals)
|
||||||
.map(|QueryResult{current, next: _}| current.map(|c| c.1))
|
.map(|(val, _)| val)
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
pub fn query_val_on_tmln(
|
pub fn query_val_on_tmln(
|
||||||
&self,
|
&self,
|
||||||
desired_time: &BigUint,
|
desired_time: &BigUint,
|
||||||
vcd: &types::VCD,
|
vcd: &types::VCD,
|
||||||
) -> Result<QueryResult<SignalValue>, SignalErrors> {
|
) -> Result<(TimeStamp, SignalValue), SignalErrors> {
|
||||||
let Signal(signal_enum) = &self;
|
let Signal(signal_enum) = &self;
|
||||||
let num_query_out = signal_enum.query_num_val_on_tmln(
|
let num_val = signal_enum.query_num_val_on_tmln(
|
||||||
desired_time,
|
desired_time,
|
||||||
&vcd.tmstmps_encoded_as_u8s,
|
&vcd.tmstmps_encoded_as_u8s,
|
||||||
&vcd.all_signals,
|
&vcd.all_signals,
|
||||||
);
|
);
|
||||||
let str_query_out = signal_enum.query_string_val_on_tmln(
|
let str_val = signal_enum.query_string_val_on_tmln(
|
||||||
desired_time,
|
desired_time,
|
||||||
&vcd.tmstmps_encoded_as_u8s,
|
&vcd.tmstmps_encoded_as_u8s,
|
||||||
&vcd.all_signals,
|
&vcd.all_signals,
|
||||||
|
@ -133,44 +119,16 @@ impl<'a> Signal<'a> {
|
||||||
// Both num and str will return the newest value that is closest to
|
// Both num and str will return the newest value that is closest to
|
||||||
// the desired time. If both have valid values, select the most recent
|
// the desired time. If both have valid values, select the most recent
|
||||||
// one
|
// one
|
||||||
match (num_query_out, str_query_out) {
|
match (num_val, str_val) {
|
||||||
(Ok(num_result), Ok(str_result)) => {
|
(Ok((num_val, num_time)), Ok((str_val, str_time))) => {
|
||||||
let next = match (num_result.next, str_result.next) {
|
|
||||||
(Some(n), Some(s)) => Some(n.min(s)),
|
|
||||||
(Some(n), None) => Some(n),
|
|
||||||
(None, Some(s)) => Some(s),
|
|
||||||
(None, None) => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
match (num_result.current, str_result.current) {
|
|
||||||
(Some((num_time, num_value)), Some((str_time, str_value))) => {
|
|
||||||
if num_time > str_time {
|
if num_time > str_time {
|
||||||
Ok(QueryResult {
|
Ok((num_time, SignalValue::BigUint(num_val)))
|
||||||
current: Some((num_time, SignalValue::BigUint(num_value))),
|
|
||||||
next,
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
Ok(QueryResult {
|
Ok((str_time, SignalValue::String(str_val)))
|
||||||
current: Some((str_time, SignalValue::String(str_value))),
|
|
||||||
next,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Some((num_time, num_val)), None) => Ok(QueryResult {
|
(Ok((num_val, time)), Err(_)) => Ok((time, SignalValue::BigUint(num_val))),
|
||||||
current: Some((num_time, SignalValue::BigUint(num_val))),
|
(Err(_), Ok((str_val, time))) => Ok((time, SignalValue::String(str_val))),
|
||||||
next,
|
|
||||||
}),
|
|
||||||
(None, Some((str_time, str_value))) => Ok(QueryResult {
|
|
||||||
current: Some((str_time, SignalValue::String(str_value))),
|
|
||||||
next,
|
|
||||||
}),
|
|
||||||
(None, None) => Ok(QueryResult {
|
|
||||||
current: None,
|
|
||||||
next,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(_e, Err(e)) => Err(e),
|
|
||||||
(Err(e), _e) => Err(e),
|
(Err(e), _e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,6 +187,10 @@ pub(super) enum SignalEnum {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SignalErrors {
|
pub enum SignalErrors {
|
||||||
|
PreTimeline {
|
||||||
|
desired_time: BigUint,
|
||||||
|
timeline_start_time: BigUint,
|
||||||
|
},
|
||||||
EmptyTimeline,
|
EmptyTimeline,
|
||||||
TimelineNotMultiple,
|
TimelineNotMultiple,
|
||||||
StrTmlnLenMismatch,
|
StrTmlnLenMismatch,
|
||||||
|
@ -278,13 +240,6 @@ impl SignalEnum {
|
||||||
SignalEnum::Alias { name, .. } => name.clone(),
|
SignalEnum::Alias { name, .. } => name.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn index(&self) -> Option<String> {
|
|
||||||
match self {
|
|
||||||
SignalEnum::Data { index, .. } => index.clone(),
|
|
||||||
SignalEnum::Alias { .. } => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper functions ultimately used by Signal's query functions later on
|
// helper functions ultimately used by Signal's query functions later on
|
||||||
|
@ -429,7 +384,7 @@ impl SignalEnum {
|
||||||
desired_time: &BigUint,
|
desired_time: &BigUint,
|
||||||
tmstmps_encoded_as_u8s: &Vec<u8>,
|
tmstmps_encoded_as_u8s: &Vec<u8>,
|
||||||
all_signals: &Vec<SignalEnum>,
|
all_signals: &Vec<SignalEnum>,
|
||||||
) -> Result<QueryResult<String>, SignalErrors> {
|
) -> Result<(String, TimeStamp), SignalErrors> {
|
||||||
let signal_idx = match self {
|
let signal_idx = match self {
|
||||||
Self::Data { self_idx, .. } => {
|
Self::Data { self_idx, .. } => {
|
||||||
let SignalIdx(idx) = self_idx;
|
let SignalIdx(idx) = self_idx;
|
||||||
|
@ -463,10 +418,7 @@ impl SignalEnum {
|
||||||
// this signal should at least have some events, otherwise, trying to index into
|
// this signal should at least have some events, otherwise, trying to index into
|
||||||
// an empty vector later on would fail
|
// an empty vector later on would fail
|
||||||
if lsb_indxs_of_string_tmstmp_vals_on_tmln.is_empty() {
|
if lsb_indxs_of_string_tmstmp_vals_on_tmln.is_empty() {
|
||||||
return Ok(QueryResult {
|
return Err(SignalErrors::EmptyTimeline);
|
||||||
current: None,
|
|
||||||
next: None
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the vector of string timeline lsb indices should have the same
|
// the vector of string timeline lsb indices should have the same
|
||||||
|
@ -480,9 +432,9 @@ impl SignalEnum {
|
||||||
let (timeline_start_time, _) =
|
let (timeline_start_time, _) =
|
||||||
self.time_and_str_val_at_event_idx(0, tmstmps_encoded_as_u8s)?;
|
self.time_and_str_val_at_event_idx(0, tmstmps_encoded_as_u8s)?;
|
||||||
if *desired_time < timeline_start_time {
|
if *desired_time < timeline_start_time {
|
||||||
return Ok(QueryResult {
|
return Err(SignalErrors::PreTimeline {
|
||||||
current: None,
|
desired_time: desired_time.clone(),
|
||||||
next: Some(timeline_start_time),
|
timeline_start_time,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,10 +446,7 @@ impl SignalEnum {
|
||||||
// check if we're requesting a value that occurs beyond the end of the timeline,
|
// check if we're requesting a value that occurs beyond the end of the timeline,
|
||||||
// if so, return the last value in this timeline
|
// if so, return the last value in this timeline
|
||||||
if *desired_time > timeline_end_time {
|
if *desired_time > timeline_end_time {
|
||||||
return Ok(QueryResult {
|
return Ok((timeline_end_val.to_string(), timeline_end_time));
|
||||||
current: Some((timeline_end_time, timeline_end_val.to_string())),
|
|
||||||
next: None,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This while loop is the meat of the lookup. Performance is log2(n),
|
// This while loop is the meat of the lookup. Performance is log2(n),
|
||||||
|
@ -516,21 +465,7 @@ impl SignalEnum {
|
||||||
lower_idx = mid_idx + 1;
|
lower_idx = mid_idx + 1;
|
||||||
}
|
}
|
||||||
std::cmp::Ordering::Equal => {
|
std::cmp::Ordering::Equal => {
|
||||||
let next_time = if mid_idx < lsb_indxs_of_string_tmstmp_vals_on_tmln.len() - 1 {
|
return Ok((curr_val.to_string(), curr_time));
|
||||||
Some(
|
|
||||||
self.time_and_str_val_at_event_idx(
|
|
||||||
mid_idx + 1,
|
|
||||||
tmstmps_encoded_as_u8s,
|
|
||||||
)?
|
|
||||||
.0,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
return Ok(QueryResult {
|
|
||||||
current: Some((curr_time, curr_val.to_string())),
|
|
||||||
next: next_time,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
std::cmp::Ordering::Greater => {
|
std::cmp::Ordering::Greater => {
|
||||||
upper_idx = mid_idx - 1;
|
upper_idx = mid_idx - 1;
|
||||||
|
@ -553,17 +488,14 @@ impl SignalEnum {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(QueryResult {
|
Ok((left_val.to_string(), left_time))
|
||||||
current: Some((left_time, left_val.to_string())),
|
|
||||||
next: Some(right_time),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
pub fn query_num_val_on_tmln(
|
pub fn query_num_val_on_tmln(
|
||||||
&self,
|
&self,
|
||||||
desired_time: &BigUint,
|
desired_time: &BigUint,
|
||||||
tmstmps_encoded_as_u8s: &Vec<u8>,
|
tmstmps_encoded_as_u8s: &Vec<u8>,
|
||||||
all_signals: &Vec<SignalEnum>,
|
all_signals: &Vec<SignalEnum>,
|
||||||
) -> Result<QueryResult<BigUint>, SignalErrors> {
|
) -> Result<(BigUint, TimeStamp), SignalErrors> {
|
||||||
let signal_idx = match self {
|
let signal_idx = match self {
|
||||||
Self::Data { self_idx, .. } => {
|
Self::Data { self_idx, .. } => {
|
||||||
let SignalIdx(idx) = self_idx;
|
let SignalIdx(idx) = self_idx;
|
||||||
|
@ -608,10 +540,7 @@ impl SignalEnum {
|
||||||
// this signal should at least have some events, otherwise, trying to index into
|
// this signal should at least have some events, otherwise, trying to index into
|
||||||
// an empty vector later on would fail
|
// an empty vector later on would fail
|
||||||
if lsb_indxs_of_num_tmstmp_vals_on_tmln.is_empty() {
|
if lsb_indxs_of_num_tmstmp_vals_on_tmln.is_empty() {
|
||||||
return Ok(QueryResult {
|
return Err(SignalErrors::EmptyTimeline);
|
||||||
current: None,
|
|
||||||
next: None
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// assertion that value_sequence is a proper multiple of
|
// assertion that value_sequence is a proper multiple of
|
||||||
|
@ -634,9 +563,9 @@ impl SignalEnum {
|
||||||
let (timeline_start_time, _) =
|
let (timeline_start_time, _) =
|
||||||
self.time_and_num_val_at_event_idx(0, tmstmps_encoded_as_u8s)?;
|
self.time_and_num_val_at_event_idx(0, tmstmps_encoded_as_u8s)?;
|
||||||
if *desired_time < timeline_start_time {
|
if *desired_time < timeline_start_time {
|
||||||
return Ok(QueryResult {
|
return Err(SignalErrors::PreTimeline {
|
||||||
current: None,
|
desired_time: desired_time.clone(),
|
||||||
next: Some(timeline_start_time),
|
timeline_start_time,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,10 +577,7 @@ impl SignalEnum {
|
||||||
// check if we're requesting a value that occurs beyond the end of the timeline,
|
// check if we're requesting a value that occurs beyond the end of the timeline,
|
||||||
// if so, return the last value in this timeline
|
// if so, return the last value in this timeline
|
||||||
if *desired_time > timeline_end_time {
|
if *desired_time > timeline_end_time {
|
||||||
return Ok(QueryResult {
|
return Ok((timeline_end_val, timeline_end_time));
|
||||||
current: Some((timeline_end_time, timeline_end_val)),
|
|
||||||
next: None,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This while loop is the meat of the lookup. Performance is log2(n),
|
// This while loop is the meat of the lookup. Performance is log2(n),
|
||||||
|
@ -670,21 +596,7 @@ impl SignalEnum {
|
||||||
lower_idx = mid_idx + 1;
|
lower_idx = mid_idx + 1;
|
||||||
}
|
}
|
||||||
std::cmp::Ordering::Equal => {
|
std::cmp::Ordering::Equal => {
|
||||||
let next_time = if mid_idx < lsb_indxs_of_num_tmstmp_vals_on_tmln.len() - 1 {
|
return Ok((curr_val, curr_time));
|
||||||
Some(
|
|
||||||
self.time_and_num_val_at_event_idx(
|
|
||||||
mid_idx + 1,
|
|
||||||
tmstmps_encoded_as_u8s,
|
|
||||||
)?
|
|
||||||
.0,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
return Ok(QueryResult {
|
|
||||||
current: Some((curr_time, curr_val)),
|
|
||||||
next: next_time,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
std::cmp::Ordering::Greater => {
|
std::cmp::Ordering::Greater => {
|
||||||
upper_idx = mid_idx - 1;
|
upper_idx = mid_idx - 1;
|
||||||
|
@ -707,9 +619,6 @@ impl SignalEnum {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(QueryResult {
|
Ok((left_val, left_time))
|
||||||
current: Some((left_time, left_val)),
|
|
||||||
next: Some(right_time),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use chrono::prelude::{DateTime, Utc};
|
||||||
use num::BigUint;
|
use num::BigUint;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
pub struct Version(pub String);
|
pub struct Version(pub String);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
|
|
Loading…
Reference in a new issue