mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-02 10:30:00 -07:00
server: mcp + global: refactor
This commit is contained in:
@@ -1,40 +0,0 @@
|
||||
use clap_derive::ValueEnum;
|
||||
use color_eyre::eyre::eyre;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum, Deserialize)]
|
||||
pub enum Format {
|
||||
#[serde(alias = "json")]
|
||||
JSON,
|
||||
#[serde(alias = "csv")]
|
||||
CSV,
|
||||
#[serde(alias = "tsv")]
|
||||
TSV,
|
||||
#[serde(alias = "md", alias = "markdown")]
|
||||
#[value(alias("markdown"))]
|
||||
MD,
|
||||
}
|
||||
|
||||
impl TryFrom<Option<String>> for Format {
|
||||
type Error = color_eyre::Report;
|
||||
fn try_from(value: Option<String>) -> Result<Self, Self::Error> {
|
||||
if let Some(value) = value {
|
||||
let value = value.to_lowercase();
|
||||
let value = value.as_str();
|
||||
if value == "md" || value == "markdown" {
|
||||
Ok(Self::MD)
|
||||
} else if value == "csv" {
|
||||
Ok(Self::CSV)
|
||||
} else if value == "tsv" {
|
||||
Ok(Self::TSV)
|
||||
} else if value == "json" {
|
||||
Ok(Self::JSON)
|
||||
} else {
|
||||
Err(eyre!("Fail"))
|
||||
}
|
||||
} else {
|
||||
Err(eyre!("Fail"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
use std::fmt::{self, Debug};
|
||||
|
||||
use color_eyre::eyre::eyre;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum Index {
|
||||
DateIndex,
|
||||
DecadeIndex,
|
||||
DifficultyEpoch,
|
||||
EmptyOutputIndex,
|
||||
HalvingEpoch,
|
||||
Height,
|
||||
InputIndex,
|
||||
MonthIndex,
|
||||
OpReturnIndex,
|
||||
OutputIndex,
|
||||
P2AIndex,
|
||||
P2MSIndex,
|
||||
P2PK33Index,
|
||||
P2PK65Index,
|
||||
P2PKHIndex,
|
||||
P2SHIndex,
|
||||
P2TRIndex,
|
||||
P2WPKHIndex,
|
||||
P2WSHIndex,
|
||||
QuarterIndex,
|
||||
TxIndex,
|
||||
UnknownOutputIndex,
|
||||
WeekIndex,
|
||||
YearIndex,
|
||||
}
|
||||
|
||||
impl Index {
|
||||
pub fn all() -> [Self; 24] {
|
||||
[
|
||||
Self::DateIndex,
|
||||
Self::DecadeIndex,
|
||||
Self::DifficultyEpoch,
|
||||
Self::EmptyOutputIndex,
|
||||
Self::HalvingEpoch,
|
||||
Self::Height,
|
||||
Self::InputIndex,
|
||||
Self::MonthIndex,
|
||||
Self::OpReturnIndex,
|
||||
Self::OutputIndex,
|
||||
Self::P2AIndex,
|
||||
Self::P2MSIndex,
|
||||
Self::P2PK33Index,
|
||||
Self::P2PK65Index,
|
||||
Self::P2PKHIndex,
|
||||
Self::P2SHIndex,
|
||||
Self::P2TRIndex,
|
||||
Self::P2WPKHIndex,
|
||||
Self::P2WSHIndex,
|
||||
Self::QuarterIndex,
|
||||
Self::TxIndex,
|
||||
Self::UnknownOutputIndex,
|
||||
Self::WeekIndex,
|
||||
Self::YearIndex,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn possible_values(&self) -> &[&str] {
|
||||
// Always have the "correct" id at the end
|
||||
match self {
|
||||
Self::DateIndex => &["d", "date", "dateindex"],
|
||||
Self::DecadeIndex => &["decade", "decadeindex"],
|
||||
Self::DifficultyEpoch => &["difficulty", "difficultyepoch"],
|
||||
Self::EmptyOutputIndex => &["empty", "emptyoutputindex"],
|
||||
Self::HalvingEpoch => &["halving", "halvingepoch"],
|
||||
Self::Height => &["h", "height"],
|
||||
Self::InputIndex => &["txin", "inputindex"],
|
||||
Self::MonthIndex => &["m", "month", "monthindex"],
|
||||
Self::OpReturnIndex => &["opreturn", "opreturnindex"],
|
||||
Self::OutputIndex => &["txout", "outputindex"],
|
||||
Self::P2AIndex => &["p2a", "p2aindex"],
|
||||
Self::P2MSIndex => &["p2ms", "p2msindex"],
|
||||
Self::P2PK33Index => &["p2pk33", "p2pk33index"],
|
||||
Self::P2PK65Index => &["p2pk65", "p2pk65index"],
|
||||
Self::P2PKHIndex => &["p2pkh", "p2pkhindex"],
|
||||
Self::P2SHIndex => &["p2sh", "p2shindex"],
|
||||
Self::P2TRIndex => &["p2tr", "p2trindex"],
|
||||
Self::P2WPKHIndex => &["p2wpkh", "p2wpkhindex"],
|
||||
Self::P2WSHIndex => &["p2wsh", "p2wshindex"],
|
||||
Self::QuarterIndex => &["q", "quarter", "quarterindex"],
|
||||
Self::TxIndex => &["tx", "txindex"],
|
||||
Self::UnknownOutputIndex => &["unknown", "unknownoutputindex"],
|
||||
Self::WeekIndex => &["w", "week", "weekindex"],
|
||||
Self::YearIndex => &["y", "year", "yearindex"],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_possible_values() -> Vec<String> {
|
||||
Self::all()
|
||||
.iter()
|
||||
.flat_map(|i| i.possible_values().iter().map(|s| s.to_string()))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn serialize_short(&self) -> String {
|
||||
self.possible_values()
|
||||
.iter()
|
||||
.find(|str| str.len() > 1)
|
||||
.unwrap()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
pub fn serialize_long(&self) -> String {
|
||||
self.possible_values().last().unwrap().to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Index {
|
||||
type Error = color_eyre::Report;
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
Ok(match value.to_lowercase().as_str() {
|
||||
v if (Self::DateIndex).possible_values().contains(&v) => Self::DateIndex,
|
||||
v if (Self::DecadeIndex).possible_values().contains(&v) => Self::DecadeIndex,
|
||||
v if (Self::DifficultyEpoch).possible_values().contains(&v) => Self::DifficultyEpoch,
|
||||
v if (Self::EmptyOutputIndex).possible_values().contains(&v) => Self::EmptyOutputIndex,
|
||||
v if (Self::HalvingEpoch).possible_values().contains(&v) => Self::HalvingEpoch,
|
||||
v if (Self::Height).possible_values().contains(&v) => Self::Height,
|
||||
v if (Self::InputIndex).possible_values().contains(&v) => Self::InputIndex,
|
||||
v if (Self::MonthIndex).possible_values().contains(&v) => Self::MonthIndex,
|
||||
v if (Self::OpReturnIndex).possible_values().contains(&v) => Self::OpReturnIndex,
|
||||
v if (Self::OutputIndex).possible_values().contains(&v) => Self::OutputIndex,
|
||||
v if (Self::P2AIndex).possible_values().contains(&v) => Self::P2AIndex,
|
||||
v if (Self::P2MSIndex).possible_values().contains(&v) => Self::P2MSIndex,
|
||||
v if (Self::P2PK33Index).possible_values().contains(&v) => Self::P2PK33Index,
|
||||
v if (Self::P2PK65Index).possible_values().contains(&v) => Self::P2PK65Index,
|
||||
v if (Self::P2PKHIndex).possible_values().contains(&v) => Self::P2PKHIndex,
|
||||
v if (Self::P2SHIndex).possible_values().contains(&v) => Self::P2SHIndex,
|
||||
v if (Self::P2TRIndex).possible_values().contains(&v) => Self::P2TRIndex,
|
||||
v if (Self::P2WPKHIndex).possible_values().contains(&v) => Self::P2WPKHIndex,
|
||||
v if (Self::P2WSHIndex).possible_values().contains(&v) => Self::P2WSHIndex,
|
||||
v if (Self::QuarterIndex).possible_values().contains(&v) => Self::QuarterIndex,
|
||||
v if (Self::QuarterIndex).possible_values().contains(&v) => Self::QuarterIndex,
|
||||
v if (Self::TxIndex).possible_values().contains(&v) => Self::TxIndex,
|
||||
v if (Self::WeekIndex).possible_values().contains(&v) => Self::WeekIndex,
|
||||
v if (Self::YearIndex).possible_values().contains(&v) => Self::YearIndex,
|
||||
v if (Self::UnknownOutputIndex).possible_values().contains(&v) => {
|
||||
Self::UnknownOutputIndex
|
||||
}
|
||||
_ => return Err(eyre!("Bad index")),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Index {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
Debug::fmt(self, f)
|
||||
}
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![doc = "\n## Example\n\n```rust"]
|
||||
#![doc = include_str!("../examples/main.rs")]
|
||||
#![doc = "```"]
|
||||
|
||||
use brk_computer::Computer;
|
||||
use brk_core::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::AnyCollectableVec;
|
||||
use tabled::settings::Style;
|
||||
|
||||
mod format;
|
||||
mod index;
|
||||
mod output;
|
||||
mod params;
|
||||
mod table;
|
||||
mod vec_trees;
|
||||
|
||||
pub use format::Format;
|
||||
pub use index::Index;
|
||||
pub use output::{Output, Value};
|
||||
pub use params::{Params, ParamsOpt};
|
||||
pub use table::Tabled;
|
||||
use vec_trees::VecTrees;
|
||||
|
||||
pub struct Query<'a> {
|
||||
pub vec_trees: VecTrees<'a>,
|
||||
_indexer: &'a Indexer,
|
||||
_computer: &'a Computer,
|
||||
}
|
||||
|
||||
impl<'a> Query<'a> {
|
||||
pub fn build(indexer: &'a Indexer, computer: &'a Computer) -> Self {
|
||||
let mut vec_trees = VecTrees::default();
|
||||
|
||||
indexer
|
||||
.vecs()
|
||||
.vecs()
|
||||
.into_iter()
|
||||
.for_each(|vec| vec_trees.insert(vec));
|
||||
|
||||
computer
|
||||
.vecs()
|
||||
.into_iter()
|
||||
.for_each(|vec| vec_trees.insert(vec));
|
||||
|
||||
Self {
|
||||
vec_trees,
|
||||
_indexer: indexer,
|
||||
_computer: computer,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn search(&self, index: Index, ids: &[&str]) -> Vec<(String, &&dyn AnyCollectableVec)> {
|
||||
let tuples = ids
|
||||
.iter()
|
||||
.flat_map(|s| {
|
||||
s.to_lowercase()
|
||||
.replace("_", "-")
|
||||
.split_whitespace()
|
||||
.flat_map(|s| {
|
||||
s.split(',')
|
||||
.flat_map(|s| s.split('+').map(|s| s.to_string()))
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.map(|mut id| {
|
||||
let mut res = self.vec_trees.id_to_index_to_vec.get(&id);
|
||||
if res.is_none() {
|
||||
if let Ok(index) = Index::try_from(id.as_str()) {
|
||||
id = index.possible_values().last().unwrap().to_string();
|
||||
res = self.vec_trees.id_to_index_to_vec.get(&id)
|
||||
}
|
||||
}
|
||||
(id, res)
|
||||
})
|
||||
.filter(|(_, opt)| opt.is_some())
|
||||
.map(|(id, vec)| (id, vec.unwrap()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
tuples
|
||||
.iter()
|
||||
.flat_map(|(str, i_to_v)| i_to_v.get(&index).map(|vec| (str.to_owned(), vec)))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
&self,
|
||||
vecs: Vec<(String, &&dyn AnyCollectableVec)>,
|
||||
from: Option<i64>,
|
||||
to: Option<i64>,
|
||||
format: Option<Format>,
|
||||
) -> color_eyre::Result<Output> {
|
||||
let mut values = vecs
|
||||
.iter()
|
||||
.map(|(_, vec)| -> Result<Vec<serde_json::Value>> {
|
||||
vec.collect_range_serde_json(from, to)
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
if values.is_empty() {
|
||||
return Ok(Output::default(format));
|
||||
}
|
||||
|
||||
let ids_last_i = vecs.len() - 1;
|
||||
|
||||
Ok(match format {
|
||||
Some(Format::CSV) | Some(Format::TSV) => {
|
||||
let delimiter = if format == Some(Format::CSV) {
|
||||
','
|
||||
} else {
|
||||
'\t'
|
||||
};
|
||||
|
||||
let mut text = vecs
|
||||
.iter()
|
||||
.map(|(id, _)| id.to_owned())
|
||||
.collect::<Vec<_>>()
|
||||
.join(&delimiter.to_string());
|
||||
|
||||
text.push('\n');
|
||||
|
||||
let values_len = values.first().unwrap().len();
|
||||
|
||||
(0..values_len).for_each(|i| {
|
||||
let mut line = "".to_string();
|
||||
values.iter().enumerate().for_each(|(id_i, v)| {
|
||||
line += &v.get(i).unwrap().to_string();
|
||||
if id_i == ids_last_i {
|
||||
line.push('\n');
|
||||
} else {
|
||||
line.push(delimiter);
|
||||
}
|
||||
});
|
||||
text += &line;
|
||||
});
|
||||
|
||||
if format == Some(Format::CSV) {
|
||||
Output::CSV(text)
|
||||
} else {
|
||||
Output::TSV(text)
|
||||
}
|
||||
}
|
||||
Some(Format::MD) => {
|
||||
let mut table =
|
||||
values.to_table(vecs.iter().map(|(s, _)| s.to_owned()).collect::<Vec<_>>());
|
||||
|
||||
table.with(Style::markdown());
|
||||
|
||||
Output::MD(table.to_string())
|
||||
}
|
||||
Some(Format::JSON) | None => {
|
||||
if values.len() == 1 {
|
||||
let mut values = values.pop().unwrap();
|
||||
if values.len() == 1 {
|
||||
let value = values.pop().unwrap();
|
||||
Output::Json(Value::Single(value))
|
||||
} else {
|
||||
Output::Json(Value::List(values))
|
||||
}
|
||||
} else {
|
||||
Output::Json(Value::Matrix(values))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn search_and_format(
|
||||
&self,
|
||||
index: Index,
|
||||
ids: &[&str],
|
||||
from: Option<i64>,
|
||||
to: Option<i64>,
|
||||
format: Option<Format>,
|
||||
) -> color_eyre::Result<Output> {
|
||||
self.format(self.search(index, ids), from, to, format)
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
use std::fmt;
|
||||
|
||||
use serde::Serialize;
|
||||
use tabled::Tabled as TabledTabled;
|
||||
|
||||
use crate::Format;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Output {
|
||||
Json(Value),
|
||||
CSV(String),
|
||||
TSV(String),
|
||||
MD(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, TabledTabled)]
|
||||
#[serde(untagged)]
|
||||
pub enum Value {
|
||||
Matrix(Vec<Vec<serde_json::Value>>),
|
||||
List(Vec<serde_json::Value>),
|
||||
Single(serde_json::Value),
|
||||
}
|
||||
|
||||
impl Output {
|
||||
pub fn default(format: Option<Format>) -> Self {
|
||||
match format {
|
||||
Some(Format::CSV) => Output::CSV("".to_string()),
|
||||
Some(Format::TSV) => Output::TSV("".to_string()),
|
||||
_ => Output::Json(Value::Single(serde_json::Value::Null)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Output {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Json(value) => write!(f, "{}", serde_json::to_string_pretty(value).unwrap()),
|
||||
Self::CSV(string) => write!(f, "{}", string),
|
||||
Self::TSV(string) => write!(f, "{}", string),
|
||||
Self::MD(string) => write!(f, "{}", string),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
use std::{fmt::Display, ops::Deref, str::FromStr};
|
||||
|
||||
use clap::builder::PossibleValuesParser;
|
||||
use clap_derive::Parser;
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use serde_with::{OneOrMany, formats::PreferOne, serde_as};
|
||||
|
||||
use crate::{Format, Index};
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize, Parser)]
|
||||
pub struct Params {
|
||||
#[clap(short, long, value_parser = PossibleValuesParser::new(Index::all_possible_values()))]
|
||||
#[serde(alias = "i")]
|
||||
/// Index of the values requested
|
||||
pub index: String,
|
||||
#[clap(short, long, value_delimiter = ' ', num_args = 1..)]
|
||||
#[serde(alias = "v")]
|
||||
#[serde_as(as = "OneOrMany<_, PreferOne>")]
|
||||
/// Names of the values requested
|
||||
pub values: Vec<String>,
|
||||
|
||||
#[clap(flatten)]
|
||||
#[serde(flatten)]
|
||||
pub rest: ParamsOpt,
|
||||
}
|
||||
|
||||
// The macro creates custom deserialization code.
|
||||
// You need to specify a function name and the field name of the flattened field.
|
||||
serde_with::flattened_maybe!(deserialize_rest, "rest");
|
||||
|
||||
impl Deref for Params {
|
||||
type Target = ParamsOpt;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.rest
|
||||
}
|
||||
}
|
||||
|
||||
impl From<((String, String), ParamsOpt)> for Params {
|
||||
fn from(((index, id), rest): ((String, String), ParamsOpt)) -> Self {
|
||||
Self {
|
||||
index,
|
||||
values: vec![id],
|
||||
rest,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Deserialize, Parser)]
|
||||
pub struct ParamsOpt {
|
||||
#[clap(short, long, allow_hyphen_values = true)]
|
||||
#[serde(default, alias = "f", deserialize_with = "de_unquote_i64")]
|
||||
/// Inclusive starting index, if negative will be from the end
|
||||
from: Option<i64>,
|
||||
#[clap(short, long, allow_hyphen_values = true)]
|
||||
#[serde(default, alias = "t", deserialize_with = "de_unquote_i64")]
|
||||
/// Exclusive ending index, if negative will be from the end, overrides 'count'
|
||||
to: Option<i64>,
|
||||
#[clap(short, long, allow_hyphen_values = true)]
|
||||
#[serde(default, alias = "c", deserialize_with = "de_unquote_usize")]
|
||||
/// Number of values
|
||||
count: Option<usize>,
|
||||
#[clap(short = 'F', long)]
|
||||
/// Format of the output
|
||||
format: Option<Format>,
|
||||
}
|
||||
|
||||
impl ParamsOpt {
|
||||
pub fn from(&self) -> Option<i64> {
|
||||
self.from
|
||||
}
|
||||
|
||||
pub fn to(&self) -> Option<i64> {
|
||||
if self.to.is_none() {
|
||||
if let Some(c) = self.count {
|
||||
let c = c as i64;
|
||||
if let Some(f) = self.from {
|
||||
if f.is_positive() || f.abs() > c {
|
||||
return Some(f + c);
|
||||
}
|
||||
} else {
|
||||
return Some(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.to
|
||||
}
|
||||
|
||||
pub fn format(&self) -> Option<Format> {
|
||||
self.format
|
||||
}
|
||||
}
|
||||
|
||||
fn de_unquote_i64<'de, D>(deserializer: D) -> Result<Option<i64>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
de_unquote(deserializer)
|
||||
}
|
||||
|
||||
fn de_unquote_usize<'de, D>(deserializer: D) -> Result<Option<usize>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
de_unquote(deserializer)
|
||||
}
|
||||
|
||||
fn de_unquote<'de, D, F>(deserializer: D) -> Result<Option<F>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
F: FromStr + Display,
|
||||
<F as std::str::FromStr>::Err: Display,
|
||||
{
|
||||
let opt: Option<String> = Option::deserialize(deserializer)?;
|
||||
let s = match opt {
|
||||
None => return Ok(None),
|
||||
Some(mut s) => {
|
||||
// strip any leading/trailing quotes
|
||||
if s.starts_with('"') && s.ends_with('"') && s.len() >= 2 {
|
||||
s = s[1..s.len() - 1].to_string();
|
||||
}
|
||||
s
|
||||
}
|
||||
};
|
||||
s.parse::<F>()
|
||||
.map(Some)
|
||||
.map_err(|e| serde::de::Error::custom(format!("cannot parse `{}` as type: {}", s, e)))
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
use tabled::{Table, builder::Builder};
|
||||
|
||||
pub trait Tabled {
|
||||
fn to_table(&self, ids: Vec<String>) -> Table;
|
||||
}
|
||||
|
||||
impl Tabled for Vec<Vec<serde_json::Value>> {
|
||||
fn to_table(&self, ids: Vec<String>) -> Table {
|
||||
let mut builder = Builder::default();
|
||||
|
||||
builder.push_record(ids);
|
||||
|
||||
if let Some(first) = self.first() {
|
||||
let len = first.len();
|
||||
|
||||
(0..len).for_each(|index| {
|
||||
builder.push_record(
|
||||
self.iter()
|
||||
.map(|vec| vec.get(index).unwrap().to_string().replace("\"", "")),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
builder.build()
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use brk_vec::AnyCollectableVec;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
|
||||
use super::index::Index;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct VecTrees<'a> {
|
||||
pub id_to_index_to_vec: BTreeMap<String, IndexToVec<'a>>,
|
||||
pub index_to_id_to_vec: BTreeMap<Index, IdToVec<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> VecTrees<'a> {
|
||||
// Not the most performant or type safe but only built once so that's okay
|
||||
pub fn insert(&mut self, vec: &'a dyn AnyCollectableVec) {
|
||||
let name = vec.name();
|
||||
let split = name.split("_to_").collect::<Vec<_>>();
|
||||
if split.len() != 2
|
||||
&& !(split.len() == 3
|
||||
&& split.get(1).is_some_and(|s| {
|
||||
s == &"up"
|
||||
|| s == &"start"
|
||||
|| s.ends_with("relative")
|
||||
|| s.starts_with("from")
|
||||
|| s == &"cumulative_up"
|
||||
|| s.starts_with("cumulative_start")
|
||||
|| s.starts_with("cumulative_from")
|
||||
|| s == &"activity"
|
||||
}))
|
||||
&& !(split.len() == 4
|
||||
&& split.get(1).is_some_and(|s| {
|
||||
s == &"up"
|
||||
|| s == &"start"
|
||||
|| s.starts_with("from")
|
||||
|| s == &"cumulative_up"
|
||||
|| s == &"cumulative_start"
|
||||
|| s.starts_with("cumulative_from")
|
||||
})
|
||||
&& split.get(2).is_some_and(|s| s.ends_with("relative")))
|
||||
{
|
||||
dbg!(&name, &split);
|
||||
panic!();
|
||||
}
|
||||
let str = vec
|
||||
.index_type_to_string()
|
||||
.split("::")
|
||||
.last()
|
||||
.unwrap()
|
||||
.to_lowercase();
|
||||
let index = Index::try_from(str.as_str())
|
||||
.inspect_err(|_| {
|
||||
dbg!(&str);
|
||||
})
|
||||
.unwrap();
|
||||
if split[0] != index.to_string().to_lowercase() {
|
||||
dbg!(&name, split[0], index.to_string());
|
||||
panic!();
|
||||
}
|
||||
let key = split[1..].join("_to_").to_string().replace("_", "-");
|
||||
let prev = self
|
||||
.id_to_index_to_vec
|
||||
.entry(key.clone())
|
||||
.or_default()
|
||||
.insert(index, vec);
|
||||
if prev.is_some() {
|
||||
dbg!(&key, str, name);
|
||||
panic!()
|
||||
}
|
||||
let prev = self
|
||||
.index_to_id_to_vec
|
||||
.entry(index)
|
||||
.or_default()
|
||||
.insert(key.clone(), vec);
|
||||
if prev.is_some() {
|
||||
dbg!(&key, str, name);
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize_id_to_index_to_vec(&self) -> BTreeMap<String, Vec<String>> {
|
||||
self.id_to_index_to_vec
|
||||
.iter()
|
||||
.map(|(id, index_to_vec)| {
|
||||
(
|
||||
id.to_string(),
|
||||
index_to_vec
|
||||
.keys()
|
||||
.map(|i| i.serialize_long())
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn serialize_index_to_id_to_vec(&self) -> BTreeMap<String, Vec<String>> {
|
||||
self.index_to_id_to_vec
|
||||
.iter()
|
||||
.map(|(index, id_to_vec)| {
|
||||
(
|
||||
index.serialize_long(),
|
||||
id_to_vec
|
||||
.keys()
|
||||
.map(|id| id.to_string())
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Deref, DerefMut)]
|
||||
pub struct IndexToVec<'a>(BTreeMap<Index, &'a dyn AnyCollectableVec>);
|
||||
|
||||
#[derive(Default, Deref, DerefMut)]
|
||||
pub struct IdToVec<'a>(BTreeMap<String, &'a dyn AnyCollectableVec>);
|
||||
Reference in New Issue
Block a user