Fix unreachable-pub and disjoint-capture lint errors
Tests / Test on ${{ matrix.build }} (linux-amd64, ubuntu-latest, stable, x86_64-unknown-linux-gnu) (push) Failing after 6m8s Details

pull/260/head
Manos Pitsidianakis 2023-07-20 00:19:42 +03:00
parent 1d0405ed5b
commit 8e698cabcf
Signed by: Manos Pitsidianakis
GPG Key ID: 7729C7707F7E09D0
23 changed files with 647 additions and 609 deletions

View File

@ -29,7 +29,7 @@ use quote::{format_ident, quote};
use regex::Regex; use regex::Regex;
// Write ConfigStructOverride to overrides.rs // Write ConfigStructOverride to overrides.rs
pub fn override_derive(filenames: &[(&str, &str)]) { pub(crate) fn override_derive(filenames: &[(&str, &str)]) {
let mut output_file = let mut output_file =
File::create("src/conf/overrides.rs").expect("Unable to open output file"); File::create("src/conf/overrides.rs").expect("Unable to open output file");
let mut output_string = r##"// @generated let mut output_string = r##"// @generated

View File

@ -40,7 +40,7 @@ use super::*;
use crate::{conf::accounts::JobRequest, jobs::JoinHandle, terminal::embed::EmbedTerminal}; use crate::{conf::accounts::JobRequest, jobs::JoinHandle, terminal::embed::EmbedTerminal};
#[cfg(feature = "gpgme")] #[cfg(feature = "gpgme")]
mod gpg; pub mod gpg;
pub mod edit_attachments; pub mod edit_attachments;
use edit_attachments::*; use edit_attachments::*;

View File

@ -444,8 +444,327 @@ pub trait MailListingTrait: ListingTrait {
envs_to_set: SmallVec<[EnvelopeHash; 8]>, envs_to_set: SmallVec<[EnvelopeHash; 8]>,
a: &ListingAction, a: &ListingAction,
) { ) {
fn inner(
context: &mut Context,
envs_to_set: SmallVec<[EnvelopeHash; 8]>,
account_hash: AccountHash,
mailbox_hash: MailboxHash,
a: &ListingAction,
) {
let env_hashes = if let Ok(batch) = EnvelopeHashBatch::try_from(envs_to_set.as_slice())
{
batch
} else {
return;
};
let account = &mut context.accounts[&account_hash];
match a {
ListingAction::SetSeen => {
let job = account.backend.write().unwrap().set_flags(
env_hashes.clone(),
mailbox_hash,
smallvec::smallvec![(Ok(Flag::SEEN), true)],
);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("set_seen".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::SetFlags { env_hashes, handle },
);
}
}
}
ListingAction::SetUnseen => {
let job = account.backend.write().unwrap().set_flags(
env_hashes.clone(),
mailbox_hash,
smallvec::smallvec![(Ok(Flag::SEEN), false)],
);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("set_unseen".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::SetFlags { env_hashes, handle },
);
}
}
}
ListingAction::Tag(Remove(ref tag_str)) => {
let job = account.backend.write().unwrap().set_flags(
env_hashes.clone(),
mailbox_hash,
smallvec::smallvec![(Err(tag_str.to_string()), false)],
);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("remove_tag".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::SetFlags { env_hashes, handle },
);
}
}
}
ListingAction::Tag(Add(ref tag_str)) => {
let job = account.backend.write().unwrap().set_flags(
env_hashes.clone(),
mailbox_hash,
smallvec::smallvec![(Err(tag_str.to_string()), true)],
);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("add_tag".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::SetFlags { env_hashes, handle },
);
}
}
}
ListingAction::Delete => {
let job = account
.backend
.write()
.unwrap()
.delete_messages(env_hashes.clone(), mailbox_hash);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("delete".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::DeleteMessages { env_hashes, handle },
);
}
}
}
ListingAction::CopyTo(ref mailbox_path) => {
match account.mailbox_by_path(mailbox_path).and_then(
|destination_mailbox_hash| {
account.backend.write().unwrap().copy_messages(
env_hashes,
mailbox_hash,
destination_mailbox_hash,
/* move? */ false,
)
},
) {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("copy_to_mailbox".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::Generic {
name: "message copying".into(),
handle,
on_finish: None,
log_level: LogLevel::INFO,
},
);
}
}
}
ListingAction::CopyToOtherAccount(ref _account_name, ref _mailbox_path) => {
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::DisplayMessage(
"Copying to another account is currently unimplemented".into(),
)));
}
ListingAction::MoveTo(ref mailbox_path) => {
match account.mailbox_by_path(mailbox_path).and_then(
|destination_mailbox_hash| {
account.backend.write().unwrap().copy_messages(
env_hashes,
mailbox_hash,
destination_mailbox_hash,
/* move? */ true,
)
},
) {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("move_to_mailbox".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::Generic {
name: "message moving".into(),
handle,
on_finish: None,
log_level: LogLevel::INFO,
},
);
}
}
}
ListingAction::ExportMbox(format, ref path) => {
use std::{future::Future, io::Write, pin::Pin};
use futures::future::try_join_all;
let futures: Result<Vec<_>> = envs_to_set
.iter()
.map(|&env_hash| {
account.operation(env_hash).and_then(|mut op| op.as_bytes())
})
.collect::<Result<Vec<_>>>();
let path_ = path.to_path_buf();
let format = (*format).unwrap_or_default();
let collection = account.collection.clone();
let (sender, mut receiver) = crate::jobs::oneshot::channel();
let fut: Pin<Box<dyn Future<Output = Result<()>> + Send + 'static>> =
Box::pin(async move {
let cl = async move {
use melib::backends::mbox::MboxMetadata;
let bytes: Vec<Vec<u8>> = try_join_all(futures?).await?;
let envs: Vec<_> = envs_to_set
.iter()
.map(|&env_hash| collection.get_env(env_hash))
.collect();
let mut file =
std::io::BufWriter::new(std::fs::File::create(&path_)?);
let mut iter = envs.iter().zip(bytes.into_iter());
let tags_lck = collection.tag_index.read().unwrap();
if let Some((env, ref bytes)) = iter.next() {
let tags: Vec<&str> = env
.tags()
.iter()
.filter_map(|h| tags_lck.get(h).map(|s| s.as_str()))
.collect();
format.append(
&mut file,
bytes.as_slice(),
env.from().get(0),
Some(env.date()),
(env.flags(), tags),
MboxMetadata::CClient,
true,
false,
)?;
}
for (env, bytes) in iter {
let tags: Vec<&str> = env
.tags()
.iter()
.filter_map(|h| tags_lck.get(h).map(|s| s.as_str()))
.collect();
format.append(
&mut file,
bytes.as_slice(),
env.from().get(0),
Some(env.date()),
(env.flags(), tags),
MboxMetadata::CClient,
false,
false,
)?;
}
file.flush()?;
Ok(())
};
let r: Result<()> = cl.await;
let _ = sender.send(r);
Ok(())
});
let handle = account
.main_loop_handler
.job_executor
.spawn_blocking("export_to_mbox".into(), fut);
let path = path.to_path_buf();
account.insert_job(
handle.job_id,
JobRequest::Generic {
name: "exporting mbox".into(),
handle,
on_finish: Some(CallbackFn(Box::new(move |context: &mut Context| {
context.replies.push_back(match receiver.try_recv() {
Err(_) | Ok(None) => UIEvent::Notification(
Some("Could not export mbox".to_string()),
"Job was canceled.".to_string(),
Some(NotificationType::Info),
),
Ok(Some(Err(err))) => UIEvent::Notification(
Some("Could not export mbox".to_string()),
err.to_string(),
Some(NotificationType::Error(err.kind)),
),
Ok(Some(Ok(()))) => UIEvent::Notification(
Some("Succesfully exported mbox".to_string()),
format!("Wrote to file {}", path.display()),
Some(NotificationType::Info),
),
});
}))),
log_level: LogLevel::INFO,
},
);
}
ListingAction::MoveToOtherAccount(ref _account_name, ref _mailbox_path) => {
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::DisplayMessage(
"Moving to another account is currently unimplemented".into(),
)));
}
_ => unreachable!(),
}
}
let account_hash = self.coordinates().0; let account_hash = self.coordinates().0;
let account = &mut context.accounts[&account_hash];
let mailbox_hash = self.coordinates().1; let mailbox_hash = self.coordinates().1;
/*{ /*{
let threads_lck = account.collection.get_threads(mailbox_hash); let threads_lck = account.collection.get_threads(mailbox_hash);
@ -457,305 +776,7 @@ pub trait MailListingTrait: ListingTrait {
} }
} }
*/ */
let env_hashes = if let Ok(batch) = EnvelopeHashBatch::try_from(envs_to_set.as_slice()) { inner(context, envs_to_set, account_hash, mailbox_hash, a);
batch
} else {
return;
};
match a {
ListingAction::SetSeen => {
let job = account.backend.write().unwrap().set_flags(
env_hashes.clone(),
mailbox_hash,
smallvec::smallvec![(Ok(Flag::SEEN), true)],
);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("set_seen".into(), fut);
account
.insert_job(handle.job_id, JobRequest::SetFlags { env_hashes, handle });
}
}
}
ListingAction::SetUnseen => {
let job = account.backend.write().unwrap().set_flags(
env_hashes.clone(),
mailbox_hash,
smallvec::smallvec![(Ok(Flag::SEEN), false)],
);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("set_unseen".into(), fut);
account
.insert_job(handle.job_id, JobRequest::SetFlags { env_hashes, handle });
}
}
}
ListingAction::Tag(Remove(ref tag_str)) => {
let job = account.backend.write().unwrap().set_flags(
env_hashes.clone(),
mailbox_hash,
smallvec::smallvec![(Err(tag_str.to_string()), false)],
);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("remove_tag".into(), fut);
account
.insert_job(handle.job_id, JobRequest::SetFlags { env_hashes, handle });
}
}
}
ListingAction::Tag(Add(ref tag_str)) => {
let job = account.backend.write().unwrap().set_flags(
env_hashes.clone(),
mailbox_hash,
smallvec::smallvec![(Err(tag_str.to_string()), true)],
);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("add_tag".into(), fut);
account
.insert_job(handle.job_id, JobRequest::SetFlags { env_hashes, handle });
}
}
}
ListingAction::Delete => {
let job = account
.backend
.write()
.unwrap()
.delete_messages(env_hashes.clone(), mailbox_hash);
match job {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("delete".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::DeleteMessages { env_hashes, handle },
);
}
}
}
ListingAction::CopyTo(ref mailbox_path) => {
match account
.mailbox_by_path(mailbox_path)
.and_then(|destination_mailbox_hash| {
account.backend.write().unwrap().copy_messages(
env_hashes,
mailbox_hash,
destination_mailbox_hash,
/* move? */ false,
)
}) {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("copy_to_mailbox".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::Generic {
name: "message copying".into(),
handle,
on_finish: None,
log_level: LogLevel::INFO,
},
);
}
}
}
ListingAction::CopyToOtherAccount(ref _account_name, ref _mailbox_path) => {
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::DisplayMessage(
"Copying to another account is currently unimplemented".into(),
)));
}
ListingAction::MoveTo(ref mailbox_path) => {
match account
.mailbox_by_path(mailbox_path)
.and_then(|destination_mailbox_hash| {
account.backend.write().unwrap().copy_messages(
env_hashes,
mailbox_hash,
destination_mailbox_hash,
/* move? */ true,
)
}) {
Err(err) => {
context.replies.push_back(UIEvent::StatusEvent(
StatusEvent::DisplayMessage(err.to_string()),
));
}
Ok(fut) => {
let handle = account
.main_loop_handler
.job_executor
.spawn_specialized("move_to_mailbox".into(), fut);
account.insert_job(
handle.job_id,
JobRequest::Generic {
name: "message moving".into(),
handle,
on_finish: None,
log_level: LogLevel::INFO,
},
);
}
}
}
ListingAction::ExportMbox(format, ref path) => {
use std::{future::Future, io::Write, pin::Pin};
use futures::future::try_join_all;
let futures: Result<Vec<_>> = envs_to_set
.iter()
.map(|&env_hash| account.operation(env_hash).and_then(|mut op| op.as_bytes()))
.collect::<Result<Vec<_>>>();
let path_ = path.to_path_buf();
let format = (*format).unwrap_or_default();
let collection = account.collection.clone();
let (sender, mut receiver) = crate::jobs::oneshot::channel();
let fut: Pin<Box<dyn Future<Output = Result<()>> + Send + 'static>> =
Box::pin(async move {
let cl = async move {
use melib::backends::mbox::MboxMetadata;
let bytes: Vec<Vec<u8>> = try_join_all(futures?).await?;
let envs: Vec<_> = envs_to_set
.iter()
.map(|&env_hash| collection.get_env(env_hash))
.collect();
let mut file = std::io::BufWriter::new(std::fs::File::create(&path_)?);
let mut iter = envs.iter().zip(bytes.into_iter());
let tags_lck = collection.tag_index.read().unwrap();
if let Some((env, ref bytes)) = iter.next() {
let tags: Vec<&str> = env
.tags()
.iter()
.filter_map(|h| tags_lck.get(h).map(|s| s.as_str()))
.collect();
format.append(
&mut file,
bytes.as_slice(),
env.from().get(0),
Some(env.date()),
(env.flags(), tags),
MboxMetadata::CClient,
true,
false,
)?;
}
for (env, bytes) in iter {
let tags: Vec<&str> = env
.tags()
.iter()
.filter_map(|h| tags_lck.get(h).map(|s| s.as_str()))
.collect();
format.append(
&mut file,
bytes.as_slice(),
env.from().get(0),
Some(env.date()),
(env.flags(), tags),
MboxMetadata::CClient,
false,
false,
)?;
}
file.flush()?;
Ok(())
};
let r: Result<()> = cl.await;
let _ = sender.send(r);
Ok(())
});
let handle = account
.main_loop_handler
.job_executor
.spawn_blocking("export_to_mbox".into(), fut);
let path = path.to_path_buf();
account.insert_job(
handle.job_id,
JobRequest::Generic {
name: "exporting mbox".into(),
handle,
on_finish: Some(CallbackFn(Box::new(move |context: &mut Context| {
context.replies.push_back(match receiver.try_recv() {
Err(_) | Ok(None) => UIEvent::Notification(
Some("Could not export mbox".to_string()),
"Job was canceled.".to_string(),
Some(NotificationType::Info),
),
Ok(Some(Err(err))) => UIEvent::Notification(
Some("Could not export mbox".to_string()),
err.to_string(),
Some(NotificationType::Error(err.kind)),
),
Ok(Some(Ok(()))) => UIEvent::Notification(
Some("Succesfully exported mbox".to_string()),
format!("Wrote to file {}", path.display()),
Some(NotificationType::Info),
),
});
}))),
log_level: LogLevel::INFO,
},
);
}
ListingAction::MoveToOtherAccount(ref _account_name, ref _mailbox_path) => {
context
.replies
.push_back(UIEvent::StatusEvent(StatusEvent::DisplayMessage(
"Moving to another account is currently unimplemented".into(),
)));
}
_ => unreachable!(),
}
self.set_dirty(true); self.set_dirty(true);
} }

