Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/calloop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ fn handle_result(
} else {
eis::connection::DisconnectReason::Protocol
};
connection.disconnected(reason, &err.to_string());
connection.disconnected(reason, Some(&err.to_string()));
let _ = connection.flush();
}

Expand Down Expand Up @@ -168,7 +168,7 @@ fn process_handshake(
if !handle.has_interface("ei_seat") || !handle.has_interface("ei_device") {
handle.disconnected(
eis::connection::DisconnectReason::Protocol,
"Need `ei_seat` and `ei_device`",
Some("Need `ei_seat` and `ei_device`"),
);
let _ = request_converter.handle().flush();
return Err(HandshakeError::MissingInterface.into());
Expand Down
6 changes: 4 additions & 2 deletions src/eiproto.rs.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

// GENERATED FILE

{# TODO handle context_type #}
{# TODO More complete handling of nullable types? #}

use crate::wire;

Expand All @@ -32,7 +32,9 @@ use crate::wire;

{%- macro arg_type(arg, owned, generic) -%}
{%- if arg.enum != None -%} {{ arg.enum.name|camel }}
{%- elif arg.protocol_type == 'string' and owned and arg.allow_null -%} Option<String>
{%- elif arg.protocol_type == 'string' and owned -%} String
{%- elif arg.protocol_type == 'string' and arg.allow_null -%} Option<&str>
{%- elif arg.protocol_type == 'string' -%} &str
{%- elif arg.protocol_type == 'int32' -%} i32
{%- elif arg.protocol_type == 'uint32' -%} u32
Expand Down Expand Up @@ -182,7 +184,7 @@ pub mod {{interface.plainname}} {
let args = &[
{%- for arg in outgoing.arguments %}
{% if arg.interface_arg_for %}
wire::Arg::{{arg.protocol_type|camel}}({{arg.name|camel}}::NAME),
wire::Arg::{{arg.protocol_type|camel}}(Some({{arg.name|camel}}::NAME)),
{% else %}
wire::Arg::{{arg.protocol_type|camel}}({{arg.name}}
{% if arg.protocol_type == 'new_id' %}
Expand Down
2 changes: 1 addition & 1 deletion src/eiproto_ei.rs
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ pub mod connection {
/// The reason for being disconnected.
reason: DisconnectReason,
/// An explanation for debugging purposes.
explanation: String,
explanation: Option<String>,
},
/// Seat presence information.
///
Expand Down
4 changes: 2 additions & 2 deletions src/eiproto_eis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ pub mod connection {
&self,
last_serial: u32,
reason: DisconnectReason,
explanation: &str,
explanation: Option<&str>,
) -> () {
let args = &[
wire::Arg::Uint32(last_serial.into()),
Expand Down Expand Up @@ -1478,7 +1478,7 @@ pub mod device {
.new_object(InterfaceName::NAME.to_string(), version);
let args = &[
wire::Arg::NewId(object.id().into()),
wire::Arg::String(InterfaceName::NAME),
wire::Arg::String(Some(InterfaceName::NAME)),
wire::Arg::Uint32(version.into()),
];

Expand Down
2 changes: 1 addition & 1 deletion src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -976,7 +976,7 @@ pub struct Disconnected {
/// Reason for disconnection.
pub reason: ei::connection::DisconnectReason,
/// Explanation for debugging purposes.
pub explanation: String,
pub explanation: Option<String>,
}

/// High-level translation of the seat description events ending with [`ei_seat.done`](ei::seat::Event::Done).
Expand Down
4 changes: 2 additions & 2 deletions src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,7 @@ impl Connection {
///
/// Will panic if an internal Mutex is poisoned.
// TODO(axka, 2025-07-08): rename to something imperative like `notify_disconnection`
// TODO(axka, 2025-07-08): `explanation` must support NULL: https://gitlab.freedesktop.org/libinput/libei/-/commit/267716a7609730914b24adf5860ec8d2cf2e7636
pub fn disconnected(&self, reason: DisconnectReason, explanation: &str) {
pub fn disconnected(&self, reason: DisconnectReason, explanation: Option<&str>) {
let seats = self
.0
.seats
Expand Down Expand Up @@ -393,6 +392,7 @@ impl EisRequestConverter {
self.handle_touchscreen_request(touchscreen, request)?;
}
}

Ok(())
}

Expand Down
25 changes: 19 additions & 6 deletions src/wire/arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub enum Arg<'a> {
Int64(i64),
Float(f32),
Fd(BorrowedFd<'a>),
String(&'a str),
String(Option<&'a str>),
NewId(u64),
Id(u64),
}
Expand Down Expand Up @@ -56,7 +56,10 @@ impl Arg<'_> {
Arg::Float(value) => buf.extend(value.to_ne_bytes()),
// XXX unwrap?
Arg::Fd(value) => fds.extend([value.try_clone_to_owned().unwrap()]),
Arg::String(value) => {
Arg::String(None) => {
buf.extend(0u32.to_ne_bytes());
}
Arg::String(Some(value)) => {
// Write 32-bit length, including NUL
let len = value.len() as u32 + 1;
buf.extend(len.to_ne_bytes());
Expand Down Expand Up @@ -145,11 +148,11 @@ impl OwnedArg for OwnedFd {
}
}

impl OwnedArg for String {
impl OwnedArg for Option<String> {
fn parse(buf: &mut ByteStream) -> Result<Self, ParseError> {
let mut len = u32::parse(buf)?;
if len == 0 {
return Ok(String::new());
return Ok(None);
}
let bytes = buf.read_n(len as usize - 1)?; // Exclude NUL
let string = String::from_utf8(bytes.collect())?;
Expand All @@ -159,11 +162,21 @@ impl OwnedArg for String {
len += 1;
buf.read::<1>()?;
}
Ok(string)
Ok(Some(string))
}

fn as_arg(&self) -> Arg<'_> {
Arg::String(self.as_deref())
}
}

impl OwnedArg for String {
fn parse(buf: &mut ByteStream) -> Result<Self, ParseError> {
Option::<String>::parse(buf)?.ok_or(ParseError::InvalidNull)
}

fn as_arg(&self) -> Arg<'_> {
Arg::String(self)
Arg::String(Some(self))
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/wire/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ pub enum ParseError {
HeaderLength(u32),
/// Message length didn't match header.
MessageLength(u32, u32),
/// NULL for non-nullable argument
InvalidNull,
}

impl fmt::Display for ParseError {
Expand All @@ -142,6 +144,9 @@ impl fmt::Display for ParseError {
Self::MessageLength(a, b) => {
write!(f, "message length didn't match header ({a} != {b})")
}
Self::InvalidNull => {
write!(f, "NULL value for non-nullable argument")
}
}
}
}
Expand Down
Loading