use crate::implementation::object;
use crate::{steady_millis, trace};
use hyprwire_core::message;
use hyprwire_core::message::wire::generic_protocol_message;
use hyprwire_core::types;
use std::os::fd::AsRawFd;
use std::sync::atomic;
pub trait WireObject: object::Object {
fn set_version(&self, version: u32);
fn version(&self) -> u32;
fn methods_out(&self) -> &[types::Method];
fn errd(&self);
fn mark_destroyed(&self) {}
fn send_message(&self, msg: &dyn message::Message);
fn protocol_name(&self) -> &str;
fn server(&self) -> bool;
fn id(&self) -> u32;
fn seq(&self) -> u32;
fn call(&self, id: u32, args: &[types::CallArg]) -> Result<u32, message::Error> {
let methods = self.methods_out();
if methods.len() <= id as usize {
let msg = format!("invalid method {} for object {}", id, self.id());
crate::log_error!("core protocol error: {msg}");
self.error(self.id(), &msg);
return Ok(0);
}
let method = &methods[id as usize];
if method.since > self.version() {
let msg = format!(
"method {} since {} but has {}",
id,
method.since,
self.version()
);
crate::log_error!("core protocol error: {msg}");
self.error(self.id(), &msg);
return Ok(0);
}
if !method.returns_type.is_empty() && self.server() {
let msg = format!(
"invalid method spec {} for object {} -> server cannot call returnsType methods",
id,
self.id()
);
crate::log_error!("core protocol error: {msg}");
self.error(self.id(), &msg);
return Ok(0);
}
if method.destructor {
self.mark_destroyed();
}
let mut data: Vec<u8> = Vec::new();
let mut fds: Vec<i32> = Vec::new();
data.push(message::MessageType::GenericProtocolMessage as u8);
data.push(types::MessageMagic::TypeObject as u8);
let obj_id = self.id();
data.extend_from_slice(&obj_id.to_le_bytes());
data.push(types::MessageMagic::TypeUint as u8);
data.extend_from_slice(&id.to_le_bytes());
let mut return_seq: u32 = 0;
if !method.returns_type.is_empty() {
trace! {
if let Some(client) = self.client_sock() {
crate::log_debug!("[hw] trace: [{} @ {:.3}] -- call {}: returnsType has {}", client.0.state.stream.as_raw_fd(), steady_millis(), id, method.returns_type);
}
}
data.push(types::MessageMagic::TypeSeq as u8);
if let Some(client) = self.client_sock() {
return_seq = client.0.seq.fetch_add(1, atomic::Ordering::Relaxed) + 1;
}
data.extend_from_slice(&return_seq.to_le_bytes());
}
let mut arg_idx: usize = 0;
let mut i: usize = 0;
while i < method.params.len() {
let Ok(param) = types::MessageMagic::try_from(method.params[i]) else {
break;
};
match param {
types::MessageMagic::TypeUint => {
data.push(types::MessageMagic::TypeUint as u8);
if let Some(types::CallArg::Uint(val)) = args.get(arg_idx) {
data.extend_from_slice(&val.to_le_bytes());
}
arg_idx += 1;
}
types::MessageMagic::TypeInt => {
data.push(types::MessageMagic::TypeInt as u8);
if let Some(types::CallArg::Int(val)) = args.get(arg_idx) {
data.extend_from_slice(&val.to_le_bytes());
}
arg_idx += 1;
}
types::MessageMagic::TypeObject => {
data.push(types::MessageMagic::TypeObject as u8);
if let Some(types::CallArg::Object(val)) = args.get(arg_idx) {
data.extend_from_slice(&val.to_le_bytes());
}
arg_idx += 1;
}
types::MessageMagic::TypeF32 => {
data.push(types::MessageMagic::TypeF32 as u8);
if let Some(types::CallArg::F32(val)) = args.get(arg_idx) {
data.extend_from_slice(&val.to_le_bytes());
}
arg_idx += 1;
}
types::MessageMagic::TypeVarchar => {
data.push(types::MessageMagic::TypeVarchar as u8);
if let Some(types::CallArg::Varchar(s)) = args.get(arg_idx) {
let mut var_int_buf = [0u8; 10];
let encoded = message::encode_var_int(s.len(), &mut var_int_buf);
data.extend_from_slice(encoded);
data.extend_from_slice(s);
}
arg_idx += 1;
}
types::MessageMagic::TypeFd => {
data.push(types::MessageMagic::TypeFd as u8);
if let Some(types::CallArg::Fd(fd)) = args.get(arg_idx) {
fds.push(*fd);
}
arg_idx += 1;
}
types::MessageMagic::TypeArray => {
i += 1;
let Ok(arr_type) = types::MessageMagic::try_from(method.params[i]) else {
break;
};
data.push(types::MessageMagic::TypeArray as u8);
data.push(arr_type as u8);
match args.get(arg_idx) {
Some(types::CallArg::UintArray(arr) | types::CallArg::ObjectArray(arr)) => {
let mut var_int_buf = [0u8; 10];
let encoded = message::encode_var_int(arr.len(), &mut var_int_buf);
data.extend_from_slice(encoded);
for val in *arr {
data.extend_from_slice(&val.to_le_bytes());
}
}
Some(types::CallArg::IntArray(arr)) => {
let mut var_int_buf = [0u8; 10];
let encoded = message::encode_var_int(arr.len(), &mut var_int_buf);
data.extend_from_slice(encoded);
for val in *arr {
data.extend_from_slice(&val.to_le_bytes());
}
}
Some(types::CallArg::F32Array(arr)) => {
let mut var_int_buf = [0u8; 10];
let encoded = message::encode_var_int(arr.len(), &mut var_int_buf);
data.extend_from_slice(encoded);
for val in *arr {
data.extend_from_slice(&val.to_le_bytes());
}
}
Some(types::CallArg::FdArray(arr)) => {
let mut var_int_buf = [0u8; 10];
let encoded = message::encode_var_int(arr.len(), &mut var_int_buf);
data.extend_from_slice(encoded);
for fd in *arr {
fds.push(*fd);
}
}
Some(types::CallArg::VarcharArray(arr)) => {
let mut var_int_buf = [0u8; 10];
let encoded = message::encode_var_int(arr.len(), &mut var_int_buf);
data.extend_from_slice(encoded);
for s in *arr {
let encoded = message::encode_var_int(s.len(), &mut var_int_buf);
data.extend_from_slice(encoded);
data.extend_from_slice(s);
}
}
_ => {
crate::log_error!("core protocol error: failed marshaling array type");
self.errd();
return Ok(0);
}
}
arg_idx += 1;
}
_ => break,
}
i += 1;
}
data.push(types::MessageMagic::End as u8);
let mut msg = generic_protocol_message::GenericProtocolMessage::new(data, fds);
if self.id() == 0 && !self.server() {
trace! {
if let Some(client) = self.client_sock() {
crate::log_debug!("[hw] trace: [{} @ {:.3}] -- call: waiting on object of type {}", client.0.state.stream.as_raw_fd(), steady_millis(), method.returns_type);
}
}
let protocol_name = self.protocol_name();
msg.set_depends_on_seq(self.seq());
let qh = self.event_queue().unwrap();
qh.inner.lock().unwrap().queue.push(msg);
if return_seq != 0 {
if let Some(client) = self.client_sock() {
client
.0
.make_object(protocol_name, method.returns_type, return_seq, &qh)?;
}
return Ok(return_seq);
}
} else {
self.send_message(&msg);
if return_seq != 0 {
let protocol_name = self.protocol_name();
if let Some(client) = self.client_sock() {
let qh = self.event_queue().unwrap();
client
.0
.make_object(protocol_name, method.returns_type, return_seq, &qh)?;
return Ok(return_seq);
}
}
}
Ok(0)
}
}