Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,6 @@ sha2 = { version = "0.10.8", default-features = false, optional = true }
greptimedb-client = { git = "https://github.com/GreptimeTeam/greptimedb-client-rust.git", rev = "bc32362adf0df17a41a95bae4221d6d8f1775656", optional = true }

# External libs
anymap = { version = "0.12", default-features = false }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be worth adding a ban to deny.toml for this?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be worth adding a ban to deny.toml for this?

That's a good idea 👍

arc-swap = { version = "1.6", default-features = false, optional = true }
async-compression = { version = "0.4.5", default-features = false, features = ["tokio", "gzip", "zstd"], optional = true }
apache-avro = { version = "0.16.0", default-features = false, optional = true }
Expand Down
1 change: 0 additions & 1 deletion LICENSE-3rdparty.csv
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ anstyle-query,https://github.com/rust-cli/anstyle,MIT OR Apache-2.0,The anstyle-
anstyle-wincon,https://github.com/rust-cli/anstyle,MIT OR Apache-2.0,The anstyle-wincon Authors
anyhow,https://github.com/dtolnay/anyhow,MIT OR Apache-2.0,David Tolnay <dtolnay@gmail.com>
anymap,https://github.com/chris-morgan/anymap,BlueOak-1.0.0 OR MIT OR Apache-2.0,Chris Morgan <rust@chrismorgan.info>
anymap,https://github.com/chris-morgan/anymap,MIT OR Apache-2.0,Chris Morgan <me@chrismorgan.info>
apache-avro,https://github.com/apache/avro,Apache-2.0,Apache Avro team <dev@avro.apache.org>
arbitrary,https://github.com/rust-fuzz/arbitrary,MIT OR Apache-2.0,"The Rust-Fuzz Project Developers, Nick Fitzgerald <fitzgen@gmail.com>, Manish Goregaokar <manishsmail@gmail.com>, Simonas Kazlauskas <arbitrary@kazlauskas.me>, Brian L. Troutwine <brian@troutwine.us>, Corey Farwell <coreyf@rwell.org>"
arc-swap,https://github.com/vorner/arc-swap,MIT OR Apache-2.0,Michal 'vorner' Vaner <vorner@vorner.cz>
Expand Down
98 changes: 73 additions & 25 deletions src/extra_context.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,99 @@
//! ExtraContext is used for passing extra data to Vector's components when Vector is used as a library.
use std::{
any::{Any, TypeId},
collections::HashMap,
marker::{Send, Sync},
sync::Arc,
};

use anymap::{
any::{Any, IntoBox},
Map,
};

/// Structure containing any extra data.
/// The data is held in an [`Arc`] so is cheap to clone.
#[derive(Clone)]
pub struct ExtraContext(Arc<Map<dyn Any + Send + Sync>>);

impl Default for ExtraContext {
fn default() -> Self {
Self(Arc::new(Map::new()))
}
}
#[derive(Clone, Default)]
pub struct ExtraContext(Arc<HashMap<TypeId, Box<dyn Any + Send + Sync>>>);

impl ExtraContext {
/// Create a new `ExtraContext` with the provided [`anymap::Map`].
pub fn new(context: Map<dyn Any + Send + Sync>) -> Self {
/// Create a new `ExtraContext` with the provided [`HashMap`].
pub fn new(context: HashMap<TypeId, Box<dyn Any + Send + Sync>>) -> Self {
Self(Arc::new(context))
}

/// Create a new `ExtraContext` that contains the single passed in value.
pub fn single_value<T: Any + Send + Sync>(value: T) -> Self {
let mut map = Map::new();
map.insert(value);
let mut map = HashMap::new();
map.insert(value.type_id(), Box::new(value) as _);
Self(Arc::new(map))
}

#[cfg(test)]
/// This is only available for tests due to panic implications of making an Arc
/// mutable when there may be multiple references to it.
fn insert<T: Any + Send + Sync>(&mut self, value: T) {
Arc::get_mut(&mut self.0)
.expect("only insert into extra context when there is a single reference to it")
.insert(value.type_id(), Box::new(value));
}

/// Get an object from the context.
pub fn get<T>(&self) -> Option<&T>
where
T: IntoBox<dyn Any + Send + Sync>,
{
self.0.get()
pub fn get<T: 'static>(&self) -> Option<&T> {
self.0
.get(&TypeId::of::<T>())
.and_then(|t| t.downcast_ref())
}

/// Get an object from the context, if it doesn't exist return the default.
pub fn get_or_default<T>(&self) -> T
pub fn get_or_default<T: 'static>(&self) -> T
where
T: IntoBox<dyn Any + Send + Sync> + Clone + Default,
T: Clone + Default,
{
self.0.get().cloned().unwrap_or_default()
self.get().cloned().unwrap_or_default()
}
}

#[cfg(test)]
mod tests {
use super::*;

#[derive(Clone, Eq, PartialEq, Debug, Default)]
struct Peas {
beans: usize,
}

#[derive(Clone, Eq, PartialEq, Debug, Default)]
struct Potatoes(usize);

#[test]
fn get_fetches_item() {
let peas = Peas { beans: 42 };
let potatoes = Potatoes(8);

let mut context = ExtraContext::default();
context.insert(peas);
context.insert(potatoes);

assert_eq!(&Peas { beans: 42 }, context.get::<Peas>().unwrap());
assert_eq!(&Potatoes(8), context.get::<Potatoes>().unwrap());
}

#[test]
fn get_or_default_fetches_item() {
let potatoes = Potatoes(8);

let mut context = ExtraContext::default();
context.insert(potatoes);

assert_eq!(Potatoes(8), context.get_or_default::<Potatoes>());
assert_eq!(Peas::default(), context.get_or_default::<Peas>());
}

#[test]
fn duplicate_types() {
let potatoes = Potatoes(8);
let potatoes99 = Potatoes(99);

let mut context = ExtraContext::default();
context.insert(potatoes);
context.insert(potatoes99);

assert_eq!(&Potatoes(99), context.get::<Potatoes>().unwrap());
}
}