summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKit La Touche <kit@transneptune.net>2025-02-21 22:18:56 -0500
committerKit La Touche <kit@transneptune.net>2025-02-21 22:53:49 -0500
commit9d1dbac74866a6175c65a25bbd8a3ccbe8cf87e4 (patch)
treef15b3f0695b948e335774aa4d92a5b064a1c0f10 /src
parent743b59b69857da81b214970ec9252bc918ad243d (diff)
parent36cadfe00cacc6a6523f9862d3f7a08a9d0ce611 (diff)
Merge branch 'main' into prop/preserve-state
Diffstat (limited to 'src')
-rw-r--r--src/boot/routes/mod.rs2
-rw-r--r--src/broadcast.rs8
-rw-r--r--src/channel/app.rs5
-rw-r--r--src/channel/history.rs4
-rw-r--r--src/channel/repo.rs6
-rw-r--r--src/channel/routes/channel/post.rs2
-rw-r--r--src/channel/routes/mod.rs6
-rw-r--r--src/channel/routes/post.rs2
-rw-r--r--src/channel/snapshot.rs2
-rw-r--r--src/cli.rs2
-rw-r--r--src/clock.rs3
-rw-r--r--src/db/backup.rs4
-rw-r--r--src/event/app.rs9
-rw-r--r--src/event/extract.rs45
-rw-r--r--src/event/repo.rs6
-rw-r--r--src/event/routes/get.rs5
-rw-r--r--src/event/routes/mod.rs2
-rw-r--r--src/event/routes/test/resume.rs26
-rw-r--r--src/invite/app.rs6
-rw-r--r--src/invite/repo.rs6
-rw-r--r--src/invite/routes/mod.rs6
-rw-r--r--src/login/app.rs2
-rw-r--r--src/login/create.rs10
-rw-r--r--src/login/history.rs4
-rw-r--r--src/login/repo.rs8
-rw-r--r--src/login/routes/mod.rs2
-rw-r--r--src/login/snapshot.rs2
-rw-r--r--src/message/app.rs4
-rw-r--r--src/message/event.rs2
-rw-r--r--src/message/history.rs4
-rw-r--r--src/message/repo.rs8
-rw-r--r--src/message/routes/mod.rs4
-rw-r--r--src/message/snapshot.rs2
-rw-r--r--src/name.rs2
-rw-r--r--src/normalize/string.rs16
-rw-r--r--src/setup/app.rs4
-rw-r--r--src/setup/repo.rs6
-rw-r--r--src/setup/routes/mod.rs2
-rw-r--r--src/test/fixtures/cookie.rs2
-rw-r--r--src/test/fixtures/event.rs6
-rw-r--r--src/test/fixtures/future.rs10
-rw-r--r--src/token/app.rs14
-rw-r--r--src/token/extract/cookie.rs3
-rw-r--r--src/token/extract/identity.rs18
-rw-r--r--src/token/repo/auth.rs8
-rw-r--r--src/token/repo/token.rs6
-rw-r--r--src/ui/assets.rs2
-rw-r--r--src/ui/routes/mod.rs8
48 files changed, 181 insertions, 135 deletions
diff --git a/src/boot/routes/mod.rs b/src/boot/routes/mod.rs
index e4d5ac8..8fd99d3 100644
--- a/src/boot/routes/mod.rs
+++ b/src/boot/routes/mod.rs
@@ -1,4 +1,4 @@
-use axum::{routing::get, Router};
+use axum::{Router, routing::get};
use crate::app::App;
diff --git a/src/broadcast.rs b/src/broadcast.rs
index bedc263..2792a18 100644
--- a/src/broadcast.rs
+++ b/src/broadcast.rs
@@ -1,8 +1,8 @@
use std::sync::{Arc, Mutex};
-use futures::{future, stream::StreamExt as _, Stream};
-use tokio::sync::broadcast::{channel, Sender};
-use tokio_stream::wrappers::{errors::BroadcastStreamRecvError, BroadcastStream};
+use futures::{Stream, future, stream::StreamExt as _};
+use tokio::sync::broadcast::{Sender, channel};
+use tokio_stream::wrappers::{BroadcastStream, errors::BroadcastStreamRecvError};
// Clones will share the same sender.
#[derive(Clone)]
@@ -47,7 +47,7 @@ where
// panic: if ``channel`` has not been previously registered, and was not
// part of the initial set of channels.
- pub fn subscribe(&self) -> impl Stream<Item = M> + std::fmt::Debug {
+ pub fn subscribe(&self) -> impl Stream<Item = M> + std::fmt::Debug + use<M> {
let rx = self.sender().subscribe();
BroadcastStream::from(rx).scan((), |(), r| {
diff --git a/src/channel/app.rs b/src/channel/app.rs
index 1e341e3..dc9e584 100644
--- a/src/channel/app.rs
+++ b/src/channel/app.rs
@@ -3,13 +3,14 @@ use itertools::Itertools;
use sqlx::sqlite::SqlitePool;
use super::{
+ Channel, Id,
repo::{LoadError, Provider as _},
- validate, Channel, Id,
+ validate,
};
use crate::{
clock::DateTime,
db::{Duplicate as _, NotFound as _},
- event::{repo::Provider as _, Broadcaster, Event, Sequence},
+ event::{Broadcaster, Event, Sequence, repo::Provider as _},
message::{self, repo::Provider as _},
name::{self, Name},
};
diff --git a/src/channel/history.rs b/src/channel/history.rs
index ef2120d..4af46ce 100644
--- a/src/channel/history.rs
+++ b/src/channel/history.rs
@@ -1,8 +1,8 @@
use itertools::Itertools as _;
use super::{
- event::{Created, Deleted, Event},
Channel, Id,
+ event::{Created, Deleted, Event},
};
use crate::event::{Instant, Sequence};
@@ -42,7 +42,7 @@ impl History {
// Event factories
impl History {
- pub fn events(&self) -> impl Iterator<Item = Event> {
+ pub fn events(&self) -> impl Iterator<Item = Event> + use<> {
[self.created()]
.into_iter()
.merge_by(self.deleted(), Sequence::merge)
diff --git a/src/channel/repo.rs b/src/channel/repo.rs
index 6612151..91f245b 100644
--- a/src/channel/repo.rs
+++ b/src/channel/repo.rs
@@ -1,5 +1,5 @@
use futures::stream::{StreamExt as _, TryStreamExt as _};
-use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction};
+use sqlx::{SqliteConnection, Transaction, sqlite::Sqlite};
use crate::{
channel::{Channel, History, Id},
@@ -13,7 +13,7 @@ pub trait Provider {
fn channels(&mut self) -> Channels;
}
-impl<'c> Provider for Transaction<'c, Sqlite> {
+impl Provider for Transaction<'_, Sqlite> {
fn channels(&mut self) -> Channels {
Channels(self)
}
@@ -21,7 +21,7 @@ impl<'c> Provider for Transaction<'c, Sqlite> {
pub struct Channels<'t>(&'t mut SqliteConnection);
-impl<'c> Channels<'c> {
+impl Channels<'_> {
pub async fn create(&mut self, name: &Name, created: &Instant) -> Result<History, sqlx::Error> {
let id = Id::generate();
let name = name.clone();
diff --git a/src/channel/routes/channel/post.rs b/src/channel/routes/channel/post.rs
index b51e691..3f14d64 100644
--- a/src/channel/routes/channel/post.rs
+++ b/src/channel/routes/channel/post.rs
@@ -8,7 +8,7 @@ use crate::{
app::App,
clock::RequestedAt,
error::{Internal, NotFound},
- message::{app::SendError, Body, Message},
+ message::{Body, Message, app::SendError},
token::extract::Identity,
};
diff --git a/src/channel/routes/mod.rs b/src/channel/routes/mod.rs
index 696bd72..c917348 100644
--- a/src/channel/routes/mod.rs
+++ b/src/channel/routes/mod.rs
@@ -1,6 +1,6 @@
use axum::{
- routing::{delete, post},
Router,
+ routing::{delete, post},
};
use crate::app::App;
@@ -14,6 +14,6 @@ mod test;
pub fn router() -> Router<App> {
Router::new()
.route("/api/channels", post(post::handler))
- .route("/api/channels/:channel", post(channel::post::handler))
- .route("/api/channels/:channel", delete(channel::delete::handler))
+ .route("/api/channels/{channel}", post(channel::post::handler))
+ .route("/api/channels/{channel}", delete(channel::delete::handler))
}
diff --git a/src/channel/routes/post.rs b/src/channel/routes/post.rs
index 2cf1cc0..72eaad6 100644
--- a/src/channel/routes/post.rs
+++ b/src/channel/routes/post.rs
@@ -6,7 +6,7 @@ use axum::{
use crate::{
app::App,
- channel::{app, Channel},
+ channel::{Channel, app},
clock::RequestedAt,
error::Internal,
name::Name,
diff --git a/src/channel/snapshot.rs b/src/channel/snapshot.rs
index 129c0d6..046ac38 100644
--- a/src/channel/snapshot.rs
+++ b/src/channel/snapshot.rs
@@ -1,6 +1,6 @@
use super::{
- event::{Created, Event},
Id,
+ event::{Created, Event},
};
use crate::{clock::DateTime, name::Name};
diff --git a/src/cli.rs b/src/cli.rs
index 0d448d2..775df7f 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -6,10 +6,10 @@
use std::{future, io};
use axum::{
+ Router,
http::header,
middleware,
response::{IntoResponse, Response},
- Router,
};
use clap::{CommandFactory, Parser};
use sqlx::sqlite::SqlitePool;
diff --git a/src/clock.rs b/src/clock.rs
index 242bcdf..4341266 100644
--- a/src/clock.rs
+++ b/src/clock.rs
@@ -1,6 +1,6 @@
use axum::{
extract::{Extension, FromRequestParts, Request},
- http::{request::Parts, StatusCode},
+ http::{StatusCode, request::Parts},
middleware::Next,
response::Response,
};
@@ -21,7 +21,6 @@ impl RequestedAt {
}
}
-#[async_trait::async_trait]
impl<S> FromRequestParts<S> for RequestedAt
where
S: Send + Sync,
diff --git a/src/db/backup.rs b/src/db/backup.rs
index bb36aea..e3fa871 100644
--- a/src/db/backup.rs
+++ b/src/db/backup.rs
@@ -1,6 +1,6 @@
use rusqlite::{
- backup::{self},
Connection,
+ backup::{self},
};
use sqlx::sqlite::{LockedSqliteHandle, SqlitePool};
@@ -28,7 +28,7 @@ impl<'p> Backup<'p> {
}
}
-impl<'p> Backup<'p> {
+impl Backup<'_> {
pub async fn backup(&mut self) -> Result<(), Error> {
let mut to = self.to.acquire().await?;
let mut to = Self::connection(&mut to.lock_handle().await?)?;
diff --git a/src/event/app.rs b/src/event/app.rs
index b309245..8661c90 100644
--- a/src/event/app.rs
+++ b/src/event/app.rs
@@ -1,12 +1,11 @@
use futures::{
- future,
+ Stream, future,
stream::{self, StreamExt as _},
- Stream,
};
use itertools::Itertools as _;
use sqlx::sqlite::SqlitePool;
-use super::{broadcaster::Broadcaster, Event, Sequence, Sequenced};
+use super::{Event, Sequence, Sequenced, broadcaster::Broadcaster};
use crate::{
channel::{self, repo::Provider as _},
login::{self, repo::Provider as _},
@@ -27,7 +26,7 @@ impl<'a> Events<'a> {
pub async fn subscribe(
&self,
resume_at: Sequence,
- ) -> Result<impl Stream<Item = Event> + std::fmt::Debug, Error> {
+ ) -> Result<impl Stream<Item = Event> + std::fmt::Debug + use<>, Error> {
// Subscribe before retrieving, to catch messages broadcast while we're
// querying the DB. We'll prune out duplicates later.
let live_messages = self.events.subscribe();
@@ -76,7 +75,7 @@ impl<'a> Events<'a> {
Ok(replay.chain(live_messages))
}
- fn resume(resume_at: Sequence) -> impl for<'m> FnMut(&'m Event) -> future::Ready<bool> {
+ fn resume(resume_at: Sequence) -> impl for<'m> FnMut(&'m Event) -> future::Ready<bool> + use<> {
let filter = Sequence::after(resume_at);
move |event| future::ready(filter(event))
}
diff --git a/src/event/extract.rs b/src/event/extract.rs
index e3021e2..8fde1d5 100644
--- a/src/event/extract.rs
+++ b/src/event/extract.rs
@@ -1,11 +1,11 @@
use std::ops::Deref;
use axum::{
- extract::FromRequestParts,
- http::{request::Parts, HeaderName, HeaderValue},
+ extract::{FromRequestParts, OptionalFromRequestParts},
+ http::{HeaderName, HeaderValue, request::Parts},
};
use axum_extra::typed_header::TypedHeader;
-use serde::{de::DeserializeOwned, Serialize};
+use serde::{Serialize, de::DeserializeOwned};
// A typed header. When used as a bare extractor, reads from the
// `Last-Event-Id` HTTP header.
@@ -44,7 +44,6 @@ where
}
}
-#[async_trait::async_trait]
impl<S, T> FromRequestParts<S> for LastEventId<T>
where
S: Send + Sync,
@@ -53,12 +52,35 @@ where
type Rejection = <TypedHeader<Self> as FromRequestParts<S>>::Rejection;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
- // This is purely for ergonomics: it allows `RequestedAt` to be extracted
- // without having to wrap it in `Extension<>`. Callers _can_ still do that,
+ // This is purely for ergonomics: it allows `LastEventId` to be extracted
+ // without having to wrap it in `TypedHeader<>`. Callers _can_ still do that,
// but they aren't forced to.
- let TypedHeader(requested_at) = TypedHeader::from_request_parts(parts, state).await?;
+ let header =
+ <TypedHeader<Self> as FromRequestParts<S>>::from_request_parts(parts, state).await?;
- Ok(requested_at)
+ Ok(header.into())
+ }
+}
+
+impl<S, T> OptionalFromRequestParts<S> for LastEventId<T>
+where
+ S: Send + Sync,
+ T: Serialize + DeserializeOwned,
+{
+ type Rejection = <TypedHeader<Self> as FromRequestParts<S>>::Rejection;
+
+ async fn from_request_parts(
+ parts: &mut Parts,
+ state: &S,
+ ) -> Result<Option<Self>, Self::Rejection> {
+ // This is purely for ergonomics: it allows `Option<LastEventId>` to be extracted
+ // without having to wrap it in `TypedHeader<>`. Callers _can_ still do that,
+ // but they aren't forced to.
+ let header =
+ <TypedHeader<Self> as OptionalFromRequestParts<S>>::from_request_parts(parts, state)
+ .await?;
+
+ Ok(header.map(Self::from))
}
}
@@ -71,6 +93,13 @@ impl<T> Deref for LastEventId<T> {
}
}
+impl<T> From<TypedHeader<LastEventId<T>>> for LastEventId<T> {
+ fn from(header: TypedHeader<Self>) -> Self {
+ let TypedHeader(value) = header;
+ value
+ }
+}
+
impl<T> From<T> for LastEventId<T> {
fn from(value: T) -> Self {
Self(value)
diff --git a/src/event/repo.rs b/src/event/repo.rs
index 56beeea..ab3c449 100644
--- a/src/event/repo.rs
+++ b/src/event/repo.rs
@@ -1,4 +1,4 @@
-use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction};
+use sqlx::{SqliteConnection, Transaction, sqlite::Sqlite};
use crate::{
clock::DateTime,
@@ -9,7 +9,7 @@ pub trait Provider {
fn sequence(&mut self) -> Sequences;
}
-impl<'c> Provider for Transaction<'c, Sqlite> {
+impl Provider for Transaction<'_, Sqlite> {
fn sequence(&mut self) -> Sequences {
Sequences(self)
}
@@ -17,7 +17,7 @@ impl<'c> Provider for Transaction<'c, Sqlite> {
pub struct Sequences<'t>(&'t mut SqliteConnection);
-impl<'c> Sequences<'c> {
+impl Sequences<'_> {
pub async fn next(&mut self, at: &DateTime) -> Result<Instant, sqlx::Error> {
let next = sqlx::query_scalar!(
r#"
diff --git a/src/event/routes/get.rs b/src/event/routes/get.rs
index ceebcc9..2ca8991 100644
--- a/src/event/routes/get.rs
+++ b/src/event/routes/get.rs
@@ -1,9 +1,8 @@
use axum::{
extract::State,
response::{
- self,
+ self, IntoResponse,
sse::{self, Sse},
- IntoResponse,
},
};
use axum_extra::extract::Query;
@@ -12,7 +11,7 @@ use futures::stream::{Stream, StreamExt as _};
use crate::{
app::App,
error::{Internal, Unauthorized},
- event::{app, extract::LastEventId, Event, Sequence, Sequenced as _},
+ event::{Event, Sequence, Sequenced as _, app, extract::LastEventId},
token::{app::ValidateError, extract::Identity},
};
diff --git a/src/event/routes/mod.rs b/src/event/routes/mod.rs
index 57ab9db..742d397 100644
--- a/src/event/routes/mod.rs
+++ b/src/event/routes/mod.rs
@@ -1,4 +1,4 @@
-use axum::{routing::get, Router};
+use axum::{Router, routing::get};
use crate::app::App;
diff --git a/src/event/routes/test/resume.rs b/src/event/routes/test/resume.rs
index fabda0c..dc27691 100644
--- a/src/event/routes/test/resume.rs
+++ b/src/event/routes/test/resume.rs
@@ -5,7 +5,7 @@ use axum_extra::extract::Query;
use futures::stream::{self, StreamExt as _};
use crate::{
- event::{routes::get, Sequenced as _},
+ event::{Sequenced as _, routes::get},
test::fixtures::{self, future::Expect as _},
};
@@ -132,9 +132,11 @@ async fn serial_resume() {
.expect_ready("zipping a finite list of events is ready immediately")
.await;
- assert!(events
- .iter()
- .all(|(event, message)| message == &event.message));
+ assert!(
+ events
+ .iter()
+ .all(|(event, message)| message == &event.message)
+ );
let (event, _) = events.last().expect("this vec is non-empty");
@@ -173,9 +175,11 @@ async fn serial_resume() {
.expect_ready("zipping a finite list of events is ready immediately")
.await;
- assert!(events
- .iter()
- .all(|(event, message)| message == &event.message));
+ assert!(
+ events
+ .iter()
+ .all(|(event, message)| message == &event.message)
+ );
let (event, _) = events.last().expect("this vec is non-empty");
@@ -214,8 +218,10 @@ async fn serial_resume() {
.expect_ready("zipping a finite list of events is ready immediately")
.await;
- assert!(events
- .iter()
- .all(|(event, message)| message == &event.message));
+ assert!(
+ events
+ .iter()
+ .all(|(event, message)| message == &event.message)
+ );
};
}
diff --git a/src/invite/app.rs b/src/invite/app.rs
index d4e877a..c56c9b3 100644
--- a/src/invite/app.rs
+++ b/src/invite/app.rs
@@ -1,17 +1,17 @@
use chrono::TimeDelta;
use sqlx::sqlite::SqlitePool;
-use super::{repo::Provider as _, Id, Invite, Summary};
+use super::{Id, Invite, Summary, repo::Provider as _};
use crate::{
clock::DateTime,
db::{Duplicate as _, NotFound as _},
event::Broadcaster,
login::{
- create::{self, Create},
Login, Password,
+ create::{self, Create},
},
name::Name,
- token::{repo::Provider as _, Secret},
+ token::{Secret, repo::Provider as _},
};
pub struct Invites<'a> {
diff --git a/src/invite/repo.rs b/src/invite/repo.rs
index 5f86e49..c1dc701 100644
--- a/src/invite/repo.rs
+++ b/src/invite/repo.rs
@@ -1,4 +1,4 @@
-use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction};
+use sqlx::{SqliteConnection, Transaction, sqlite::Sqlite};
use super::{Id, Invite, Summary};
use crate::{
@@ -11,7 +11,7 @@ pub trait Provider {
fn invites(&mut self) -> Invites;
}
-impl<'c> Provider for Transaction<'c, Sqlite> {
+impl Provider for Transaction<'_, Sqlite> {
fn invites(&mut self) -> Invites {
Invites(self)
}
@@ -19,7 +19,7 @@ impl<'c> Provider for Transaction<'c, Sqlite> {
pub struct Invites<'t>(&'t mut SqliteConnection);
-impl<'c> Invites<'c> {
+impl Invites<'_> {
pub async fn create(
&mut self,
issuer: &Login,
diff --git a/src/invite/routes/mod.rs b/src/invite/routes/mod.rs
index 2f7375c..d83efc6 100644
--- a/src/invite/routes/mod.rs
+++ b/src/invite/routes/mod.rs
@@ -1,6 +1,6 @@
use axum::{
- routing::{get, post},
Router,
+ routing::{get, post},
};
use crate::app::App;
@@ -13,6 +13,6 @@ mod test;
pub fn router() -> Router<App> {
Router::new()
.route("/api/invite", post(post::handler))
- .route("/api/invite/:invite", get(invite::get::handler))
- .route("/api/invite/:invite", post(invite::post::handler))
+ .route("/api/invite/{invite}", get(invite::get::handler))
+ .route("/api/invite/{invite}", post(invite::post::handler))
}
diff --git a/src/login/app.rs b/src/login/app.rs
index f458561..2da4d6a 100644
--- a/src/login/app.rs
+++ b/src/login/app.rs
@@ -1,8 +1,8 @@
use sqlx::sqlite::SqlitePool;
use super::{
- create::{self, Create},
Login, Password,
+ create::{self, Create},
};
use crate::{clock::DateTime, event::Broadcaster, name::Name};
diff --git a/src/login/create.rs b/src/login/create.rs
index 693daaf..c5cea08 100644
--- a/src/login/create.rs
+++ b/src/login/create.rs
@@ -7,6 +7,7 @@ use crate::{
name::Name,
};
+#[must_use = "dropping a login creation attempt is likely a mistake"]
pub struct Create<'a> {
name: &'a Name,
password: &'a Password,
@@ -14,7 +15,6 @@ pub struct Create<'a> {
}
impl<'a> Create<'a> {
- #[must_use = "dropping a login creation attempt is likely a mistake"]
pub fn begin(name: &'a Name, password: &'a Password, created_at: &'a DateTime) -> Self {
Self {
name,
@@ -23,7 +23,6 @@ impl<'a> Create<'a> {
}
}
- #[must_use = "dropping a login creation attempt is likely a mistake"]
pub fn validate(self) -> Result<Validated<'a>, Error> {
let Self {
name,
@@ -45,15 +44,15 @@ impl<'a> Create<'a> {
}
}
+#[must_use = "dropping a login creation attempt is likely a mistake"]
pub struct Validated<'a> {
name: &'a Name,
password_hash: StoredHash,
created_at: &'a DateTime,
}
-impl<'a> Validated<'a> {
- #[must_use = "dropping a login creation attempt is likely a mistake"]
- pub async fn store<'c>(self, tx: &mut Transaction<'c, Sqlite>) -> Result<Stored, sqlx::Error> {
+impl Validated<'_> {
+ pub async fn store(self, tx: &mut Transaction<'_, Sqlite>) -> Result<Stored, sqlx::Error> {
let Self {
name,
password_hash,
@@ -67,6 +66,7 @@ impl<'a> Validated<'a> {
}
}
+#[must_use = "dropping a login creation attempt is likely a mistake"]
pub struct Stored {
login: History,
}
diff --git a/src/login/history.rs b/src/login/history.rs
index 8161b0b..d67bcce 100644
--- a/src/login/history.rs
+++ b/src/login/history.rs
@@ -1,6 +1,6 @@
use super::{
- event::{Created, Event},
Id, Login,
+ event::{Created, Event},
};
use crate::event::{Instant, Sequence};
@@ -46,7 +46,7 @@ impl History {
.into()
}
- pub fn events(&self) -> impl Iterator<Item = Event> {
+ pub fn events(&self) -> impl Iterator<Item = Event> + use<> {
[self.created()].into_iter()
}
}
diff --git a/src/login/repo.rs b/src/login/repo.rs
index 1c63a4b..03f2c17 100644
--- a/src/login/repo.rs
+++ b/src/login/repo.rs
@@ -1,10 +1,10 @@
use futures::stream::{StreamExt as _, TryStreamExt as _};
-use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction};
+use sqlx::{SqliteConnection, Transaction, sqlite::Sqlite};
use crate::{
clock::DateTime,
event::{Instant, Sequence},
- login::{password::StoredHash, History, Id, Login},
+ login::{History, Id, Login, password::StoredHash},
name::{self, Name},
};
@@ -12,7 +12,7 @@ pub trait Provider {
fn logins(&mut self) -> Logins;
}
-impl<'c> Provider for Transaction<'c, Sqlite> {
+impl Provider for Transaction<'_, Sqlite> {
fn logins(&mut self) -> Logins {
Logins(self)
}
@@ -20,7 +20,7 @@ impl<'c> Provider for Transaction<'c, Sqlite> {
pub struct Logins<'t>(&'t mut SqliteConnection);
-impl<'c> Logins<'c> {
+impl Logins<'_> {
pub async fn create(
&mut self,
name: &Name,
diff --git a/src/login/routes/mod.rs b/src/login/routes/mod.rs
index bbd0c3f..ade96cb 100644
--- a/src/login/routes/mod.rs
+++ b/src/login/routes/mod.rs
@@ -1,4 +1,4 @@
-use axum::{routing::post, Router};
+use axum::{Router, routing::post};
use crate::app::App;
diff --git a/src/login/snapshot.rs b/src/login/snapshot.rs
index e1eb96c..5c5dce0 100644
--- a/src/login/snapshot.rs
+++ b/src/login/snapshot.rs
@@ -1,6 +1,6 @@
use super::{
- event::{Created, Event},
Id,
+ event::{Created, Event},
};
use crate::name::Name;
diff --git a/src/message/app.rs b/src/message/app.rs
index 7bf68d1..60206f1 100644
--- a/src/message/app.rs
+++ b/src/message/app.rs
@@ -2,12 +2,12 @@ use chrono::TimeDelta;
use itertools::Itertools;
use sqlx::sqlite::SqlitePool;
-use super::{repo::Provider as _, Body, Id, Message};
+use super::{Body, Id, Message, repo::Provider as _};
use crate::{
channel::{self, repo::Provider as _},
clock::DateTime,
db::NotFound as _,
- event::{repo::Provider as _, Broadcaster, Event, Sequence},
+ event::{Broadcaster, Event, Sequence, repo::Provider as _},
login::Login,
name,
};
diff --git a/src/message/event.rs b/src/message/event.rs
index 1cd5847..bd116b1 100644
--- a/src/message/event.rs
+++ b/src/message/event.rs
@@ -1,4 +1,4 @@
-use super::{snapshot::Message, Id};
+use super::{Id, snapshot::Message};
use crate::event::{Instant, Sequenced};
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
diff --git a/src/message/history.rs b/src/message/history.rs
index ed8f5df..1a72c08 100644
--- a/src/message/history.rs
+++ b/src/message/history.rs
@@ -1,8 +1,8 @@
use itertools::Itertools as _;
use super::{
- event::{Deleted, Event, Sent},
Id, Message,
+ event::{Deleted, Event, Sent},
};
use crate::event::{Instant, Sequence};
@@ -58,7 +58,7 @@ impl History {
})
}
- pub fn events(&self) -> impl Iterator<Item = Event> {
+ pub fn events(&self) -> impl Iterator<Item = Event> + use<> {
[self.sent()]
.into_iter()
.merge_by(self.deleted(), Sequence::merge)
diff --git a/src/message/repo.rs b/src/message/repo.rs
index 14f8eaf..8a0a72c 100644
--- a/src/message/repo.rs
+++ b/src/message/repo.rs
@@ -1,6 +1,6 @@
-use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction};
+use sqlx::{SqliteConnection, Transaction, sqlite::Sqlite};
-use super::{snapshot::Message, Body, History, Id};
+use super::{Body, History, Id, snapshot::Message};
use crate::{
channel,
clock::DateTime,
@@ -12,7 +12,7 @@ pub trait Provider {
fn messages(&mut self) -> Messages;
}
-impl<'c> Provider for Transaction<'c, Sqlite> {
+impl Provider for Transaction<'_, Sqlite> {
fn messages(&mut self) -> Messages {
Messages(self)
}
@@ -20,7 +20,7 @@ impl<'c> Provider for Transaction<'c, Sqlite> {
pub struct Messages<'t>(&'t mut SqliteConnection);
-impl<'c> Messages<'c> {
+impl Messages<'_> {
pub async fn create(
&mut self,
channel: &channel::History,
diff --git a/src/message/routes/mod.rs b/src/message/routes/mod.rs
index dfe8628..00b2b1a 100644
--- a/src/message/routes/mod.rs
+++ b/src/message/routes/mod.rs
@@ -1,9 +1,9 @@
-use axum::{routing::delete, Router};
+use axum::{Router, routing::delete};
use crate::app::App;
mod message;
pub fn router() -> Router<App> {
- Router::new().route("/api/messages/:message", delete(message::delete::handler))
+ Router::new().route("/api/messages/{message}", delete(message::delete::handler))
}
diff --git a/src/message/snapshot.rs b/src/message/snapshot.rs
index 53b7176..d924ea1 100644
--- a/src/message/snapshot.rs
+++ b/src/message/snapshot.rs
@@ -1,6 +1,6 @@
use super::{
- event::{Event, Sent},
Body, Id,
+ event::{Event, Sent},
};
use crate::{channel, clock::DateTime, event::Instant, login};
diff --git a/src/name.rs b/src/name.rs
index 9187d33..9861bc1 100644
--- a/src/name.rs
+++ b/src/name.rs
@@ -50,7 +50,7 @@ impl Name {
#[derive(Debug, thiserror::Error)]
pub enum Error {
- #[error("stored canonical form {0:#?} does not match computed canonical form {:#?} for name {:#?}", .1.as_str(), .2.as_str())]
+ #[error("stored canonical form {stored:#?} does not match computed canonical form {computed:#?} for name {expected:#?}", stored=.0, computed=.1.as_str(), expected=.2.as_str())]
CanonicalMismatch(String, ident::String, nfc::String),
}
diff --git a/src/normalize/string.rs b/src/normalize/string.rs
index a0d178c..ee33267 100644
--- a/src/normalize/string.rs
+++ b/src/normalize/string.rs
@@ -1,8 +1,8 @@
use std::{fmt, string::String as StdString};
use sqlx::{
- encode::{Encode, IsNull},
- Database, Decode, Type,
+ encode::{Encode, IsNull}, Database, Decode,
+ Type,
};
pub trait Normalize: Clone + Default {
@@ -84,20 +84,20 @@ where
DB: Database,
StdString: Encode<'q, DB>,
{
- fn encode_by_ref(
- &self,
+ fn encode(
+ self,
buf: &mut <DB as Database>::ArgumentBuffer<'q>,
) -> Result<IsNull, sqlx::error::BoxDynError> {
let Self(value, _) = self;
- value.encode_by_ref(buf)
+ value.encode(buf)
}
- fn encode(
- self,
+ fn encode_by_ref(
+ &self,
buf: &mut <DB as Database>::ArgumentBuffer<'q>,
) -> Result<IsNull, sqlx::error::BoxDynError> {
let Self(value, _) = self;
- value.encode(buf)
+ value.encode_by_ref(buf)
}
fn produces(&self) -> Option<<DB as Database>::TypeInfo> {
diff --git a/src/setup/app.rs b/src/setup/app.rs
index c1f7b69..9553f40 100644
--- a/src/setup/app.rs
+++ b/src/setup/app.rs
@@ -5,11 +5,11 @@ use crate::{
clock::DateTime,
event::Broadcaster,
login::{
- create::{self, Create},
Login, Password,
+ create::{self, Create},
},
name::Name,
- token::{repo::Provider as _, Secret},
+ token::{Secret, repo::Provider as _},
};
pub struct Setup<'a> {
diff --git a/src/setup/repo.rs b/src/setup/repo.rs
index de93f51..ac01496 100644
--- a/src/setup/repo.rs
+++ b/src/setup/repo.rs
@@ -1,10 +1,10 @@
-use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction};
+use sqlx::{SqliteConnection, Transaction, sqlite::Sqlite};
pub trait Provider {
fn setup(&mut self) -> Setup;
}
-impl<'c> Provider for Transaction<'c, Sqlite> {
+impl Provider for Transaction<'_, Sqlite> {
fn setup(&mut self) -> Setup {
Setup(self)
}
@@ -12,7 +12,7 @@ impl<'c> Provider for Transaction<'c, Sqlite> {
pub struct Setup<'t>(&'t mut SqliteConnection);
-impl<'c> Setup<'c> {
+impl Setup<'_> {
pub async fn completed(&mut self) -> Result<bool, sqlx::Error> {
let completed = sqlx::query_scalar!(
r#"
diff --git a/src/setup/routes/mod.rs b/src/setup/routes/mod.rs
index 6054983..977a790 100644
--- a/src/setup/routes/mod.rs
+++ b/src/setup/routes/mod.rs
@@ -1,4 +1,4 @@
-use axum::{routing::post, Router};
+use axum::{Router, routing::post};
use crate::app::App;
diff --git a/src/test/fixtures/cookie.rs b/src/test/fixtures/cookie.rs
index 58777c8..fcb379f 100644
--- a/src/test/fixtures/cookie.rs
+++ b/src/test/fixtures/cookie.rs
@@ -5,7 +5,7 @@ use crate::{
clock::RequestedAt,
login::Password,
name::Name,
- token::{extract::IdentityCookie, Secret},
+ token::{Secret, extract::IdentityCookie},
};
pub fn not_logged_in() -> IdentityCookie {
diff --git a/src/test/fixtures/event.rs b/src/test/fixtures/event.rs
index de02d4d..e11f6ee 100644
--- a/src/test/fixtures/event.rs
+++ b/src/test/fixtures/event.rs
@@ -26,8 +26,8 @@ pub fn login(event: Event) -> Ready<Option<login::Event>> {
pub mod channel {
use std::future::{self, Ready};
- use crate::channel::event;
pub use crate::channel::Event;
+ use crate::channel::event;
pub fn created(event: Event) -> Ready<Option<event::Created>> {
future::ready(match event {
@@ -47,8 +47,8 @@ pub mod channel {
pub mod message {
use std::future::{self, Ready};
- use crate::message::event;
pub use crate::message::Event;
+ use crate::message::event;
pub fn sent(event: Event) -> Ready<Option<event::Sent>> {
future::ready(match event {
@@ -68,8 +68,8 @@ pub mod message {
pub mod login {
use std::future::{self, Ready};
- use crate::login::event;
pub use crate::login::Event;
+ use crate::login::event;
pub fn created(event: Event) -> Ready<Option<event::Created>> {
future::ready(match event {
diff --git a/src/test/fixtures/future.rs b/src/test/fixtures/future.rs
index 2f810a3..c0fa528 100644
--- a/src/test/fixtures/future.rs
+++ b/src/test/fixtures/future.rs
@@ -52,7 +52,7 @@ pub trait Expect: Sized {
Self: Future<Output = Option<T>>;
}
-impl<'a, St> Expect for stream::Next<'a, St> {
+impl<St> Expect for stream::Next<'_, St> {
fn expect_ready(self, message: &str) -> Ready<Self> {
Ready {
future: self,
@@ -131,7 +131,7 @@ pub struct Ready<'m, F> {
message: &'m str,
}
-impl<'m, F> Future for Ready<'m, F>
+impl<F> Future for Ready<'_, F>
where
F: Future + std::fmt::Debug,
{
@@ -155,7 +155,7 @@ pub struct Wait<'m, F> {
message: &'m str,
}
-impl<'m, F> Future for Wait<'m, F>
+impl<F> Future for Wait<'_, F>
where
F: Future + std::fmt::Debug,
{
@@ -179,7 +179,7 @@ pub struct Some<'m, F> {
message: &'m str,
}
-impl<'m, F, T> Future for Some<'m, F>
+impl<F, T> Future for Some<'_, F>
where
F: Future<Output = Option<T>> + std::fmt::Debug,
{
@@ -203,7 +203,7 @@ pub struct None<'m, F> {
message: &'m str,
}
-impl<'m, F, T> Future for None<'m, F>
+impl<F, T> Future for None<'_, F>
where
F: Future<Output = Option<T>> + std::fmt::Debug,
{
diff --git a/src/token/app.rs b/src/token/app.rs
index 5c0aeb0..3f054ff 100644
--- a/src/token/app.rs
+++ b/src/token/app.rs
@@ -1,19 +1,18 @@
use chrono::TimeDelta;
use futures::{
- future,
+ Stream, future,
stream::{self, StreamExt as _},
- Stream,
};
use sqlx::sqlite::SqlitePool;
use super::{
- repo::{self, auth::Provider as _, Provider as _},
Broadcaster, Event as TokenEvent, Id, Secret,
+ repo::{self, Provider as _, auth::Provider as _},
};
use crate::{
clock::DateTime,
db::NotFound as _,
- login::{repo::Provider as _, Login, Password},
+ login::{Login, Password, repo::Provider as _},
name::{self, Name},
};
@@ -120,12 +119,13 @@ impl<'a> Tokens<'a> {
Ok((token, login))
}
- pub async fn limit_stream<E>(
+ pub async fn limit_stream<S, E>(
&self,
token: Id,
- events: impl Stream<Item = E> + std::fmt::Debug,
- ) -> Result<impl Stream<Item = E> + std::fmt::Debug, ValidateError>
+ events: S,
+ ) -> Result<impl Stream<Item = E> + std::fmt::Debug + use<S, E>, ValidateError>
where
+ S: Stream<Item = E> + std::fmt::Debug,
E: std::fmt::Debug,
{
// Subscribe, first.
diff --git a/src/token/extract/cookie.rs b/src/token/extract/cookie.rs
index af5787d..a8e15d4 100644
--- a/src/token/extract/cookie.rs
+++ b/src/token/extract/cookie.rs
@@ -25,7 +25,7 @@ impl fmt::Debug for Identity {
}
impl Identity {
- const COOKIE_NAME: &str = "identity";
+ const COOKIE_NAME: &'static str = "identity";
// Creates a new, unpopulated identity token store.
#[cfg(test)]
@@ -71,7 +71,6 @@ impl Identity {
}
}
-#[async_trait::async_trait]
impl<S> FromRequestParts<S> for Identity
where
S: Send + Sync,
diff --git a/src/token/extract/identity.rs b/src/token/extract/identity.rs
index a69f509..acfd7ae 100644
--- a/src/token/extract/identity.rs
+++ b/src/token/extract/identity.rs
@@ -1,5 +1,5 @@
use axum::{
- extract::{FromRequestParts, State},
+ extract::{FromRequestParts, OptionalFromRequestParts, State},
http::request::Parts,
response::{IntoResponse, Response},
};
@@ -20,7 +20,6 @@ pub struct Identity {
pub login: Login,
}
-#[async_trait::async_trait]
impl FromRequestParts<App> for Identity {
type Rejection = LoginError<Internal>;
@@ -39,6 +38,21 @@ impl FromRequestParts<App> for Identity {
}
}
+impl OptionalFromRequestParts<App> for Identity {
+ type Rejection = LoginError<Internal>;
+
+ async fn from_request_parts(
+ parts: &mut Parts,
+ state: &App,
+ ) -> Result<Option<Self>, Self::Rejection> {
+ match <Self as FromRequestParts<App>>::from_request_parts(parts, state).await {
+ Ok(identity) => Ok(Some(identity)),
+ Err(LoginError::Unauthorized) => Ok(None),
+ Err(other) => Err(other),
+ }
+ }
+}
+
pub enum LoginError<E> {
Failure(E),
Unauthorized,
diff --git a/src/token/repo/auth.rs b/src/token/repo/auth.rs
index b51db8c..0deed10 100644
--- a/src/token/repo/auth.rs
+++ b/src/token/repo/auth.rs
@@ -1,10 +1,10 @@
-use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction};
+use sqlx::{SqliteConnection, Transaction, sqlite::Sqlite};
use crate::{
clock::DateTime,
db::NotFound,
event::{Instant, Sequence},
- login::{self, password::StoredHash, History, Login},
+ login::{self, History, Login, password::StoredHash},
name::{self, Name},
};
@@ -12,7 +12,7 @@ pub trait Provider {
fn auth(&mut self) -> Auth;
}
-impl<'c> Provider for Transaction<'c, Sqlite> {
+impl Provider for Transaction<'_, Sqlite> {
fn auth(&mut self) -> Auth {
Auth(self)
}
@@ -20,7 +20,7 @@ impl<'c> Provider for Transaction<'c, Sqlite> {
pub struct Auth<'t>(&'t mut SqliteConnection);
-impl<'t> Auth<'t> {
+impl Auth<'_> {
pub async fn for_name(&mut self, name: &Name) -> Result<(History, StoredHash), LoadError> {
let name = name.canonical();
let row = sqlx::query!(
diff --git a/src/token/repo/token.rs b/src/token/repo/token.rs
index 33b89d5..ff42fad 100644
--- a/src/token/repo/token.rs
+++ b/src/token/repo/token.rs
@@ -1,4 +1,4 @@
-use sqlx::{sqlite::Sqlite, SqliteConnection, Transaction};
+use sqlx::{SqliteConnection, Transaction, sqlite::Sqlite};
use uuid::Uuid;
use crate::{
@@ -14,7 +14,7 @@ pub trait Provider {
fn tokens(&mut self) -> Tokens;
}
-impl<'c> Provider for Transaction<'c, Sqlite> {
+impl Provider for Transaction<'_, Sqlite> {
fn tokens(&mut self) -> Tokens {
Tokens(self)
}
@@ -22,7 +22,7 @@ impl<'c> Provider for Transaction<'c, Sqlite> {
pub struct Tokens<'t>(&'t mut SqliteConnection);
-impl<'c> Tokens<'c> {
+impl Tokens<'_> {
// Issue a new token for an existing login. The issued_at timestamp will
// be used to control expiry, until the token is actually used.
pub async fn issue(
diff --git a/src/ui/assets.rs b/src/ui/assets.rs
index 6a7563a..142cdf9 100644
--- a/src/ui/assets.rs
+++ b/src/ui/assets.rs
@@ -1,6 +1,6 @@
use ::mime::{FromStrError, Mime};
use axum::{
- http::{header, StatusCode},
+ http::{StatusCode, header},
response::{IntoResponse, Response},
};
use rust_embed::EmbeddedFile;
diff --git a/src/ui/routes/mod.rs b/src/ui/routes/mod.rs
index 48b3f90..80dc1e5 100644
--- a/src/ui/routes/mod.rs
+++ b/src/ui/routes/mod.rs
@@ -1,4 +1,4 @@
-use axum::{middleware, routing::get, Router};
+use axum::{Router, middleware, routing::get};
use crate::{app::App, ui::middleware::setup_required};
@@ -13,14 +13,14 @@ mod setup;
pub fn router(app: &App) -> Router<App> {
[
Router::new()
- .route("/*path", get(path::get::handler))
+ .route("/{*path}", get(path::get::handler))
.route("/setup", get(setup::get::handler)),
Router::new()
.route("/", get(get::handler))
.route("/me", get(me::get::handler))
.route("/login", get(login::get::handler))
- .route("/ch/:channel", get(ch::channel::get::handler))
- .route("/invite/:invite", get(invite::invite::get::handler))
+ .route("/ch/{channel}", get(ch::channel::get::handler))
+ .route("/invite/{invite}", get(invite::invite::get::handler))
.route_layer(middleware::from_fn_with_state(app.clone(), setup_required)),
]
.into_iter()