View File

@ -45,7 +45,7 @@ mod thread;
pub use thread::*; pub use thread::*;
mod types; mod types;
pub use types::*; pub use types::*;
mod state; pub mod state;
use state::*; use state::*;
pub mod envelope; pub mod envelope;

View File

@ -1010,7 +1010,7 @@ mod pp {
/// Expands `include` macros in configuration file and other configuration /// Expands `include` macros in configuration file and other configuration
/// files (eg. themes) in the filesystem. /// files (eg. themes) in the filesystem.
pub fn pp<P: AsRef<Path>>(path: P) -> Result<String> { pub(super) fn pp<P: AsRef<Path>>(path: P) -> Result<String> {
let p_buf: PathBuf = if path.as_ref().is_relative() { let p_buf: PathBuf = if path.as_ref().is_relative() {
path.as_ref().expand().canonicalize()? path.as_ref().expand().canonicalize()?
} else { } else {

View File

@ -466,6 +466,8 @@ impl Account {
let backend = map.get(&settings.account().format)( let backend = map.get(&settings.account().format)(
settings.account(), settings.account(),
Box::new(move |path: &str| { Box::new(move |path: &str| {
// disjoint-capture-in-closures
let _ = &s;
s.account.subscribed_mailboxes.is_empty() s.account.subscribed_mailboxes.is_empty()
|| (s.mailbox_confs.contains_key(path) || (s.mailbox_confs.contains_key(path)
&& s.mailbox_confs[path].mailbox_conf().subscribe.is_true()) && s.mailbox_confs[path].mailbox_conf().subscribe.is_true())

View File

@ -171,7 +171,7 @@ macro_rules! named_unit_variant {
}; };
} }
mod strings { pub mod strings {
named_unit_variant!(server_submission); named_unit_variant!(server_submission);
} }

View File

@ -44,7 +44,11 @@ use crate::types::{ThreadEvent, UIEvent};
type AsyncTask = async_task::Runnable; type AsyncTask = async_task::Runnable;
fn find_task<T>(local: &Worker<T>, global: &Injector<T>, stealers: &[Stealer<T>]) -> Option<T> { fn find_task(
local: &Worker<MeliTask>,
global: &Injector<MeliTask>,
stealers: &[Stealer<MeliTask>],
) -> Option<MeliTask> {
// Pop a task from the local queue, if not empty. // Pop a task from the local queue, if not empty.
local.pop().or_else(|| { local.pop().or_else(|| {
// Otherwise, we need to look for a task elsewhere. // Otherwise, we need to look for a task elsewhere.

View File

@ -26,13 +26,13 @@ use serde::{de, de::Visitor, Deserialize, Deserializer};
mod color; mod color;
pub use color::*; pub use color::*;
#[macro_use] #[macro_use]
mod position; pub mod position;
#[macro_use] #[macro_use]
mod cells; pub mod cells;
#[macro_use] #[macro_use]
mod keys; pub mod keys;
pub mod embed; pub mod embed;
mod text_editing; pub mod text_editing;
use std::fmt; use std::fmt;
pub use self::{cells::*, keys::*, position::*, text_editing::*}; pub use self::{cells::*, keys::*, position::*, text_editing::*};

View File

@ -746,7 +746,6 @@ impl Serialize for Color {
} }
} }
pub use aliases::*;
pub mod aliases { pub mod aliases {
use super::Color; use super::Color;

View File

@ -34,10 +34,10 @@ mod watch;
pub use watch::*; pub use watch::*;
mod search; mod search;
pub use search::*; pub use search::*;
mod cache; pub mod cache;
pub mod error; pub mod error;
pub mod managesieve; pub mod managesieve;
mod untagged; pub mod untagged;
use std::{ use std::{
collections::{hash_map::DefaultHasher, BTreeSet, HashMap, HashSet}, collections::{hash_map::DefaultHasher, BTreeSet, HashMap, HashSet},

View File

@ -20,7 +20,7 @@
*/ */
use super::*; use super::*;
mod sync; pub mod sync;
use std::convert::TryFrom; use std::convert::TryFrom;
use crate::{ use crate::{
@ -104,7 +104,7 @@ pub trait ImapCacheReset: Send + core::fmt::Debug {
pub use sqlite3_m::*; pub use sqlite3_m::*;
#[cfg(feature = "sqlite3")] #[cfg(feature = "sqlite3")]
mod sqlite3_m { pub mod sqlite3_m {
use super::*; use super::*;
use crate::utils::sqlite3::{ use crate::utils::sqlite3::{
self, self,
@ -739,7 +739,7 @@ pub(super) async fn fetch_cached_envs(state: &mut FetchState) -> Result<Option<V
pub use default_m::*; pub use default_m::*;
#[cfg(not(feature = "sqlite3"))] #[cfg(not(feature = "sqlite3"))]
mod default_m { pub mod default_m {
use super::*; use super::*;
#[derive(Debug)] #[derive(Debug)]
pub struct DefaultCache; pub struct DefaultCache;

View File

@ -25,11 +25,6 @@ use std::{
time::SystemTime, time::SystemTime,
}; };
use nom::{
branch::alt, bytes::complete::tag, combinator::map, multi::separated_list1,
sequence::separated_pair,
};
use super::{ImapConnection, ImapProtocol, ImapServerConf, UIDStore}; use super::{ImapConnection, ImapProtocol, ImapServerConf, UIDStore};
use crate::{ use crate::{
conf::AccountSettings, conf::AccountSettings,
@ -43,17 +38,6 @@ pub struct ManageSieveConnection {
pub inner: ImapConnection, pub inner: ImapConnection,
} }
pub fn managesieve_capabilities(input: &[u8]) -> Result<Vec<(&[u8], &[u8])>> {
let (_, ret) = separated_list1(
tag(b"\r\n"),
alt((
separated_pair(quoted_raw, tag(b" "), quoted_raw),
map(quoted_raw, |q| (q, &b""[..])),
)),
)(input)?;
Ok(ret)
}
#[derive(PartialEq, Eq, Debug, Copy, Clone)] #[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum ManageSieveResponse<'a> { pub enum ManageSieveResponse<'a> {
Ok { Ok {
@ -66,231 +50,6 @@ pub enum ManageSieveResponse<'a> {
}, },
} }
mod parser {
use nom::{
bytes::complete::tag,
character::complete::crlf,
combinator::{iterator, map, opt},
};
pub use nom::{
bytes::complete::{is_not, tag_no_case},
sequence::{delimited, pair, preceded, terminated},
};
use super::*;
pub fn sieve_name(input: &[u8]) -> IResult<&[u8], &[u8]> {
crate::backends::imap::protocol_parser::string_token(input)
}
// *(sieve-name [SP "ACTIVE"] CRLF)
// response-oknobye
pub fn listscripts(input: &[u8]) -> IResult<&[u8], Vec<(&[u8], bool)>> {
let mut it = iterator(
input,
alt((
terminated(
map(terminated(sieve_name, tag_no_case(b" ACTIVE")), |r| {
(r, true)
}),
crlf,
),
terminated(map(sieve_name, |r| (r, false)), crlf),
)),
);
let parsed = (&mut it).collect::<Vec<(&[u8], bool)>>();
let res: IResult<_, _> = it.finish();
let (rest, _) = res?;
Ok((rest, parsed))
}
// response-getscript = (sieve-script CRLF response-ok) /
// response-nobye
pub fn getscript(input: &[u8]) -> IResult<&[u8], &[u8]> {
sieve_name(input)
}
pub fn response_oknobye(input: &[u8]) -> IResult<&[u8], ManageSieveResponse> {
alt((
map(
terminated(
pair(
preceded(
tag_no_case(b"ok"),
opt(preceded(
tag(b" "),
delimited(tag(b"("), is_not(")"), tag(b")")),
)),
),
opt(preceded(tag(b" "), sieve_name)),
),
crlf,
),
|(code, message)| ManageSieveResponse::Ok { code, message },
),
map(
terminated(
pair(
preceded(
alt((tag_no_case(b"no"), tag_no_case(b"bye"))),
opt(preceded(
tag(b" "),
delimited(tag(b"("), is_not(")"), tag(b")")),
)),
),
opt(preceded(tag(b" "), sieve_name)),
),
crlf,
),
|(code, message)| ManageSieveResponse::NoBye { code, message },
),
))(input)
}
#[test]
fn test_managesieve_listscripts() {
let input_1 = b"\"summer_script\"\r\n\"vacation_script\"\r\n{13}\r\nclever\"script\r\n\"main_script\" ACTIVE\r\nOK";
assert_eq!(
terminated(listscripts, tag_no_case(b"OK"))(input_1),
Ok((
&b""[..],
vec![
(&b"summer_script"[..], false),
(&b"vacation_script"[..], false),
(&b"clever\"script"[..], false),
(&b"main_script"[..], true)
]
))
);
let input_2 = b"\"summer_script\"\r\n\"main_script\" active\r\nok";
assert_eq!(
terminated(listscripts, tag_no_case(b"OK"))(input_2),
Ok((
&b""[..],
vec![(&b"summer_script"[..], false), (&b"main_script"[..], true)]
))
);
let input_3 = b"ok";
assert_eq!(
terminated(listscripts, tag_no_case(b"OK"))(input_3),
Ok((&b""[..], vec![]))
);
}
#[test]
fn test_managesieve_general() {
assert_eq!(managesieve_capabilities(b"\"IMPLEMENTATION\" \"Dovecot Pigeonhole\"\r\n\"SIEVE\" \"fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date index ihave duplicate mime foreverypart extracttext\"\r\n\"NOTIFY\" \"mailto\"\r\n\"SASL\" \"PLAIN\"\r\n\"STARTTLS\"\r\n\"VERSION\" \"1.0\"\r\n").unwrap(), vec![
(&b"IMPLEMENTATION"[..],&b"Dovecot Pigeonhole"[..]),
(&b"SIEVE"[..],&b"fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date index ihave duplicate mime foreverypart extracttext"[..]),
(&b"NOTIFY"[..],&b"mailto"[..]),
(&b"SASL"[..],&b"PLAIN"[..]),
(&b"STARTTLS"[..], &b""[..]),
(&b"VERSION"[..],&b"1.0"[..])]
);
let response_ok = b"OK (WARNINGS) \"line 8: server redirect action limit is 2, this redirect might be ignored\"\r\n";
assert_eq!(
response_oknobye(response_ok),
Ok((
&b""[..],
ManageSieveResponse::Ok {
code: Some(&b"WARNINGS"[..]),
message: Some(&b"line 8: server redirect action limit is 2, this redirect might be ignored"[..]),
}
))
);
let response_ok = b"OK (WARNINGS)\r\n";
assert_eq!(
response_oknobye(response_ok),
Ok((
&b""[..],
ManageSieveResponse::Ok {
code: Some(&b"WARNINGS"[..]),
message: None,
}
))
);
let response_ok =
b"OK \"line 8: server redirect action limit is 2, this redirect might be ignored\"\r\n";
assert_eq!(
response_oknobye(response_ok),
Ok((
&b""[..],
ManageSieveResponse::Ok {
code: None,
message: Some(&b"line 8: server redirect action limit is 2, this redirect might be ignored"[..]),
}
))
);
let response_ok = b"Ok\r\n";
assert_eq!(
response_oknobye(response_ok),
Ok((
&b""[..],
ManageSieveResponse::Ok {
code: None,
message: None,
}
))
);
let response_nobye = b"No (NONEXISTENT) \"There is no script by that name\"\r\n";
assert_eq!(
response_oknobye(response_nobye),
Ok((
&b""[..],
ManageSieveResponse::NoBye {
code: Some(&b"NONEXISTENT"[..]),
message: Some(&b"There is no script by that name"[..]),
}
))
);
let response_nobye = b"No (NONEXISTENT) {31}\r\nThere is no script by that name\r\n";
assert_eq!(
response_oknobye(response_nobye),
Ok((
&b""[..],
ManageSieveResponse::NoBye {
code: Some(&b"NONEXISTENT"[..]),
message: Some(&b"There is no script by that name"[..]),
}
))
);
let response_nobye = b"No\r\n";
assert_eq!(
response_oknobye(response_nobye),
Ok((
&b""[..],
ManageSieveResponse::NoBye {
code: None,
message: None,
}
))
);
}
}
// Return a byte sequence surrounded by "s and decoded if necessary
pub fn quoted_raw(input: &[u8]) -> IResult<&[u8], &[u8]> {
if input.is_empty() || input[0] != b'"' {
return Err(nom::Err::Error((input, "empty").into()));
}
let mut i = 1;
while i < input.len() {
if input[i] == b'\"' && input[i - 1] != b'\\' {
return Ok((&input[i + 1..], &input[1..i]));
}
i += 1;
}
Err(nom::Err::Error((input, "no quotes").into()))
}
impl ManageSieveConnection { impl ManageSieveConnection {
pub fn new( pub fn new(
account_hash: crate::backends::AccountHash, account_hash: crate::backends::AccountHash,
@ -479,3 +238,247 @@ impl ManageSieveConnection {
Ok(()) Ok(())
} }
} }
pub mod parser {
use nom::{
branch::alt,
bytes::complete::tag,
character::complete::crlf,
combinator::{iterator, map, opt},
multi::separated_list1,
sequence::separated_pair,
};
pub use nom::{
bytes::complete::{is_not, tag_no_case},
sequence::{delimited, pair, preceded, terminated},
};
use super::*;
/// Return a byte sequence surrounded by "s and decoded if necessary
pub fn quoted_raw(input: &[u8]) -> IResult<&[u8], &[u8]> {
if input.is_empty() || input[0] != b'"' {
return Err(nom::Err::Error((input, "empty").into()));
}
let mut i = 1;
while i < input.len() {
if input[i] == b'\"' && input[i - 1] != b'\\' {
return Ok((&input[i + 1..], &input[1..i]));
}
i += 1;
}
Err(nom::Err::Error((input, "no quotes").into()))
}
pub fn managesieve_capabilities(input: &[u8]) -> Result<Vec<(&[u8], &[u8])>> {
let (_, ret) = separated_list1(
tag(b"\r\n"),
alt((
separated_pair(quoted_raw, tag(b" "), quoted_raw),
map(quoted_raw, |q| (q, &b""[..])),
)),
)(input)?;
Ok(ret)
}
pub fn sieve_name(input: &[u8]) -> IResult<&[u8], &[u8]> {
crate::backends::imap::protocol_parser::string_token(input)
}
// *(sieve-name [SP "ACTIVE"] CRLF)
// response-oknobye
pub fn listscripts(input: &[u8]) -> IResult<&[u8], Vec<(&[u8], bool)>> {
let mut it = iterator(
input,
alt((
terminated(
map(terminated(sieve_name, tag_no_case(b" ACTIVE")), |r| {
(r, true)
}),
crlf,
),
terminated(map(sieve_name, |r| (r, false)), crlf),
)),
);
let parsed = (&mut it).collect::<Vec<(&[u8], bool)>>();
let res: IResult<_, _> = it.finish();
let (rest, _) = res?;
Ok((rest, parsed))
}
// response-getscript = (sieve-script CRLF response-ok) /
// response-nobye
pub fn getscript(input: &[u8]) -> IResult<&[u8], &[u8]> {
sieve_name(input)
}
pub fn response_oknobye(input: &[u8]) -> IResult<&[u8], ManageSieveResponse> {
alt((
map(
terminated(
pair(
preceded(
tag_no_case(b"ok"),
opt(preceded(
tag(b" "),
delimited(tag(b"("), is_not(")"), tag(b")")),
)),
),
opt(preceded(tag(b" "), sieve_name)),
),
crlf,
),
|(code, message)| ManageSieveResponse::Ok { code, message },
),
map(
terminated(
pair(
preceded(
alt((tag_no_case(b"no"), tag_no_case(b"bye"))),
opt(preceded(
tag(b" "),
delimited(tag(b"("), is_not(")"), tag(b")")),
)),
),
opt(preceded(tag(b" "), sieve_name)),
),
crlf,
),
|(code, message)| ManageSieveResponse::NoBye { code, message },
),
))(input)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_managesieve_listscripts() {
let input_1 = b"\"summer_script\"\r\n\"vacation_script\"\r\n{13}\r\nclever\"script\r\n\"main_script\" ACTIVE\r\nOK";
assert_eq!(
terminated(listscripts, tag_no_case(b"OK"))(input_1),
Ok((
&b""[..],
vec![
(&b"summer_script"[..], false),
(&b"vacation_script"[..], false),
(&b"clever\"script"[..], false),
(&b"main_script"[..], true)
]
))
);
let input_2 = b"\"summer_script\"\r\n\"main_script\" active\r\nok";
assert_eq!(
terminated(listscripts, tag_no_case(b"OK"))(input_2),
Ok((
&b""[..],
vec![(&b"summer_script"[..], false), (&b"main_script"[..], true)]
))
);
let input_3 = b"ok";
assert_eq!(
terminated(listscripts, tag_no_case(b"OK"))(input_3),
Ok((&b""[..], vec![]))
);
}
#[test]
fn test_managesieve_general() {
assert_eq!(managesieve_capabilities(b"\"IMPLEMENTATION\" \"Dovecot Pigeonhole\"\r\n\"SIEVE\" \"fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date index ihave duplicate mime foreverypart extracttext\"\r\n\"NOTIFY\" \"mailto\"\r\n\"SASL\" \"PLAIN\"\r\n\"STARTTLS\"\r\n\"VERSION\" \"1.0\"\r\n").unwrap(), vec![
(&b"IMPLEMENTATION"[..],&b"Dovecot Pigeonhole"[..]),
(&b"SIEVE"[..],&b"fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date index ihave duplicate mime foreverypart extracttext"[..]),
(&b"NOTIFY"[..],&b"mailto"[..]),
(&b"SASL"[..],&b"PLAIN"[..]),
(&b"STARTTLS"[..], &b""[..]),
(&b"VERSION"[..],&b"1.0"[..])]
);
let response_ok = b"OK (WARNINGS) \"line 8: server redirect action limit is 2, this redirect might be ignored\"\r\n";
assert_eq!(
response_oknobye(response_ok),
Ok((
&b""[..],
ManageSieveResponse::Ok {
code: Some(&b"WARNINGS"[..]),
message: Some(&b"line 8: server redirect action limit is 2, this redirect might be ignored"[..]),
}
))
);
let response_ok = b"OK (WARNINGS)\r\n";
assert_eq!(
response_oknobye(response_ok),
Ok((
&b""[..],
ManageSieveResponse::Ok {
code: Some(&b"WARNINGS"[..]),
message: None,
}
))
);
let response_ok =
b"OK \"line 8: server redirect action limit is 2, this redirect might be ignored\"\r\n";
assert_eq!(
response_oknobye(response_ok),
Ok((
&b""[..],
ManageSieveResponse::Ok {
code: None,
message: Some(&b"line 8: server redirect action limit is 2, this redirect might be ignored"[..]),
}
))
);
let response_ok = b"Ok\r\n";
assert_eq!(
response_oknobye(response_ok),
Ok((
&b""[..],
ManageSieveResponse::Ok {
code: None,
message: None,
}
))
);
let response_nobye = b"No (NONEXISTENT) \"There is no script by that name\"\r\n";
assert_eq!(
response_oknobye(response_nobye),
Ok((
&b""[..],
ManageSieveResponse::NoBye {
code: Some(&b"NONEXISTENT"[..]),
message: Some(&b"There is no script by that name"[..]),
}
))
);
let response_nobye = b"No (NONEXISTENT) {31}\r\nThere is no script by that name\r\n";
assert_eq!(
response_oknobye(response_nobye),
Ok((
&b""[..],
ManageSieveResponse::NoBye {
code: Some(&b"NONEXISTENT"[..]),
message: Some(&b"There is no script by that name"[..]),
}
))
);
let response_nobye = b"No\r\n";
assert_eq!(
response_oknobye(response_nobye),
Ok((
&b""[..],
ManageSieveResponse::NoBye {
code: None,
message: None,
}
))
);
}
}
}

View File

@ -202,20 +202,20 @@ fn get_rw_lock_blocking(f: &File, path: &Path) -> Result<()> {
} }
#[derive(Debug)] #[derive(Debug)]
struct MboxMailbox { pub struct MboxMailbox {
hash: MailboxHash, pub hash: MailboxHash,
name: String, pub name: String,
path: PathBuf, pub path: PathBuf,
fs_path: PathBuf, pub fs_path: PathBuf,
content: Vec<u8>, pub content: Vec<u8>,
children: Vec<MailboxHash>, pub children: Vec<MailboxHash>,
parent: Option<MailboxHash>, pub parent: Option<MailboxHash>,
usage: Arc<RwLock<SpecialUsageMailbox>>, pub usage: Arc<RwLock<SpecialUsageMailbox>>,
is_subscribed: bool, pub is_subscribed: bool,
permissions: MailboxPermissions, pub permissions: MailboxPermissions,
pub total: Arc<Mutex<usize>>, pub total: Arc<Mutex<usize>>,
pub unseen: Arc<Mutex<usize>>, pub unseen: Arc<Mutex<usize>>,
index: Arc<Mutex<HashMap<EnvelopeHash, (Offset, Length)>>>, pub index: Arc<Mutex<HashMap<EnvelopeHash, (Offset, Length)>>>,
} }
impl BackendMailbox for MboxMailbox { impl BackendMailbox for MboxMailbox {
@ -285,11 +285,11 @@ impl BackendMailbox for MboxMailbox {
/// `BackendOp` implementor for Mbox /// `BackendOp` implementor for Mbox
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct MboxOp { pub struct MboxOp {
_hash: EnvelopeHash, pub _hash: EnvelopeHash,
path: PathBuf, pub path: PathBuf,
offset: Offset, pub offset: Offset,
length: Length, pub length: Length,
slice: std::cell::RefCell<Option<Vec<u8>>>, pub slice: std::cell::RefCell<Option<Vec<u8>>>,
} }
impl MboxOp { impl MboxOp {

View File

@ -30,6 +30,7 @@ use smallvec::SmallVec;
use crate::{get_conf_val, get_path_hash}; use crate::{get_conf_val, get_path_hash};
mod store; mod store;
pub use store::*;
#[macro_use] #[macro_use]
mod protocol_parser; mod protocol_parser;
pub use protocol_parser::*; pub use protocol_parser::*;

View File

@ -55,7 +55,7 @@ CREATE TABLE IF NOT EXISTS article (
#[derive(Debug)] #[derive(Debug)]
pub struct Store { pub struct Store {
connection: Connection, pub connection: Connection,
} }
impl Store { impl Store {

View File

@ -718,7 +718,7 @@ impl MailBackend for NotmuchDb {
use notify::{watcher, RecursiveMode, Watcher}; use notify::{watcher, RecursiveMode, Watcher};
let account_hash = self.account_hash; let account_hash = self.account_hash;
let collection = self.collection.clone(); let tag_index = self.collection.tag_index.clone();
let lib = self.lib.clone(); let lib = self.lib.clone();
let path = self.path.clone(); let path = self.path.clone();
let revision_uuid = self.revision_uuid.clone(); let revision_uuid = self.revision_uuid.clone();
@ -748,7 +748,7 @@ impl MailBackend for NotmuchDb {
mailboxes.clone(), mailboxes.clone(),
index.clone(), index.clone(),
mailbox_index.clone(), mailbox_index.clone(),
collection.tag_index.clone(), tag_index.clone(),
account_hash, account_hash,
event_consumer.clone(), event_consumer.clone(),
new_revision_uuid, new_revision_uuid,
@ -826,7 +826,7 @@ impl MailBackend for NotmuchDb {
self.lib.clone(), self.lib.clone(),
true, true,
)?; )?;
let collection = self.collection.clone(); let tag_index = self.collection.clone().tag_index;
let index = self.index.clone(); let index = self.index.clone();
Ok(Box::pin(async move { Ok(Box::pin(async move {
@ -914,11 +914,7 @@ impl MailBackend for NotmuchDb {
for (f, v) in flags.iter() { for (f, v) in flags.iter() {
if let (Err(tag), true) = (f, v) { if let (Err(tag), true) = (f, v) {
let hash = TagHash::from_bytes(tag.as_bytes()); let hash = TagHash::from_bytes(tag.as_bytes());
collection tag_index.write().unwrap().insert(hash, tag.to_string());
.tag_index
.write()
.unwrap()
.insert(hash, tag.to_string());
} }
} }

View File

@ -186,7 +186,7 @@ macro_rules! named_unit_variant {
}; };
} }
mod strings { pub mod strings {
named_unit_variant!(ask); named_unit_variant!(ask);
} }
@ -253,7 +253,7 @@ impl<'de> Deserialize<'de> for ToggleFlag {
{ {
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(untagged)] #[serde(untagged)]
pub enum InnerToggleFlag { enum InnerToggleFlag {
Bool(bool), Bool(bool),
#[serde(with = "strings::ask")] #[serde(with = "strings::ask")]
Ask, Ask,

View File

@ -2595,25 +2595,26 @@ pub mod address {
)) ))
} }
///`no-fold-literal = "[" *dtext "]"`
pub fn no_fold_literal(input: &[u8]) -> IResult<&[u8], Cow<'_, [u8]>> {
let orig_input = input;
let (input, _) = tag("[")(input)?;
let (input, ret) = many0(dtext)(input)?;
let (input, _) = tag("]")(input)?;
Ok((input, Cow::Borrowed(&orig_input[0..ret.len() + 1])))
}
///`id-left = dot-atom-text / obs-id-left`
pub fn id_left(input: &[u8]) -> IResult<&[u8], Cow<'_, [u8]>> {
dot_atom_text(input)
}
///`id-right = dot-atom-text / no-fold-literal / obs-id-right`
pub fn id_right(input: &[u8]) -> IResult<&[u8], Cow<'_, [u8]>> {
alt((dot_atom_text, no_fold_literal))(input)
}
///`msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]` ///`msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]`
pub fn msg_id(input: &[u8]) -> IResult<&[u8], MessageID> { pub fn msg_id(input: &[u8]) -> IResult<&[u8], MessageID> {
///`no-fold-literal = "[" *dtext "]"`
pub fn no_fold_literal(input: &[u8]) -> IResult<&[u8], Cow<'_, [u8]>> {
let orig_input = input;
let (input, _) = tag("[")(input)?;
let (input, ret) = many0(dtext)(input)?;
let (input, _) = tag("]")(input)?;
Ok((input, Cow::Borrowed(&orig_input[0..ret.len() + 1])))
}
///`id-left = dot-atom-text / obs-id-left`
pub fn id_left(input: &[u8]) -> IResult<&[u8], Cow<'_, [u8]>> {
dot_atom_text(input)
}
///`id-right = dot-atom-text / no-fold-literal / obs-id-right`
pub fn id_right(input: &[u8]) -> IResult<&[u8], Cow<'_, [u8]>> {
alt((dot_atom_text, no_fold_literal))(input)
}
let (input, _) = opt(cfws)(input)?; let (input, _) = opt(cfws)(input)?;
let orig_input = input; let orig_input = input;
let (input, _) = tag("<")(input)?; let (input, _) = tag("<")(input)?;

View File

@ -30,6 +30,9 @@ struct TagData {
io_state: Arc<Mutex<IoState>>, io_state: Arc<Mutex<IoState>>,
} }
///
/// # Safety
/// .
pub unsafe extern "C" fn gpgme_register_io_cb( pub unsafe extern "C" fn gpgme_register_io_cb(
data: *mut ::std::os::raw::c_void, data: *mut ::std::os::raw::c_void,
fd: ::std::os::raw::c_int, fd: ::std::os::raw::c_int,
@ -66,6 +69,9 @@ pub unsafe extern "C" fn gpgme_register_io_cb(
0 0
} }
///
/// # Safety
/// .
pub unsafe extern "C" fn gpgme_remove_io_cb(tag: *mut ::std::os::raw::c_void) { pub unsafe extern "C" fn gpgme_remove_io_cb(tag: *mut ::std::os::raw::c_void) {
let tag_data: Arc<TagData> = Arc::from_raw(tag as *const _); let tag_data: Arc<TagData> = Arc::from_raw(tag as *const _);
let mut io_state_lck = tag_data.io_state.lock().unwrap(); let mut io_state_lck = tag_data.io_state.lock().unwrap();
@ -75,6 +81,9 @@ pub unsafe extern "C" fn gpgme_remove_io_cb(tag: *mut ::std::os::raw::c_void) {
let _ = Arc::into_raw(tag_data); let _ = Arc::into_raw(tag_data);
} }
///
/// # Safety
/// .
pub unsafe extern "C" fn gpgme_event_io_cb( pub unsafe extern "C" fn gpgme_event_io_cb(
data: *mut ::std::os::raw::c_void, data: *mut ::std::os::raw::c_void,
type_: gpgme_event_io_t, type_: gpgme_event_io_t,

View File

@ -72,9 +72,9 @@ macro_rules! c_string_literal {
} }
}}; }};
} }
mod bindings; pub mod bindings;
use bindings::*; use bindings::*;
mod io; pub mod io;
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GpgmeFlag { pub enum GpgmeFlag {
@ -804,7 +804,8 @@ impl Context {
.chain_err_summary(|| { .chain_err_summary(|| {
"libgpgme error: could not perform seek on signature data object" "libgpgme error: could not perform seek on signature data object"
})?; })?;
_ = text; // disjoint-capture-in-closures
let _ = &text;
sig.into_bytes() sig.into_bytes()
}) })
} }
@ -1127,7 +1128,8 @@ impl Context {
cipher cipher
.seek(std::io::SeekFrom::Start(0)) .seek(std::io::SeekFrom::Start(0))
.chain_err_summary(|| "libgpgme error: could not perform seek on plain text")?; .chain_err_summary(|| "libgpgme error: could not perform seek on plain text")?;
_ = plain; // disjoint-capture-in-closures
let _ = &plain;
cipher.into_bytes() cipher.into_bytes()
}) })
} }

View File

@ -22,8 +22,8 @@
pub mod grapheme_clusters; pub mod grapheme_clusters;
pub mod line_break; pub mod line_break;
pub mod search; pub mod search;
mod tables; pub mod tables;
mod types; pub mod types;
pub use types::Reflow; pub use types::Reflow;
pub mod wcwidth; pub mod wcwidth;
pub use grapheme_clusters::*; pub use grapheme_clusters::*;

View File

@ -741,7 +741,7 @@ const TIMEZONE_ABBR: &[(&[u8], (i8, i8))] = &[
(b"YEKT", (05, 0)), (b"YEKT", (05, 0)),
]; ];
mod lib { pub mod lib {
use std::convert::TryFrom; use std::convert::TryFrom;
use libc::tm; use libc::tm;