BackendOp: Change set_{flag,tag} methods

async
Manos Pitsidianakis 2020-06-28 19:16:13 +03:00
parent 8c1fc031e5
commit c82367e00d
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
10 changed files with 257 additions and 187 deletions

View File

@ -68,9 +68,9 @@ use std::fmt::Debug;
use std::ops::Deref;
use std::sync::{Arc, RwLock};
use core::pin::Pin;
pub use futures::stream::Stream;
use std::future::Future;
pub use std::pin::Pin;
use std;
use std::collections::HashMap;
@ -330,6 +330,11 @@ pub trait MailBackend: ::std::fmt::Debug + Send + Sync {
work_context: WorkContext,
) -> Result<std::thread::ThreadId>;
fn mailboxes(&self) -> Result<HashMap<MailboxHash, Mailbox>>;
fn mailboxes_async(
&self,
) -> Result<Pin<Box<dyn Future<Output = Result<HashMap<MailboxHash, Mailbox>>> + Send>>> {
Err(MeliError::new("Unimplemented."))
}
fn operation(&self, hash: EnvelopeHash) -> Result<Box<dyn BackendOp>>;
fn save(&self, bytes: &[u8], mailbox_hash: MailboxHash, flags: Option<Flag>) -> Result<()>;
@ -427,8 +432,16 @@ pub trait BackendOp: ::std::fmt::Debug + ::std::marker::Send {
fn description(&self) -> String;
fn as_bytes(&mut self) -> Result<&[u8]>;
fn fetch_flags(&self) -> Result<Flag>;
fn set_flag(&mut self, envelope: &mut Envelope, flag: Flag, value: bool) -> Result<()>;
fn set_tag(&mut self, envelope: &mut Envelope, tag: String, value: bool) -> Result<()>;
fn set_flag(
&mut self,
flag: Flag,
value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>>;
fn set_tag(
&mut self,
tag: String,
value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>>;
}
/// Wrapper for BackendOps that are to be set read-only.
@ -456,10 +469,18 @@ impl BackendOp for ReadOnlyOp {
fn fetch_flags(&self) -> Result<Flag> {
self.op.fetch_flags()
}
fn set_flag(&mut self, _envelope: &mut Envelope, _flag: Flag, _value: bool) -> Result<()> {
fn set_flag(
&mut self,
_flag: Flag,
_value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
Err(MeliError::new("read-only set."))
}
fn set_tag(&mut self, _envelope: &mut Envelope, _tag: String, _value: bool) -> Result<()> {
fn set_tag(
&mut self,
_tag: String,
_value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
Err(MeliError::new("read-only set."))
}
}

View File

@ -21,7 +21,7 @@
use super::*;
use crate::backends::BackendOp;
use crate::backends::*;
use crate::email::*;
use crate::error::{MeliError, Result};
use std::cell::Cell;
@ -98,7 +98,6 @@ impl BackendOp for ImapOp {
let mut bytes_cache = self.uid_store.byte_cache.lock()?;
let cache = bytes_cache.entry(self.uid).or_default();
if let Some((flags, _)) = flags {
self.flags.set(Some(flags));
cache.flags = Some(flags);
}
cache.bytes =
@ -149,77 +148,87 @@ impl BackendOp for ImapOp {
Ok(self.flags.get().unwrap())
}
fn set_flag(&mut self, _envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> {
fn set_flag(
&mut self,
f: Flag,
value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
let mut flags = self.fetch_flags()?;
flags.set(f, value);
let connection = self.connection.clone();
let mailbox_hash = self.mailbox_hash;
let uid = self.uid;
let uid_store = self.uid_store.clone();
let mut response = String::with_capacity(8 * 1024);
let mut conn = try_lock(&self.connection, Some(std::time::Duration::new(2, 0)))?;
conn.select_mailbox(self.mailbox_hash, &mut response, false)?;
debug!(&response);
conn.send_command(
format!(
"UID STORE {} FLAGS.SILENT ({})",
self.uid,
flags_to_imap_list!(flags)
)
.as_bytes(),
)?;
conn.read_response(&mut response, RequiredResponses::STORE_REQUIRED)?;
debug!(&response);
match protocol_parser::uid_fetch_flags_response(response.as_bytes())
.map(|(_, v)| v)
.map_err(MeliError::from)
{
Ok(v) => {
if v.len() == 1 {
debug!("responses len is {}", v.len());
let (uid, (flags, _)) = v[0];
assert_eq!(uid, self.uid);
self.flags.set(Some(flags));
Ok(Box::pin(async move {
let mut conn = try_lock(&connection, Some(std::time::Duration::new(2, 0)))?;
conn.select_mailbox(mailbox_hash, &mut response, false)?;
debug!(&response);
conn.send_command(
format!(
"UID STORE {} FLAGS.SILENT ({})",
uid,
flags_to_imap_list!(flags)
)
.as_bytes(),
)?;
conn.read_response(&mut response, RequiredResponses::STORE_REQUIRED)?;
debug!(&response);
match protocol_parser::uid_fetch_flags_response(response.as_bytes())
.map(|(_, v)| v)
.map_err(MeliError::from)
{
Ok(v) => {
if v.len() == 1 {
debug!("responses len is {}", v.len());
let (uid, (flags, _)) = v[0];
assert_eq!(uid, uid);
}
}
Err(e) => Err(e)?,
}
Err(e) => Err(e)?,
}
let mut bytes_cache = self.uid_store.byte_cache.lock()?;
let cache = bytes_cache.entry(self.uid).or_default();
cache.flags = Some(flags);
Ok(())
let mut bytes_cache = uid_store.byte_cache.lock()?;
let cache = bytes_cache.entry(uid).or_default();
cache.flags = Some(flags);
Ok(())
}))
}
fn set_tag(&mut self, envelope: &mut Envelope, tag: String, value: bool) -> Result<()> {
fn set_tag(
&mut self,
tag: String,
value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
let mut response = String::with_capacity(8 * 1024);
let mut conn = try_lock(&self.connection, Some(std::time::Duration::new(2, 0)))?;
conn.select_mailbox(self.mailbox_hash, &mut response, false)?;
conn.send_command(
format!(
"UID STORE {} {}FLAGS.SILENT ({})",
self.uid,
if value { "+" } else { "-" },
&tag
)
.as_bytes(),
)?;
conn.read_response(&mut response, RequiredResponses::STORE_REQUIRED)?;
protocol_parser::uid_fetch_flags_response(response.as_bytes())
.map(|(_, v)| v)
.map_err(MeliError::from)?;
let hash = tag_hash!(tag);
if value {
self.uid_store.tag_index.write().unwrap().insert(hash, tag);
} else {
self.uid_store.tag_index.write().unwrap().remove(&hash);
}
if !envelope.labels().iter().any(|&h_| h_ == hash) {
let connection = self.connection.clone();
let mailbox_hash = self.mailbox_hash;
let uid = self.uid;
let uid_store = self.uid_store.clone();
Ok(Box::pin(async move {
let mut conn = try_lock(&connection, Some(std::time::Duration::new(2, 0)))?;
conn.select_mailbox(mailbox_hash, &mut response, false)?;
conn.send_command(
format!(
"UID STORE {} {}FLAGS.SILENT ({})",
uid,
if value { "+" } else { "-" },
&tag
)
.as_bytes(),
)?;
conn.read_response(&mut response, RequiredResponses::STORE_REQUIRED)?;
protocol_parser::uid_fetch_flags_response(response.as_bytes())
.map(|(_, v)| v)
.map_err(MeliError::from)?;
let hash = tag_hash!(tag);
if value {
envelope.labels_mut().push(hash);
uid_store.tag_index.write().unwrap().insert(hash, tag);
} else {
uid_store.tag_index.write().unwrap().remove(&hash);
}
}
if !value {
if let Some(pos) = envelope.labels().iter().position(|&h_| h_ == hash) {
envelope.labels_mut().remove(pos);
}
}
Ok(())
Ok(())
}))
}
}

View File

@ -164,7 +164,7 @@ impl BackendOp for ImapOp {
self.flags.get().unwrap()
}
fn set_flag(&mut self, _envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> {
fn set_flag(&mut self, f: Flag, value: bool) -> Result<()> {
let mut flags = self.fetch_flags();
flags.set(f, value);
@ -202,7 +202,7 @@ impl BackendOp for ImapOp {
Ok(())
}
fn set_tag(&mut self, envelope: &mut Envelope, tag: String, value: bool) -> Result<()> {
fn set_tag(&mut self, tag: String, value: bool) -> Result<()> {
let mut response = String::with_capacity(8 * 1024);
let mut conn = try_lock(&self.connection, Some(std::time::Duration::new(2, 0)))?;
conn.select_mailbox(self.mailbox_hash, &mut response)?;

View File

@ -21,7 +21,7 @@
use super::*;
use crate::backends::BackendOp;
use crate::backends::*;
use crate::error::Result;
use std::cell::Cell;
use std::sync::{Arc, RwLock};
@ -101,11 +101,19 @@ impl BackendOp for JmapOp {
Ok(Flag::default())
}
fn set_flag(&mut self, _envelope: &mut Envelope, _f: Flag, _value: bool) -> Result<()> {
Ok(())
fn set_flag(
&mut self,
_f: Flag,
_value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
Err(MeliError::new("Unimplemented"))
}
fn set_tag(&mut self, _envelope: &mut Envelope, _tag: String, _value: bool) -> Result<()> {
Ok(())
fn set_tag(
&mut self,
_tag: String,
_value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
Err(MeliError::new("Unimplemented"))
}
}

View File

@ -26,11 +26,11 @@ pub use self::backend::*;
mod stream;
pub use stream::*;
pub use futures::stream::Stream;
use crate::backends::*;
use crate::email::{Envelope, Flag};
use crate::email::Flag;
use crate::error::{MeliError, Result};
use crate::shellexpand::ShellExpandTrait;
pub use futures::stream::Stream;
use memmap::{Mmap, Protection};
use std::collections::hash_map::DefaultHasher;
@ -106,49 +106,61 @@ impl<'a> BackendOp for MaildirOp {
Ok(path.flags())
}
fn set_flag(&mut self, envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> {
let path = self.path();
let path = path.to_str().unwrap(); // Assume UTF-8 validity
let idx: usize = path
.rfind(":2,")
.ok_or_else(|| MeliError::new(format!("Invalid email filename: {:?}", self)))?
+ 3;
let mut new_name: String = path[..idx].to_string();
fn set_flag(
&mut self,
f: Flag,
value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
let mut flags = self.fetch_flags()?;
flags.set(f, value);
if !(flags & Flag::DRAFT).is_empty() {
new_name.push('D');
}
if !(flags & Flag::FLAGGED).is_empty() {
new_name.push('F');
}
if !(flags & Flag::PASSED).is_empty() {
new_name.push('P');
}
if !(flags & Flag::REPLIED).is_empty() {
new_name.push('R');
}
if !(flags & Flag::SEEN).is_empty() {
new_name.push('S');
}
if !(flags & Flag::TRASHED).is_empty() {
new_name.push('T');
}
let old_hash = envelope.hash();
let new_name: PathBuf = new_name.into();
let old_hash = self.hash;
let mailbox_hash = self.mailbox_hash;
let hash_index = self.hash_index.clone();
let mut map = hash_index.lock().unwrap();
let map = map.entry(self.mailbox_hash).or_default();
map.entry(old_hash).or_default().modified = Some(PathMod::Path(new_name.clone()));
let path = self.path();
Ok(Box::pin(async move {
let path = path;
let path = path.to_str().unwrap(); // Assume UTF-8 validity
let idx: usize = path
.rfind(":2,")
.ok_or_else(|| MeliError::new(format!("Invalid email filename: {:?}", path)))?
+ 3;
let mut new_name: String = path[..idx].to_string();
flags.set(f, value);
debug!("renaming {:?} to {:?}", path, new_name);
fs::rename(&path, &new_name)?;
debug!("success in rename");
Ok(())
if !(flags & Flag::DRAFT).is_empty() {
new_name.push('D');
}
if !(flags & Flag::FLAGGED).is_empty() {
new_name.push('F');
}
if !(flags & Flag::PASSED).is_empty() {
new_name.push('P');
}
if !(flags & Flag::REPLIED).is_empty() {
new_name.push('R');
}
if !(flags & Flag::SEEN).is_empty() {
new_name.push('S');
}
if !(flags & Flag::TRASHED).is_empty() {
new_name.push('T');
}
let new_name: PathBuf = new_name.into();
let mut map = hash_index.lock().unwrap();
let map = map.entry(mailbox_hash).or_default();
map.entry(old_hash).or_default().modified = Some(PathMod::Path(new_name.clone()));
debug!("renaming {:?} to {:?}", path, new_name);
fs::rename(&path, &new_name)?;
debug!("success in rename");
Ok(())
}))
}
fn set_tag(&mut self, _envelope: &mut Envelope, _tag: String, _value: bool) -> Result<()> {
fn set_tag(
&mut self,
_tag: String,
_value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
Err(MeliError::new("Maildir doesn't support tags."))
}
}

View File

@ -24,12 +24,7 @@
*/
use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
use crate::backends::BackendOp;
use crate::backends::MailboxHash;
use crate::backends::{
BackendMailbox, MailBackend, Mailbox, MailboxPermissions, RefreshEvent, RefreshEventConsumer,
RefreshEventKind, SpecialUsageMailbox,
};
use crate::backends::*;
use crate::conf::AccountSettings;
use crate::email::parser::BytesExt;
use crate::email::*;
@ -257,11 +252,19 @@ impl BackendOp for MboxOp {
Ok(flags)
}
fn set_flag(&mut self, _envelope: &mut Envelope, _flag: Flag, _value: bool) -> Result<()> {
Ok(())
fn set_flag(
&mut self,
_flag: Flag,
_value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
Err(MeliError::new("Unimplemented."))
}
fn set_tag(&mut self, _envelope: &mut Envelope, _tag: String, _value: bool) -> Result<()> {
fn set_tag(
&mut self,
_tag: String,
_value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
Err(MeliError::new("mbox doesn't support tags."))
}
}

View File

@ -20,11 +20,7 @@
*/
use crate::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
use crate::backends::MailboxHash;
use crate::backends::{
BackendMailbox, BackendOp, MailBackend, Mailbox, MailboxPermissions, RefreshEventConsumer,
SpecialUsageMailbox,
};
use crate::backends::*;
use crate::conf::AccountSettings;
use crate::email::{Envelope, EnvelopeHash, Flag};
use crate::error::{MeliError, Result};
@ -407,7 +403,7 @@ impl MailBackend for NotmuchDb {
_work_context: WorkContext,
) -> Result<std::thread::ThreadId> {
extern crate notify;
use crate::backends::{RefreshEvent, RefreshEventKind::*};
use crate::backends::RefreshEventKind::*;
use notify::{watcher, RecursiveMode, Watcher};
let (tx, rx) = std::sync::mpsc::channel();
let mut watcher = watcher(tx, std::time::Duration::from_secs(2)).unwrap();
@ -621,7 +617,7 @@ impl MailBackend for NotmuchDb {
.as_ref()
.unwrap_or(&self.path)
.to_path_buf();
crate::backends::MaildirType::save_to_mailbox(path, bytes, flags)
MaildirType::save_to_mailbox(path, bytes, flags)
}
fn as_any(&self) -> &dyn ::std::any::Any {
@ -681,10 +677,13 @@ impl BackendOp for NotmuchOp {
Ok(flags)
}
fn set_flag(&mut self, envelope: &mut Envelope, f: Flag, value: bool) -> Result<()> {
fn set_flag(
&mut self,
f: Flag,
value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
let mut flags = self.fetch_flags()?;
flags.set(f, value);
envelope.set_flags(flags);
let mut message: *mut notmuch_message_t = std::ptr::null_mut();
let mut index_lck = self.index.write().unwrap();
unsafe {
@ -713,7 +712,7 @@ impl BackendOp for NotmuchOp {
macro_rules! add_tag {
($l:literal) => {{
if tags.contains(unsafe { &cstr!($l) }) {
return Ok(());
return Ok(Box::pin(async { Ok(()) }));
}
if let Err(err) = try_call!(
self.lib,
@ -728,7 +727,7 @@ impl BackendOp for NotmuchOp {
macro_rules! remove_tag {
($l:literal) => {{
if !tags.contains(unsafe { &cstr!($l) }) {
return Ok(());
return Ok(Box::pin(async { Ok(()) }));
}
if let Err(err) = try_call!(
self.lib,
@ -771,10 +770,14 @@ impl BackendOp for NotmuchOp {
*p = c_str.into();
}
Ok(())
Ok(Box::pin(async { Ok(()) }))
}
fn set_tag(&mut self, envelope: &mut Envelope, tag: String, value: bool) -> Result<()> {
fn set_tag(
&mut self,
tag: String,
value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
let mut message: *mut notmuch_message_t = std::ptr::null_mut();
let index_lck = self.index.read().unwrap();
unsafe {
@ -817,17 +820,7 @@ impl BackendOp for NotmuchOp {
if value {
self.tag_index.write().unwrap().insert(hash, tag);
}
if !envelope.labels().iter().any(|&h_| h_ == hash) {
if value {
envelope.labels_mut().push(hash);
}
}
if !value {
if let Some(pos) = envelope.labels().iter().position(|&h_| h_ == hash) {
envelope.labels_mut().remove(pos);
}
}
Ok(())
Ok(Box::pin(async { Ok(()) }))
}
}

View File

@ -49,8 +49,10 @@ use std::borrow::Cow;
use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::fmt;
use std::future::Future;
use std::hash::Hasher;
use std::option::Option;
use std::pin::Pin;
use std::str;
use std::string::String;
@ -605,9 +607,9 @@ impl Envelope {
f: Flag,
value: bool,
mut operation: Box<dyn BackendOp>,
) -> Result<()> {
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
self.flags.set(f, value);
operation.set_flag(self, f, value)
operation.set_flag(f, value)
}
pub fn set_flags(&mut self, f: Flag) {
self.flags = f;
@ -615,18 +617,24 @@ impl Envelope {
pub fn flags(&self) -> Flag {
self.flags
}
pub fn set_seen(&mut self, operation: Box<dyn BackendOp>) -> Result<()> {
pub fn set_seen(
&mut self,
operation: Box<dyn BackendOp>,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
if !self.flags.contains(Flag::SEEN) {
self.set_flag(Flag::SEEN, true, operation)
} else {
Ok(())
Ok(Box::pin(async { Ok(()) }))
}
}
pub fn set_unseen(&mut self, operation: Box<dyn BackendOp>) -> Result<()> {
pub fn set_unseen(
&mut self,
operation: Box<dyn BackendOp>,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
if self.flags.contains(Flag::SEEN) {
self.set_flag(Flag::SEEN, false, operation)
} else {
Ok(())
Ok(Box::pin(async { Ok(()) }))
}
}
pub fn is_seen(&self) -> bool {

View File

@ -168,48 +168,56 @@ pub trait MailListingTrait: ListingTrait {
};
let mut envelope: EnvelopeRefMut = account.collection.get_env_mut(env_hash);
match a {
ListingAction::SetSeen => {
if let Err(e) = envelope.set_seen(op) {
ListingAction::SetSeen => match envelope.set_seen(op) {
Err(e) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(e.to_string()),
));
}
}
ListingAction::SetUnseen => {
if let Err(e) = envelope.set_unseen(op) {
Ok(fut) => {
//accout.job_executor.spawn_specialized(fut);
}
},
ListingAction::SetUnseen => match envelope.set_unseen(op) {
Err(e) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(e.to_string()),
));
}
}
Ok(fut) => {}
},
ListingAction::Delete => {
drop(envelope);
if let Err(err) = account.delete(env_hash, mailbox_hash) {
context.replies.push_back(UIEvent::Notification(
Some("Could not delete.".to_string()),
err.to_string(),
Some(NotificationType::ERROR),
));
return;
match account.delete(env_hash, mailbox_hash) {
Err(err) => {
context.replies.push_back(UIEvent::Notification(
Some("Could not delete.".to_string()),
err.to_string(),
Some(NotificationType::ERROR),
));
return;
}
Ok(fut) => {}
}
continue;
}
ListingAction::CopyTo(ref mailbox_path) => {
drop(envelope);
if let Err(err) =
account
.mailbox_by_path(mailbox_path)
.and_then(|mailbox_hash| {
op.as_bytes()
.and_then(|bytes| account.save(bytes, mailbox_hash, None))
})
{
context.replies.push_back(UIEvent::Notification(
Some("Could not copy.".to_string()),
err.to_string(),
Some(NotificationType::ERROR),
));
return;
match account
.mailbox_by_path(mailbox_path)
.and_then(|mailbox_hash| {
op.as_bytes()
.and_then(|bytes| account.save(bytes, mailbox_hash, None))
}) {
Err(err) => {
context.replies.push_back(UIEvent::Notification(
Some("Could not copy.".to_string()),
err.to_string(),
Some(NotificationType::ERROR),
));
return;
}
Ok(fut) => {}
}
continue;
}
@ -297,7 +305,7 @@ pub trait MailListingTrait: ListingTrait {
continue;
}
ListingAction::Tag(Remove(ref tag_str)) => {
if let Err(err) = op.set_tag(&mut envelope, tag_str.to_string(), false) {
if let Err(err) = op.set_tag(tag_str.to_string(), false) {
context.replies.push_back(UIEvent::Notification(
Some("Could not set tag.".to_string()),
err.to_string(),
@ -307,7 +315,7 @@ pub trait MailListingTrait: ListingTrait {
}
}
ListingAction::Tag(Add(ref tag_str)) => {
if let Err(err) = op.set_tag(&mut envelope, tag_str.to_string(), true) {
if let Err(err) = op.set_tag(tag_str.to_string(), true) {
context.replies.push_back(UIEvent::Notification(
Some("Could not set tag.".to_string()),
err.to_string(),

View File

@ -21,13 +21,13 @@
use super::*;
use melib::async_workers::{Async, AsyncBuilder, AsyncStatus, WorkContext};
use melib::backends::MailboxHash;
use melib::backends::{Backend, BackendOp, Backends, MailBackend, Mailbox, RefreshEventConsumer};
use melib::backends::*;
use melib::conf::AccountSettings;
use melib::email::{Envelope, EnvelopeHash, Flag};
use melib::error::{MeliError, Result};
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::future::Future;
use std::sync::{Arc, Mutex, RwLock};
// TODO replace with melib::Envelope after simplifying melib::Envelope's
@ -318,11 +318,19 @@ impl BackendOp for PluginOp {
Err(MeliError::new("Unimplemented."))
}
fn set_flag(&mut self, __envelope: &mut Envelope, _f: Flag, _value: bool) -> Result<()> {
fn set_flag(
&mut self,
_f: Flag,
_value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
Err(MeliError::new("Unimplemented."))
}
fn set_tag(&mut self, _envelope: &mut Envelope, _tag: String, _value: bool) -> Result<()> {
fn set_tag(
&mut self,
_tag: String,
_value: bool,
) -> Result<Pin<Box<dyn Future<Output = Result<()>> + Send>>> {
Err(MeliError::new("Unimplemented."))
}
}