forked from lavina/lavina
1
0
Fork 0

clean up ByteVec type aliases

This commit is contained in:
Nikita Vilunov 2023-04-14 00:38:26 +02:00
parent 55b69f4c8a
commit 4057b4a910
10 changed files with 140 additions and 137 deletions

View File

@ -27,9 +27,10 @@ use crate::{
/// Opaque player identifier. Cannot contain spaces, must be shorter than 32. /// Opaque player identifier. Cannot contain spaces, must be shorter than 32.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)] #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
pub struct PlayerId(Box<str>); pub struct PlayerId(Str);
impl PlayerId { impl PlayerId {
pub fn from_bytes(bytes: Box<str>) -> Result<PlayerId> { pub fn from(str: impl Into<Str>) -> Result<PlayerId> {
let bytes = str.into();
if bytes.len() > 32 { if bytes.len() > 32 {
return Err(fail("Nickname cannot be longer than 32 symbols")); return Err(fail("Nickname cannot be longer than 32 symbols"));
} }
@ -38,10 +39,10 @@ impl PlayerId {
} }
Ok(PlayerId(bytes)) Ok(PlayerId(bytes))
} }
pub fn as_bytes(&self) -> &Box<str> { pub fn as_inner(&self) -> &Str {
&self.0 &self.0
} }
pub fn into_bytes(self) -> Box<str> { pub fn into_inner(self) -> Str {
self.0 self.0
} }
} }
@ -55,7 +56,7 @@ pub struct PlayerConnection {
player_handle: PlayerHandle, player_handle: PlayerHandle,
} }
impl PlayerConnection { impl PlayerConnection {
pub async fn send_message(&mut self, room_id: RoomId, body: Box<str>) -> Result<()> { pub async fn send_message(&mut self, room_id: RoomId, body: Str) -> Result<()> {
self.player_handle self.player_handle
.send_message(room_id, self.connection_id.clone(), body) .send_message(room_id, self.connection_id.clone(), body)
.await .await
@ -67,7 +68,7 @@ impl PlayerConnection {
.await .await
} }
pub async fn change_topic(&mut self, room_id: RoomId, new_topic: ByteVec) -> Result<()> { pub async fn change_topic(&mut self, room_id: RoomId, new_topic: Str) -> Result<()> {
let (promise, deferred) = oneshot(); let (promise, deferred) = oneshot();
let cmd = Cmd::ChangeTopic { let cmd = Cmd::ChangeTopic {
room_id, room_id,
@ -129,7 +130,7 @@ impl PlayerHandle {
&self, &self,
room_id: RoomId, room_id: RoomId,
connection_id: ConnectionId, connection_id: ConnectionId,
body: Box<str>, body: Str,
) -> Result<()> { ) -> Result<()> {
let (promise, deferred) = oneshot(); let (promise, deferred) = oneshot();
let cmd = Cmd::SendMessage { let cmd = Cmd::SendMessage {
@ -186,12 +187,12 @@ pub enum Cmd {
}, },
SendMessage { SendMessage {
room_id: RoomId, room_id: RoomId,
body: Box<str>, body: Str,
promise: Promise<()>, promise: Promise<()>,
}, },
ChangeTopic { ChangeTopic {
room_id: RoomId, room_id: RoomId,
new_topic: ByteVec, new_topic: Str,
promise: Promise<()>, promise: Promise<()>,
}, },
} }
@ -206,12 +207,12 @@ pub enum JoinResult {
pub enum Updates { pub enum Updates {
RoomTopicChanged { RoomTopicChanged {
room_id: RoomId, room_id: RoomId,
new_topic: ByteVec, new_topic: Str,
}, },
NewMessage { NewMessage {
room_id: RoomId, room_id: RoomId,
author_id: PlayerId, author_id: PlayerId,
body: Box<str>, body: Str,
}, },
RoomJoined { RoomJoined {
room_id: RoomId, room_id: RoomId,
@ -288,7 +289,7 @@ impl Player {
player_id, player_id,
connections: AnonTable::new(), connections: AnonTable::new(),
my_rooms: HashMap::new(), my_rooms: HashMap::new(),
banned_from: HashSet::from([RoomId::from_bytes("empty".into()).unwrap()]), banned_from: HashSet::from([RoomId::from("empty").unwrap()]),
rx, rx,
handle, handle,
rooms, rooms,

View File

@ -16,9 +16,10 @@ use crate::{
/// Opaque room id /// Opaque room id
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)] #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
pub struct RoomId(ByteVec); pub struct RoomId(Str);
impl RoomId { impl RoomId {
pub fn from_bytes(bytes: ByteVec) -> Result<RoomId> { pub fn from(str: impl Into<Str>) -> Result<RoomId> {
let bytes = str.into();
if bytes.len() > 32 { if bytes.len() > 32 {
return Err(anyhow::Error::msg( return Err(anyhow::Error::msg(
"Room name cannot be longer than 32 symbols", "Room name cannot be longer than 32 symbols",
@ -29,10 +30,10 @@ impl RoomId {
} }
Ok(RoomId(bytes)) Ok(RoomId(bytes))
} }
pub fn as_bytes(&self) -> &ByteVec { pub fn as_inner(&self) -> &Str {
&self.0 &self.0
} }
pub fn into_bytes(self) -> ByteVec { pub fn into_inner(self) -> Str {
self.0 self.0
} }
} }
@ -112,7 +113,7 @@ impl RoomHandle {
lock.broadcast_update(update, player_id).await; lock.broadcast_update(update, player_id).await;
} }
pub async fn send_message(&self, player_id: PlayerId, body: Box<str>) { pub async fn send_message(&self, player_id: PlayerId, body: Str) {
let lock = self.0.read().await; let lock = self.0.read().await;
lock.send_message(player_id, body).await; lock.send_message(player_id, body).await;
} }
@ -130,7 +131,7 @@ impl RoomHandle {
} }
} }
pub async fn set_topic(&mut self, changer_id: PlayerId, new_topic: ByteVec) { pub async fn set_topic(&mut self, changer_id: PlayerId, new_topic: Str) {
let mut lock = self.0.write().await; let mut lock = self.0.write().await;
lock.topic = new_topic.clone(); lock.topic = new_topic.clone();
let update = Updates::RoomTopicChanged { let update = Updates::RoomTopicChanged {
@ -144,7 +145,7 @@ impl RoomHandle {
struct Room { struct Room {
room_id: RoomId, room_id: RoomId,
subscriptions: HashMap<PlayerId, PlayerHandle>, subscriptions: HashMap<PlayerId, PlayerHandle>,
topic: ByteVec, topic: Str,
} }
impl Room { impl Room {
async fn add_subscriber(&mut self, player_id: PlayerId, player_handle: PlayerHandle) { async fn add_subscriber(&mut self, player_id: PlayerId, player_handle: PlayerHandle) {
@ -157,7 +158,7 @@ impl Room {
self.broadcast_update(update, &player_id).await; self.broadcast_update(update, &player_id).await;
} }
async fn send_message(&self, author_id: PlayerId, body: Box<str>) { async fn send_message(&self, author_id: PlayerId, body: Str) {
tracing::info!("Adding a message to room"); tracing::info!("Adding a message to room");
let update = Updates::NewMessage { let update = Updates::NewMessage {
room_id: self.room_id.clone(), room_id: self.room_id.clone(),
@ -182,5 +183,5 @@ impl Room {
pub struct RoomInfo { pub struct RoomInfo {
pub id: RoomId, pub id: RoomId,
pub members: Vec<PlayerId>, pub members: Vec<PlayerId>,
pub topic: ByteVec, pub topic: Str,
} }

View File

@ -10,8 +10,7 @@ pub mod log {
} }
pub type Result<T> = std::result::Result<T, anyhow::Error>; pub type Result<T> = std::result::Result<T, anyhow::Error>;
pub type Str = std::sync::Arc<str>;
pub type ByteVec = Box<str>;
pub fn fail(msg: &str) -> anyhow::Error { pub fn fail(msg: &str) -> anyhow::Error {
anyhow::Error::msg(msg.to_owned()) anyhow::Error::msg(msg.to_owned())

View File

@ -23,19 +23,19 @@ mod test;
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
pub struct ServerConfig { pub struct ServerConfig {
pub listen_on: SocketAddr, pub listen_on: SocketAddr,
pub server_name: Box<str>, pub server_name: Str,
} }
#[derive(Debug)] #[derive(Debug)]
struct RegisteredUser { struct RegisteredUser {
nickname: Box<str>, nickname: Str,
/** /**
* Username is mostly unused in modern IRC. * Username is mostly unused in modern IRC.
* *
* [https://stackoverflow.com/questions/31666247/what-is-the-difference-between-the-nick-username-and-real-name-in-irc-and-wha] * [https://stackoverflow.com/questions/31666247/what-is-the-difference-between-the-nick-username-and-real-name-in-irc-and-wha]
*/ */
username: Box<str>, username: Str,
realname: Box<str>, realname: Str,
} }
async fn handle_socket( async fn handle_socket(
@ -83,8 +83,8 @@ async fn handle_registration<'a>(
) -> Result<RegisteredUser> { ) -> Result<RegisteredUser> {
let mut buffer = vec![]; let mut buffer = vec![];
let mut future_nickname: Option<Box<str>> = None; let mut future_nickname: Option<Str> = None;
let mut future_username: Option<(Box<str>, Box<str>)> = None; let mut future_username: Option<(Str, Str)> = None;
loop { loop {
let res = reader.read_until(b'\n', &mut buffer).await; let res = reader.read_until(b'\n', &mut buffer).await;
@ -153,7 +153,7 @@ async fn handle_registered_socket<'a>(
let mut buffer = vec![]; let mut buffer = vec![];
log::info!("Handling registered user: {user:?}"); log::info!("Handling registered user: {user:?}");
let player_id = PlayerId::from_bytes(user.nickname.clone())?; let player_id = PlayerId::from(user.nickname.clone())?;
let mut connection = players.connect_to_player(player_id.clone()).await; let mut connection = players.connect_to_player(player_id.clone()).await;
ServerMessage { ServerMessage {
@ -213,7 +213,7 @@ async fn handle_registered_socket<'a>(
produce_on_join_cmd_messages( produce_on_join_cmd_messages(
&config, &config,
&user, &user,
&Chan::Global(room.id.as_bytes().clone()), &Chan::Global(room.id.as_inner().clone()),
room, room,
writer, writer,
) )
@ -280,7 +280,7 @@ async fn handle_update(
if player_id == &new_member_id { if player_id == &new_member_id {
if let Some(room) = rooms.get_room(&room_id) { if let Some(room) = rooms.get_room(&room_id) {
let room_info = room.get_room_info().await; let room_info = room.get_room_info().await;
let chan = Chan::Global(room_id.as_bytes().clone()); let chan = Chan::Global(room_id.as_inner().clone());
produce_on_join_cmd_messages(&config, &user, &chan, &room_info, writer).await?; produce_on_join_cmd_messages(&config, &user, &chan, &room_info, writer).await?;
writer.flush().await?; writer.flush().await?;
} else { } else {
@ -289,8 +289,8 @@ async fn handle_update(
} else { } else {
ServerMessage { ServerMessage {
tags: vec![], tags: vec![],
sender: Some(new_member_id.as_bytes().clone()), sender: Some(new_member_id.as_inner().clone()),
body: ServerMessageBody::Join(Chan::Global(room_id.as_bytes().clone())), body: ServerMessageBody::Join(Chan::Global(room_id.as_inner().clone())),
} }
.write_async(writer) .write_async(writer)
.await?; .await?;
@ -303,8 +303,8 @@ async fn handle_update(
} => { } => {
ServerMessage { ServerMessage {
tags: vec![], tags: vec![],
sender: Some(former_member_id.as_bytes().clone()), sender: Some(former_member_id.as_inner().clone()),
body: ServerMessageBody::Part(Chan::Global(room_id.as_bytes().clone())), body: ServerMessageBody::Part(Chan::Global(room_id.as_inner().clone())),
} }
.write_async(writer) .write_async(writer)
.await?; .await?;
@ -317,9 +317,9 @@ async fn handle_update(
} => { } => {
ServerMessage { ServerMessage {
tags: vec![], tags: vec![],
sender: Some(author_id.as_bytes().clone()), sender: Some(author_id.as_inner().clone()),
body: ServerMessageBody::PrivateMessage { body: ServerMessageBody::PrivateMessage {
target: Recipient::Chan(Chan::Global(room_id.as_bytes().clone())), target: Recipient::Chan(Chan::Global(room_id.as_inner().clone())),
body: body.clone(), body: body.clone(),
}, },
} }
@ -333,7 +333,7 @@ async fn handle_update(
sender: Some(config.server_name.clone()), sender: Some(config.server_name.clone()),
body: ServerMessageBody::N332Topic { body: ServerMessageBody::N332Topic {
client: user.nickname.clone(), client: user.nickname.clone(),
chat: Chan::Global(room_id.as_bytes().clone()), chat: Chan::Global(room_id.as_inner().clone()),
topic: new_topic, topic: new_topic,
}, },
} }
@ -345,8 +345,8 @@ async fn handle_update(
// TODO think about the case when the user was banned, but was not in the room - no need to send PART in this case // TODO think about the case when the user was banned, but was not in the room - no need to send PART in this case
ServerMessage { ServerMessage {
tags: vec![], tags: vec![],
sender: Some(player_id.as_bytes().clone()), sender: Some(player_id.as_inner().clone()),
body: ServerMessageBody::Part(Chan::Global(room_id.as_bytes().clone())), body: ServerMessageBody::Part(Chan::Global(room_id.as_inner().clone())),
} }
.write_async(writer) .write_async(writer)
.await?; .await?;
@ -393,7 +393,7 @@ async fn handle_incoming_message(
} }
ClientMessage::PrivateMessage { recipient, body } => match recipient { ClientMessage::PrivateMessage { recipient, body } => match recipient {
Recipient::Chan(Chan::Global(chan)) => { Recipient::Chan(Chan::Global(chan)) => {
let room_id = RoomId::from_bytes(chan)?; let room_id = RoomId::from(chan)?;
user_handle.send_message(room_id, body).await?; user_handle.send_message(room_id, body).await?;
}, },
_ => log::warn!("Unsupported target type"), _ => log::warn!("Unsupported target type"),
@ -401,7 +401,7 @@ async fn handle_incoming_message(
ClientMessage::Topic { chan, topic } => { ClientMessage::Topic { chan, topic } => {
match chan { match chan {
Chan::Global(chan) => { Chan::Global(chan) => {
let room_id = RoomId::from_bytes(chan)?; let room_id = RoomId::from(chan)?;
user_handle user_handle
.change_topic(room_id.clone(), topic.clone()) .change_topic(room_id.clone(), topic.clone())
.await?; .await?;
@ -410,7 +410,7 @@ async fn handle_incoming_message(
sender: Some(config.server_name.clone()), sender: Some(config.server_name.clone()),
body: ServerMessageBody::N332Topic { body: ServerMessageBody::N332Topic {
client: user.nickname.clone(), client: user.nickname.clone(),
chat: Chan::Global(room_id.as_bytes().clone()), chat: Chan::Global(room_id.as_inner().clone()),
topic, topic,
}, },
} }
@ -447,14 +447,14 @@ async fn handle_incoming_message(
writer.flush().await?; writer.flush().await?;
} }
Recipient::Chan(Chan::Global(chan)) => { Recipient::Chan(Chan::Global(chan)) => {
let room = rooms.get_room(&RoomId::from_bytes(chan.clone())?); let room = rooms.get_room(&RoomId::from(chan.clone())?);
if let Some(room) = room { if let Some(room) = room {
let room_info = room.get_room_info().await; let room_info = room.get_room_info().await;
for member in room_info.members { for member in room_info.members {
ServerMessage { ServerMessage {
tags: vec![], tags: vec![],
sender: Some(config.server_name.clone()), sender: Some(config.server_name.clone()),
body: user_to_who_msg(config, user, member.as_bytes()), body: user_to_who_msg(config, user, member.as_inner()),
} }
.write_async(writer) .write_async(writer)
.await?; .await?;
@ -519,7 +519,7 @@ async fn handle_incoming_message(
fn user_to_who_msg( fn user_to_who_msg(
config: &ServerConfig, config: &ServerConfig,
requestor: &RegisteredUser, requestor: &RegisteredUser,
target_user_nickname: &ByteVec, target_user_nickname: &Str,
) -> ServerMessageBody { ) -> ServerMessageBody {
// Username is equal to nickname // Username is equal to nickname
let username = format!("~{target_user_nickname}").into(); let username = format!("~{target_user_nickname}").into();
@ -549,7 +549,7 @@ async fn handle_join(
) -> Result<()> { ) -> Result<()> {
match chan { match chan {
Chan::Global(chan_name) => { Chan::Global(chan_name) => {
let room_id = RoomId::from_bytes(chan_name.clone())?; let room_id = RoomId::from(chan_name.clone())?;
if let JoinResult::Success(room_info) = user_handle.join_room(room_id).await? { if let JoinResult::Success(room_info) = user_handle.join_room(room_id).await? {
produce_on_join_cmd_messages(&config, &user, chan, &room_info, writer).await?; produce_on_join_cmd_messages(&config, &user, chan, &room_info, writer).await?;
} else { } else {
@ -580,7 +580,7 @@ async fn handle_part(
writer: &mut (impl AsyncWrite + Unpin), writer: &mut (impl AsyncWrite + Unpin),
) -> Result<()> { ) -> Result<()> {
if let Chan::Global(chan_name) = chan { if let Chan::Global(chan_name) = chan {
let room_id = RoomId::from_bytes(chan_name.clone())?; let room_id = RoomId::from(chan_name.clone())?;
user_handle.leave_room(room_id).await?; user_handle.leave_room(room_id).await?;
ServerMessage { ServerMessage {
tags: vec![], tags: vec![],
@ -622,13 +622,13 @@ async fn produce_on_join_cmd_messages(
.write_async(writer) .write_async(writer)
.await?; .await?;
let mut members: String = if let Some(head) = room_info.members.first() { let mut members: String = if let Some(head) = room_info.members.first() {
head.as_bytes().clone() head.as_inner().clone()
} else { } else {
user.nickname.clone() user.nickname.clone()
}.into(); }.as_ref().into();
for i in &room_info.members[1..] { for i in &room_info.members[1..] {
members.push(' '); members.push(' ');
members.push_str(i.as_bytes()); members.push_str(i.as_inner());
} }
ServerMessage { ServerMessage {
tags: vec![], tags: vec![],

View File

@ -253,11 +253,13 @@ async fn socket_auth(
let _ = xmpp::sasl::Auth::parse(xml_reader, reader_buf).await?; let _ = xmpp::sasl::Auth::parse(xml_reader, reader_buf).await?;
xmpp::sasl::Success.write_xml(xml_writer).await?; xmpp::sasl::Success.write_xml(xml_writer).await?;
let name: Str = "darova".into();
Ok(Authenticated { Ok(Authenticated {
player_id: PlayerId::from_bytes("darova".into())?, player_id: PlayerId::from("darova")?,
xmpp_name: Name("darova".into()), xmpp_name: Name(name.clone()),
xmpp_resource: Resource("darova".to_owned()), xmpp_resource: Resource(name.clone()),
xmpp_muc_name: Resource("darova".to_owned()), xmpp_muc_name: Resource(name),
}) })
} }
@ -337,9 +339,9 @@ async fn socket_final(
resource: Some(authenticated.xmpp_resource.clone()), resource: Some(authenticated.xmpp_resource.clone()),
}), }),
from: Some(Jid { from: Some(Jid {
name: Some(Name(room_id.into_bytes().into())), name: Some(Name(room_id.into_inner().into())),
server: Server("rooms.localhost".into()), server: Server("rooms.localhost".into()),
resource: Some(Resource(author_id.into_bytes().into())), resource: Some(Resource(author_id.into_inner().into())),
}), }),
id: None, id: None,
r#type: xmpp::client::MessageType::Groupchat, r#type: xmpp::client::MessageType::Groupchat,
@ -391,10 +393,10 @@ async fn handle_packet(
resource: _, resource: _,
}) = m.to }) = m.to
{ {
if server.0 == "rooms.localhost" && m.r#type == MessageType::Groupchat { if server.0.as_ref() == "rooms.localhost" && m.r#type == MessageType::Groupchat {
user_handle user_handle
.send_message( .send_message(
RoomId::from_bytes(name.0.clone().into())?, RoomId::from(name.0.clone())?,
m.body.clone().into(), m.body.clone().into(),
) )
.await?; .await?;
@ -446,7 +448,7 @@ async fn handle_packet(
}) = p.to }) = p.to
{ {
let a = user_handle let a = user_handle
.join_room(RoomId::from_bytes(name.0.clone())?) .join_room(RoomId::from(name.0.clone())?)
.await?; .await?;
Presence::<()> { Presence::<()> {
to: Some(Jid { to: Some(Jid {
@ -484,8 +486,8 @@ async fn handle_iq(output: &mut Vec<Event<'static>>, iq: Iq<IqClientBody>, rooms
r#type: xmpp::client::IqType::Result, r#type: xmpp::client::IqType::Result,
body: BindResponse(Jid { body: BindResponse(Jid {
name: Some(Name("darova".into())), name: Some(Name("darova".into())),
server: Server("localhost".to_string()), server: Server("localhost".into()),
resource: Some(Resource("kek".to_string())), resource: Some(Resource("kek".into())),
}), }),
}; };
req.serialize(output); req.serialize(output);
@ -592,7 +594,7 @@ async fn disco_items(to: Option<&str>, req: &ItemQuery, rooms: &RoomRegistry) ->
vec![Item { vec![Item {
jid: Jid { jid: Jid {
name: None, name: None,
server: Server("rooms.localhost".to_string()), server: Server("rooms.localhost".into()),
resource: None, resource: None,
}, },
name: None, name: None,
@ -605,8 +607,8 @@ async fn disco_items(to: Option<&str>, req: &ItemQuery, rooms: &RoomRegistry) ->
.into_iter() .into_iter()
.map(|room_info| Item { .map(|room_info| Item {
jid: Jid { jid: Jid {
name: Some(Name(room_info.id.into_bytes())), name: Some(Name(room_info.id.into_inner())),
server: Server("rooms.localhost".to_string()), server: Server("rooms.localhost".into()),
resource: None, resource: None,
}, },
name: None, name: None,

View File

@ -9,20 +9,20 @@ pub enum ClientMessage {
}, },
/// PING <token> /// PING <token>
Ping { Ping {
token: Box<str>, token: Str,
}, },
/// PONG <token> /// PONG <token>
Pong { Pong {
token: Box<str>, token: Str,
}, },
/// NICK <nickname> /// NICK <nickname>
Nick { Nick {
nickname: Box<str>, nickname: Str,
}, },
/// USER <username> 0 * :<realname> /// USER <username> 0 * :<realname>
User { User {
username: Box<str>, username: Str,
realname: Box<str>, realname: Str,
}, },
/// JOIN <chan> /// JOIN <chan>
Join(Chan), Join(Chan),
@ -37,20 +37,20 @@ pub enum ClientMessage {
/// TOPIC <chan> :<topic> /// TOPIC <chan> :<topic>
Topic { Topic {
chan: Chan, chan: Chan,
topic: Box<str>, topic: Str,
}, },
Part { Part {
chan: Chan, chan: Chan,
message: Box<str>, message: Str,
}, },
/// PRIVMSG <target> :<msg> /// PRIVMSG <target> :<msg>
PrivateMessage { PrivateMessage {
recipient: Recipient, recipient: Recipient,
body: Box<str>, body: Str,
}, },
/// QUIT :<reason> /// QUIT :<reason>
Quit { Quit {
reason: Box<str>, reason: Str,
}, },
} }

View File

@ -3,6 +3,7 @@ pub mod client;
pub mod server; pub mod server;
use std::io::Result; use std::io::Result;
use crate::prelude::Str;
use nom::{ use nom::{
branch::alt, branch::alt,
@ -11,12 +12,10 @@ use nom::{
}; };
use tokio::io::{AsyncWrite, AsyncWriteExt}; use tokio::io::{AsyncWrite, AsyncWriteExt};
type ByteVec = Box<str>;
/// Single message tag value. /// Single message tag value.
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct Tag { pub struct Tag {
key: ByteVec, key: Str,
value: Option<u8>, value: Option<u8>,
} }
@ -31,9 +30,9 @@ fn token(input: &str) -> IResult<&str, &str> {
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum Chan { pub enum Chan {
/// #<name> — network-global channel, available from any server in the network. /// #<name> — network-global channel, available from any server in the network.
Global(Box<str>), Global(Str),
/// &<name> — server-local channel, available only to connections to the same server. Rarely used in practice. /// &<name> — server-local channel, available only to connections to the same server. Rarely used in practice.
Local(Box<str>), Local(Str),
} }
impl Chan { impl Chan {
pub async fn write_async(&self, writer: &mut (impl AsyncWrite + Unpin)) -> Result<()> { pub async fn write_async(&self, writer: &mut (impl AsyncWrite + Unpin)) -> Result<()> {
@ -69,7 +68,7 @@ fn chan(input: &str) -> IResult<&str, Chan> {
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum Recipient { pub enum Recipient {
Nick(ByteVec), Nick(Str),
Chan(Chan), Chan(Chan),
} }
impl Recipient { impl Recipient {

View File

@ -9,7 +9,7 @@ pub struct ServerMessage {
/// Optional tags section, prefixed with `@` /// Optional tags section, prefixed with `@`
pub tags: Vec<Tag>, pub tags: Vec<Tag>,
/// Optional server name, prefixed with `:`. /// Optional server name, prefixed with `:`.
pub sender: Option<ByteVec>, pub sender: Option<Str>,
pub body: ServerMessageBody, pub body: ServerMessageBody,
} }
@ -44,93 +44,93 @@ pub fn server_message(input: &str) -> IResult<&str, ServerMessage> {
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum ServerMessageBody { pub enum ServerMessageBody {
Notice { Notice {
first_target: ByteVec, first_target: Str,
rest_targets: Vec<ByteVec>, rest_targets: Vec<Str>,
text: ByteVec, text: Str,
}, },
Ping { Ping {
token: ByteVec, token: Str,
}, },
Pong { Pong {
from: ByteVec, from: Str,
token: ByteVec, token: Str,
}, },
PrivateMessage { PrivateMessage {
target: Recipient, target: Recipient,
body: ByteVec, body: Str,
}, },
Join(Chan), Join(Chan),
Part(Chan), Part(Chan),
Error { Error {
reason: ByteVec, reason: Str,
}, },
N001Welcome { N001Welcome {
client: ByteVec, client: Str,
text: ByteVec, text: Str,
}, },
N002YourHost { N002YourHost {
client: ByteVec, client: Str,
text: ByteVec, text: Str,
}, },
N003Created { N003Created {
client: ByteVec, client: Str,
text: ByteVec, text: Str,
}, },
N004MyInfo { N004MyInfo {
client: ByteVec, client: Str,
hostname: ByteVec, hostname: Str,
softname: ByteVec, softname: Str,
// TODO user modes, channel modes, channel modes with a parameter // TODO user modes, channel modes, channel modes with a parameter
}, },
N005ISupport { N005ISupport {
client: ByteVec, client: Str,
params: ByteVec, // TODO make this a datatype params: Str, // TODO make this a datatype
}, },
/// Reply to a client's [Mode](crate::protos::irc::client::ClientMessage::Mode) request. /// Reply to a client's [Mode](crate::protos::irc::client::ClientMessage::Mode) request.
N221UserModeIs { N221UserModeIs {
client: ByteVec, client: Str,
modes: ByteVec, modes: Str,
}, },
/// Final reply to a client's [Who](crate::protos::irc::client::ClientMessage::Who) request. /// Final reply to a client's [Who](crate::protos::irc::client::ClientMessage::Who) request.
N315EndOfWho { N315EndOfWho {
client: ByteVec, client: Str,
mask: Recipient, mask: Recipient,
/// Usually `b"End of WHO list"` /// Usually `b"End of WHO list"`
msg: ByteVec, msg: Str,
}, },
N332Topic { N332Topic {
client: ByteVec, client: Str,
chat: Chan, chat: Chan,
topic: ByteVec, topic: Str,
}, },
/// A reply to a client's [Who](crate::protos::irc::client::ClientMessage::Who) request. /// A reply to a client's [Who](crate::protos::irc::client::ClientMessage::Who) request.
N352WhoReply { N352WhoReply {
client: ByteVec, client: Str,
// chan = * // chan = *
username: ByteVec, username: Str,
/// User's hostname /// User's hostname
host: ByteVec, host: Str,
/// Hostname of the server the user is connected to /// Hostname of the server the user is connected to
server: ByteVec, server: Str,
nickname: ByteVec, nickname: Str,
/// Flags /// Flags
flags: AwayStatus, flags: AwayStatus,
hops: u8, hops: u8,
realname: ByteVec, realname: Str,
}, },
N353NamesReply { N353NamesReply {
client: ByteVec, client: Str,
chan: Chan, chan: Chan,
members: ByteVec, // TODO make this a non-empty list with prefixes members: Str, // TODO make this a non-empty list with prefixes
}, },
N366NamesReplyEnd { N366NamesReplyEnd {
client: ByteVec, client: Str,
chan: Chan, chan: Chan,
}, },
N474BannedFromChan { N474BannedFromChan {
client: ByteVec, client: Str,
chan: Chan, chan: Chan,
message: ByteVec, message: Str,
}, },
} }

View File

@ -12,13 +12,13 @@ pub const XMLNS: &'static str = "urn:ietf:params:xml:ns:xmpp-bind";
// TODO remove `pub` in newtypes, introduce validation // TODO remove `pub` in newtypes, introduce validation
#[derive(PartialEq, Eq, Debug, Clone)] #[derive(PartialEq, Eq, Debug, Clone)]
pub struct Name(pub Box<str>); pub struct Name(pub Str);
#[derive(PartialEq, Eq, Debug, Clone)] #[derive(PartialEq, Eq, Debug, Clone)]
pub struct Server(pub String); pub struct Server(pub Str);
#[derive(PartialEq, Eq, Debug, Clone)] #[derive(PartialEq, Eq, Debug, Clone)]
pub struct Resource(pub String); pub struct Resource(pub Str);
#[derive(PartialEq, Eq, Debug, Clone)] #[derive(PartialEq, Eq, Debug, Clone)]
pub struct Jid { pub struct Jid {
@ -51,10 +51,10 @@ impl Jid {
let name = m.get(2).map(|name| Name(name.as_str().into())); let name = m.get(2).map(|name| Name(name.as_str().into()));
let server = m.get(3).unwrap(); let server = m.get(3).unwrap();
let server = Server(server.as_str().to_string()); let server = Server(server.as_str().into());
let resource = m let resource = m
.get(5) .get(5)
.map(|resource| Resource(resource.as_str().to_string())); .map(|resource| Resource(resource.as_str().into()));
Ok(Jid { Ok(Jid {
name, name,
@ -101,6 +101,7 @@ impl FromXml for BindRequest {
} }
} }
// TODO rewrite as a generator
impl Parser for BindRequestParser { impl Parser for BindRequestParser {
type Output = Result<BindRequest>; type Output = Result<BindRequest>;
@ -138,7 +139,7 @@ impl Parser for BindRequestParser {
let Some(resource) = resource else { let Some(resource) = resource else {
return Continuation::Final(Err(ffail!("No resource was provided"))); return Continuation::Final(Err(ffail!("No resource was provided")));
}; };
Continuation::Final(Ok(BindRequest(Resource(resource)))) Continuation::Final(Ok(BindRequest(Resource(resource.into()))))
} }
_ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))), _ => Continuation::Final(Err(ffail!("Unexpected XML event: {event:?}"))),
}, },
@ -208,7 +209,7 @@ mod tests {
} }
} }
.unwrap(); .unwrap();
assert_eq!(result, BindRequest(Resource("mobile".to_string())),) assert_eq!(result, BindRequest(Resource("mobile".into())),)
} }
#[test] #[test]

View File

@ -17,10 +17,10 @@ pub struct Message {
pub to: Option<Jid>, pub to: Option<Jid>,
// default is Normal // default is Normal
pub r#type: MessageType, pub r#type: MessageType,
pub lang: Option<String>, pub lang: Option<Str>,
pub subject: Option<String>, pub subject: Option<Str>,
pub body: String, pub body: Str,
} }
impl FromXmlTag for Message { impl FromXmlTag for Message {
@ -53,9 +53,9 @@ struct MessageParserState {
id: Option<String>, id: Option<String>,
to: Option<Jid>, to: Option<Jid>,
r#type: MessageType, r#type: MessageType,
lang: Option<String>, lang: Option<Str>,
subject: Option<String>, subject: Option<Str>,
body: Option<String>, body: Option<Str>,
} }
impl Parser for MessageParser { impl Parser for MessageParser {
type Output = Result<Message>; type Output = Result<Message>;
@ -124,7 +124,7 @@ impl Parser for MessageParser {
InSubject(mut state) => match event { InSubject(mut state) => match event {
Event::Text(ref bytes) => { Event::Text(ref bytes) => {
let subject = fail_fast!(std::str::from_utf8(&*bytes)); let subject = fail_fast!(std::str::from_utf8(&*bytes));
state.subject = Some(subject.to_string()); state.subject = Some(subject.into());
Continuation::Continue(InSubject(state).into()) Continuation::Continue(InSubject(state).into())
} }
Event::End(_) => Continuation::Continue(Outer(state).into()), Event::End(_) => Continuation::Continue(Outer(state).into()),
@ -133,7 +133,7 @@ impl Parser for MessageParser {
InBody(mut state) => match event { InBody(mut state) => match event {
Event::Text(ref bytes) => match std::str::from_utf8(&*bytes) { Event::Text(ref bytes) => match std::str::from_utf8(&*bytes) {
Ok(subject) => { Ok(subject) => {
state.body = Some(subject.to_string()); state.body = Some(subject.into());
Continuation::Continue(InBody(state).into()) Continuation::Continue(InBody(state).into())
} }
Err(err) => Continuation::Final(Err(err.into())), Err(err) => Continuation::Final(Err(err.into())),
@ -614,13 +614,13 @@ mod tests {
id: Some("aacea".to_string()), id: Some("aacea".to_string()),
to: Some(Jid { to: Some(Jid {
name: Some(Name("nikita".into())), name: Some(Name("nikita".into())),
server: Server("vlnv.dev".to_owned()), server: Server("vlnv.dev".into()),
resource: None resource: None
}), }),
r#type: MessageType::Chat, r#type: MessageType::Chat,
lang: None, lang: None,
subject: Some("daa".to_string()), subject: Some("daa".into()),
body: "bbb".to_string(), body: "bbb".into(),
} }
) )
} }
@ -655,7 +655,7 @@ mod tests {
id: "bind_1".to_string(), id: "bind_1".to_string(),
to: None, to: None,
r#type: IqType::Set, r#type: IqType::Set,
body: BindRequest(Resource("mobile".to_string())) body: BindRequest(Resource("mobile".into()))
} }
) )
} }