mirror of
https://github.com/pezkuwichain/pezkuwi-telemetry.git
synced 2026-06-12 13:31:15 +00:00
Give things unique ID types, not aliases, to prevent mixups
This commit is contained in:
@@ -1,65 +1,52 @@
|
||||
use std::{fmt::Display, hash::Hash};
|
||||
use serde::{Serialize,Deserialize};
|
||||
use std::hash::Hash;
|
||||
use bimap::BiMap;
|
||||
|
||||
#[derive(Clone,Copy,Debug,Hash,PartialEq,Eq,Serialize,Deserialize)]
|
||||
pub struct Id(usize);
|
||||
|
||||
impl std::convert::From<Id> for usize {
|
||||
fn from(id: Id) -> usize {
|
||||
id.0
|
||||
}
|
||||
}
|
||||
impl std::convert::From<usize> for Id {
|
||||
fn from(n: usize) -> Id {
|
||||
Id(n)
|
||||
}
|
||||
}
|
||||
impl Display for Id {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// A struct that allows you to assign an ID to an arbitrary set of
|
||||
/// details (so long as they are Eq+Hash+Clone), and then access
|
||||
/// the assigned ID given those details or access the details given
|
||||
/// the ID.
|
||||
#[derive(Debug)]
|
||||
pub struct AssignId<Details> {
|
||||
current_id: Id,
|
||||
mapping: BiMap<Id, Details>
|
||||
pub struct AssignId<Id, Details> {
|
||||
current_id: usize,
|
||||
mapping: BiMap<usize, Details>,
|
||||
_id_type: std::marker::PhantomData<Id>
|
||||
}
|
||||
|
||||
impl <Details> AssignId<Details> where Details: Eq + Hash {
|
||||
impl <Id, Details> AssignId<Id, Details>
|
||||
where
|
||||
Details: Eq + Hash,
|
||||
Id: From<usize> + Copy,
|
||||
usize: From<Id>
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
current_id: Id(0),
|
||||
mapping: BiMap::new()
|
||||
current_id: 0,
|
||||
mapping: BiMap::new(),
|
||||
_id_type: std::marker::PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assign_id(&mut self, details: Details) -> Id {
|
||||
let this_id = self.current_id;
|
||||
self.current_id.0 += 1;
|
||||
self.current_id += 1;
|
||||
self.mapping.insert(this_id, details);
|
||||
this_id
|
||||
this_id.into()
|
||||
}
|
||||
|
||||
pub fn get_details(&mut self, id: Id) -> Option<&Details> {
|
||||
self.mapping.get_by_left(&id)
|
||||
self.mapping.get_by_left(&id.into())
|
||||
}
|
||||
|
||||
pub fn get_id(&mut self, details: &Details) -> Option<Id> {
|
||||
self.mapping.get_by_right(details).map(|id| *id)
|
||||
self.mapping.get_by_right(details).map(|&id| id.into())
|
||||
}
|
||||
|
||||
pub fn remove_by_id(&mut self, id: Id) -> Option<Details> {
|
||||
self.mapping.remove_by_left(&id).map(|(_,details)| details)
|
||||
self.mapping.remove_by_left(&id.into()).map(|(_,details)| details)
|
||||
}
|
||||
|
||||
pub fn remove_by_details(&mut self, details: &Details) -> Option<Id> {
|
||||
self.mapping.remove_by_right(&details).map(|(id,_)| id)
|
||||
self.mapping.remove_by_right(&details).map(|(id,_)| id.into())
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
@@ -67,6 +54,6 @@ impl <Details> AssignId<Details> where Details: Eq + Hash {
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = (Id, &Details)> {
|
||||
self.mapping.iter().map(|(id, details)| (*id, details))
|
||||
self.mapping.iter().map(|(&id, details)| (id.into(), details))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/// Define a type that can be used as an ID, be converted from/to the inner type,
|
||||
/// and serialized/deserialized transparently into the inner type.
|
||||
#[macro_export]
|
||||
macro_rules! id_type {
|
||||
($( #[$attrs:meta] )* $vis:vis $ty:ident ( $inner:ident ) $(;)? ) => {
|
||||
#[derive(Debug,Clone,Copy,PartialEq,Eq,Hash)]
|
||||
$( #[$attrs] )*
|
||||
$vis struct $ty($inner);
|
||||
|
||||
impl $ty {
|
||||
#[allow(dead_code)]
|
||||
pub fn new(inner: $inner) -> Self {
|
||||
Self(inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$inner> for $ty {
|
||||
fn from(inner: $inner) -> Self {
|
||||
Self(inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$ty> for $inner {
|
||||
fn from(ty: $ty) -> Self {
|
||||
ty.0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
#[test]
|
||||
fn create_and_use_new_id_type() {
|
||||
id_type!{
|
||||
Foo(usize)
|
||||
};
|
||||
let _ = Foo::new(123);
|
||||
let id = Foo::from(123);
|
||||
let _: usize = id.into();
|
||||
|
||||
// Check that these don't lead to compile errors:
|
||||
id_type!{
|
||||
Bar(usize);
|
||||
};
|
||||
id_type!{
|
||||
pub Wibble(u64)
|
||||
};
|
||||
id_type!{
|
||||
/// We can have doc strings, too
|
||||
pub(crate) Wobble(u16)
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,12 +2,16 @@ use std::net::IpAddr;
|
||||
|
||||
use crate::node::Payload;
|
||||
use crate::types::{NodeDetails, BlockHash};
|
||||
use crate::assign_id::Id;
|
||||
use crate::id_type;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// The shard-local ID of a given node, where a single connection
|
||||
/// might send data on behalf of more than one chain.
|
||||
pub type LocalId = Id;
|
||||
id_type! {
|
||||
/// The shard-local ID of a given node, where a single connection
|
||||
/// might send data on behalf of more than one chain.
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub ShardNodeId(usize);
|
||||
}
|
||||
|
||||
|
||||
/// Message sent from the shard to the backend core
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
@@ -16,17 +20,17 @@ pub enum FromShardAggregator {
|
||||
AddNode {
|
||||
ip: Option<IpAddr>,
|
||||
node: NodeDetails,
|
||||
local_id: LocalId,
|
||||
local_id: ShardNodeId,
|
||||
genesis_hash: BlockHash
|
||||
},
|
||||
/// Send a message payload to update details for a node
|
||||
UpdateNode {
|
||||
local_id: LocalId,
|
||||
local_id: ShardNodeId,
|
||||
payload: Payload,
|
||||
},
|
||||
/// Inform the core that a node has been removed
|
||||
RemoveNode {
|
||||
local_id: LocalId
|
||||
local_id: ShardNodeId
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +38,7 @@ pub enum FromShardAggregator {
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
pub enum FromTelemetryCore {
|
||||
Mute {
|
||||
local_id: LocalId,
|
||||
local_id: ShardNodeId,
|
||||
reason: MuteReason
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,5 @@ pub mod util;
|
||||
pub mod json;
|
||||
pub mod log_level;
|
||||
pub mod assign_id;
|
||||
pub mod most_seen;
|
||||
pub mod most_seen;
|
||||
pub mod id_type;
|
||||
@@ -4,10 +4,8 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::util::{now, MeanList};
|
||||
use crate::json;
|
||||
|
||||
pub type NodeId = usize;
|
||||
pub type BlockNumber = u64;
|
||||
pub type Timestamp = u64;
|
||||
pub type Address = Box<str>;
|
||||
pub use primitive_types::H256 as BlockHash;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
@@ -106,21 +104,6 @@ pub struct NodeLocation {
|
||||
pub city: Box<str>,
|
||||
}
|
||||
|
||||
// impl Serialize for NodeDetails {
|
||||
// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
// where
|
||||
// S: Serializer,
|
||||
// {
|
||||
// let mut tup = serializer.serialize_tuple(6)?;
|
||||
// tup.serialize_element(&self.name)?;
|
||||
// tup.serialize_element(&self.implementation)?;
|
||||
// tup.serialize_element(&self.version)?;
|
||||
// tup.serialize_element(&self.validator)?;
|
||||
// tup.serialize_element(&self.network_id)?;
|
||||
// tup.end()
|
||||
// }
|
||||
// }
|
||||
|
||||
impl Serialize for NodeStats {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
mod dense_map;
|
||||
mod mean_list;
|
||||
mod null;
|
||||
mod num_stats;
|
||||
|
||||
pub use dense_map::DenseMap;
|
||||
pub use mean_list::MeanList;
|
||||
pub use null::NullAny;
|
||||
pub use num_stats::NumStats;
|
||||
|
||||
pub fn fnv<D: AsRef<[u8]>>(data: D) -> u64 {
|
||||
|
||||
@@ -1,17 +1,22 @@
|
||||
pub type Id = usize;
|
||||
|
||||
pub struct DenseMap<T> {
|
||||
pub struct DenseMap<Id, T> {
|
||||
/// List of retired indexes that can be re-used
|
||||
retired: Vec<Id>,
|
||||
retired: Vec<usize>,
|
||||
/// All items
|
||||
items: Vec<Option<T>>,
|
||||
/// Our ID type
|
||||
_id_ty: std::marker::PhantomData<Id>
|
||||
}
|
||||
|
||||
impl<T> DenseMap<T> {
|
||||
impl<Id, T> DenseMap<Id, T>
|
||||
where
|
||||
Id: From<usize> + Copy,
|
||||
usize: From<Id>
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
DenseMap {
|
||||
retired: Vec::new(),
|
||||
items: Vec::new(),
|
||||
_id_ty: std::marker::PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +30,12 @@ impl<T> DenseMap<T> {
|
||||
{
|
||||
match self.retired.pop() {
|
||||
Some(id) => {
|
||||
self.items[id] = Some(f(id));
|
||||
id
|
||||
let id_out = id.into();
|
||||
self.items[id] = Some(f(id_out));
|
||||
id_out
|
||||
}
|
||||
None => {
|
||||
let id = self.items.len();
|
||||
let id = self.items.len().into();
|
||||
self.items.push(Some(f(id)));
|
||||
id
|
||||
}
|
||||
@@ -37,14 +43,17 @@ impl<T> DenseMap<T> {
|
||||
}
|
||||
|
||||
pub fn get(&self, id: Id) -> Option<&T> {
|
||||
let id: usize = id.into();
|
||||
self.items.get(id).and_then(|item| item.as_ref())
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, id: Id) -> Option<&mut T> {
|
||||
let id: usize = id.into();
|
||||
self.items.get_mut(id).and_then(|item| item.as_mut())
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, id: Id) -> Option<T> {
|
||||
let id: usize = id.into();
|
||||
let old = self.items.get_mut(id).and_then(|item| item.take());
|
||||
|
||||
if old.is_some() {
|
||||
@@ -60,14 +69,14 @@ impl<T> DenseMap<T> {
|
||||
self.items
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(id, item)| Some((id, item.as_ref()?)))
|
||||
.filter_map(|(id, item)| Some((id.into(), item.as_ref()?)))
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = (Id, &mut T)> + '_ {
|
||||
self.items
|
||||
.iter_mut()
|
||||
.enumerate()
|
||||
.filter_map(|(id, item)| Some((id, item.as_mut()?)))
|
||||
.filter_map(|(id, item)| Some((id.into(), item.as_mut()?)))
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
use serde::de::{Deserialize, Deserializer, IgnoredAny};
|
||||
use serde::ser::{Serialize, Serializer};
|
||||
|
||||
/// Alternative to `serde::de::IgnoreAny` that implements `Serialize`.
|
||||
/// Will serialize to `null` in JSON, or empty data in bincode.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct NullAny;
|
||||
|
||||
impl<'de> Deserialize<'de> for NullAny {
|
||||
#[inline]
|
||||
fn deserialize<D>(deserializer: D) -> Result<NullAny, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
// `bincode` is going to throw an error here as it does not support `IgnoredAny`.
|
||||
//
|
||||
// When using `bincode` `NullAny` will always serialize to unit (aka no data), so
|
||||
// this safely becomes a no-op.
|
||||
let _ = deserializer.deserialize_ignored_any(IgnoredAny);
|
||||
|
||||
Ok(NullAny)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for NullAny {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_unit()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::NullAny;
|
||||
use bincode::Options;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
struct Dummy {
|
||||
ignore: NullAny,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_json_null() {
|
||||
let dummy: Dummy = serde_json::from_str(r#"{"ignore":null}"#).unwrap();
|
||||
|
||||
assert_eq!(dummy, Dummy { ignore: NullAny });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_json_struct() {
|
||||
let dummy: Dummy = serde_json::from_str(r#"{"ignore":{"foo":"bar"}}"#).unwrap();
|
||||
|
||||
assert_eq!(dummy, Dummy { ignore: NullAny });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_json_struct_invalid() {
|
||||
let dummy = serde_json::from_str::<Dummy>(r#"{"ignore":{"foo":"bar"}"#);
|
||||
|
||||
assert!(dummy.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_json_vec_any() {
|
||||
let raw = [NullAny; 10];
|
||||
let json = r#"[null,true,false,10,{},[],[null],{"foo":"bar"},[9,9,9],"ten"]"#;
|
||||
|
||||
let deserialized: Vec<NullAny> = serde_json::from_str(json).unwrap();
|
||||
|
||||
assert_eq!(&raw[..], &deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_json_null() {
|
||||
let dummy = Dummy { ignore: NullAny };
|
||||
|
||||
let json = serde_json::to_string(&dummy).unwrap();
|
||||
|
||||
assert_eq!(json, r#"{"ignore":null}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bincode_vec() {
|
||||
let raw = vec![NullAny; 10];
|
||||
|
||||
let bytes = bincode::options().serialize(&raw).unwrap();
|
||||
|
||||
assert_eq!(bytes, &[10u8]);
|
||||
|
||||
let deserialized: Vec<NullAny> = bincode::options().deserialize(&bytes).unwrap();
|
||||
|
||||
assert_eq!(raw, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bincode_tuple() {
|
||||
let raw = (NullAny, "Hello world".to_string());
|
||||
|
||||
let bytes = bincode::options().serialize(&raw).unwrap();
|
||||
|
||||
assert_eq!(bytes, b"\x0BHello world"); // 0B = 11 = length of string
|
||||
|
||||
let deserialized: (NullAny, String) = bincode::options().deserialize(&bytes).unwrap();
|
||||
|
||||
assert_eq!(raw, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn json_vec() {
|
||||
let raw = vec![NullAny; 10];
|
||||
|
||||
let json = serde_json::to_string(&raw).unwrap();
|
||||
|
||||
assert_eq!(json, "[null,null,null,null,null,null,null,null,null,null]");
|
||||
|
||||
let deserialized: Vec<NullAny> = serde_json::from_str(&json).unwrap();
|
||||
|
||||
assert_eq!(raw, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn json_tuple() {
|
||||
let raw = (NullAny, "Hello world".to_string());
|
||||
|
||||
let json = serde_json::to_string(&raw).unwrap();
|
||||
|
||||
assert_eq!(json, r#"[null,"Hello world"]"#);
|
||||
|
||||
let deserialized: (NullAny, String) = serde_json::from_str(&json).unwrap();
|
||||
|
||||
assert_eq!(raw, deserialized);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user