Reputation: 3181
I'm trying trigger notifications based on the changes of TaskStatus
(enum). A Task
is the cornerstone of my program and is linked to a NotifierService
. I set things so that set_status
calls the notifier
pub type NotifierService = fn(&Task);
pub struct Task<'a> {
pub status: TaskStatus,
pub message_id: String,
pub magnet_link: String,
pub notifier: &'a NotifierService,
}
impl<'a> Task<'a> {
pub fn new(magnet_link: String, message_id: String, notifier: &'a NotifierService) -> Self {
Self {
magnet_link,
message_id,
status: TaskStatus::RECEIVED,
notifier,
}
}
pub fn set_status(mut self, status: TaskStatus) {
self.status = status;
(self.notifier)(&self);
}
}
NotifierService
So far so good. What I would like to do is to override -- probably not the good term -- NotifierService
so that it points to a method of my choosing every time I use it in composition somewhere. For example
pub struct DiscordService {
client: Client,
headers: HeaderMap,
notifier: NotifierService,
}
impl MessagingService for DiscordService {
fn new() -> Self {
let client = Client::new();
let mut headers = HeaderMap::new();
let notifier = Self::update_task_status; //self does not exist yet, how to point to this method
return Self {
client,
headers,
notifier,
};
}
fn update_task_status(&self, task: &Task) {.....
I obviously experience a
mismatched types
expected fn pointer `for<'a, 'b> fn(&'a Task<'b>)`
found fn item `for<'a, 'b, 'c> fn(&'a DiscordService, &'b Task<'c>)
Since self
is not defined at this point in the constructor, I can't simply say
let notifier = |task: &Task|Self::update_task_status(self:????, task)
Is there a way so I could provide a method as NotifierService
every time I use it in composition in new impl
? Could the definition of NotifierService
contain a dynamic reference -- again, probably not the right term -- to accept different method(&self, task: &Task)
pub type NotifierService = fn(??<dyn>??, &Task);
I am fairly new to rust and I struggle with this notion of types being function pointers (among other things). I would like Task
and the notification to be as service agnostic as possible but I am not sure this is the rustacean way.
Upvotes: 0
Views: 61
Reputation: 3181
Thanks @kmdreko, the dyn field was the answer. Here is the code. No need to add anything to the DiscordService
but it's new
implementation needed some tuning.
pub struct Task<'a> {
pub status: TaskStatus,
pub message_id: String,
pub magnet_link: String,
pub notifier: &'a dyn MessagingService,
}
impl<'a> Task<'a> {
pub fn new(
magnet_link: String,
message_id: String,
notifier: &'a dyn MessagingService,
) -> Self {
Self {
magnet_link,
message_id,
status: TaskStatus::RECEIVED,
notifier,
}
}
// Update private field status and call the associated
// notifier
pub fn set_status(mut self, status: TaskStatus) {
self.status = status;
self.notifier.update_task_status(&self);
}
pub fn get_status(&self) -> String {
self.status.to_string()
}
}
As you pointed out, this works because of a Sized
restriction on the trait.
pub trait MessagingService {
fn new() -> Self
where
Self: Sized;
fn fetch_tasks(&self) -> Option<Vec<Task>>;
fn update_task_status(&self, task: &Task);
}
This is the kind of tricks I missed to transpose my OOP to rust. Thanks
Upvotes: 1