style: apply cargo fmt across workspace

This commit is contained in:
Karim Jerbi committed 2026-10-11 03:14:29 +01:00
1 parent 85710e5454
commit 9cf9ff2c5c
531 files changed
+57740 -33906

No files matched your search

+80 -29
View File
@@ -16,7 +16,7 @@ use crate::ipc::protocol::{
HostResponse, HostToPlugin, PluginRequest, PluginResponse, PluginToHost, RunnerHandshake,
};
use crate::ipc::transport::{recv, send};
use crate::shm::{DocumentViewInfo, SharedDocumentReader, DocumentViewData};
use crate::shm::{DocumentViewData, DocumentViewInfo, SharedDocumentReader};
/// Shared registry of active interactive commands, keyed by host-assigned id.
pub type InteractiveRegistry = Rc<RefCell<HashMap<u64, Box<dyn InteractiveCommand>>>>;
@@ -60,7 +60,10 @@ impl IpcClient {
&self,
req: PluginRequest,
) -> Result<PluginResponse, crate::ipc::transport::TransportError> {
send(&mut self.stream.borrow_mut(), &PluginToHost::Request(Box::new(req)))?;
send(
&mut self.stream.borrow_mut(),
&PluginToHost::Request(Box::new(req)),
)?;
loop {
match recv::<HostToPlugin>(&mut self.stream.borrow_mut())? {
HostToPlugin::Response(resp) => return Ok(*resp),
@@ -389,16 +392,18 @@ impl HostApi for PluginHostApi {
}
}
match self.doc_view.borrow().as_ref() {
Some(info) => match SharedDocumentReader::<DocumentViewData>::open(Path::new(&info.path)) {
Ok(reader) => Box::new(reader),
Err(e) => {
eprintln!(
"[plugin] failed to open document view at {}: {e}",
info.path
);
Box::new(EmptyDocumentReader)
Some(info) => {
match SharedDocumentReader::<DocumentViewData>::open(Path::new(&info.path)) {
Ok(reader) => Box::new(reader),
Err(e) => {
eprintln!(
"[plugin] failed to open document view at {}: {e}",
info.path
);
Box::new(EmptyDocumentReader)
}
}
},
}
None => Box::new(EmptyDocumentReader),
}
}
@@ -419,7 +424,9 @@ impl HostApi for PluginHostApi {
}
fn system_variable(&self, name: &str) -> Option<HostSettingValue> {
match self.client.request(PluginRequest::GetSystemVariable { name: name.to_owned() }) {
match self.client.request(PluginRequest::GetSystemVariable {
name: name.to_owned(),
}) {
Ok(PluginResponse::SystemVariable(value)) => value,
_ => None,
}
@@ -451,11 +458,16 @@ impl HostApi for PluginHostApi {
label: &str,
entities: Vec<EntityType>,
) -> Result<(), String> {
match self.client.request(PluginRequest::UpdateEntitiesTransaction {
label: label.to_owned(), entities,
}) {
match self
.client
.request(PluginRequest::UpdateEntitiesTransaction {
label: label.to_owned(),
entities,
}) {
Ok(PluginResponse::EntityTransactionResult(result)) => {
if result.is_ok() { self.document_cache = OnceCell::new(); }
if result.is_ok() {
self.document_cache = OnceCell::new();
}
result
}
Ok(PluginResponse::Error(error)) => Err(error),
@@ -471,10 +483,18 @@ impl HostApi for PluginHostApi {
}
}
fn solid_operation(&mut self, operation: crate::host::SolidOperation) -> Result<Handle, String> {
match self.client.request(PluginRequest::SolidOperation { operation }) {
fn solid_operation(
&mut self,
operation: crate::host::SolidOperation,
) -> Result<Handle, String> {
match self
.client
.request(PluginRequest::SolidOperation { operation })
{
Ok(PluginResponse::SolidResult(result)) => {
if result.is_ok() { self.document_cache = OnceCell::new(); }
if result.is_ok() {
self.document_cache = OnceCell::new();
}
result
}
Ok(PluginResponse::Error(error)) => Err(error),
@@ -483,7 +503,10 @@ impl HostApi for PluginHostApi {
}
}
fn run_command(&mut self, request: crate::host::CommandRequest) -> Result<crate::host::CommandOutcome, String> {
fn run_command(
&mut self,
request: crate::host::CommandRequest,
) -> Result<crate::host::CommandOutcome, String> {
match self.client.request(PluginRequest::RunCommand { request }) {
Ok(PluginResponse::CommandResult(result)) => {
self.document_cache = OnceCell::new();
@@ -495,10 +518,18 @@ impl HostApi for PluginHostApi {
}
}
fn table_operation(&mut self, operation: crate::host::TableOperation) -> Result<Handle, String> {
match self.client.request(PluginRequest::TableOperation { operation }) {
fn table_operation(
&mut self,
operation: crate::host::TableOperation,
) -> Result<Handle, String> {
match self
.client
.request(PluginRequest::TableOperation { operation })
{
Ok(PluginResponse::TableResult(result)) => {
if result.is_ok() { self.document_cache = OnceCell::new(); }
if result.is_ok() {
self.document_cache = OnceCell::new();
}
result
}
Ok(PluginResponse::Error(error)) => Err(error),
@@ -508,7 +539,9 @@ impl HostApi for PluginHostApi {
}
fn set_selection(&mut self, handles: &[Handle]) -> Result<(), String> {
match self.client.request(PluginRequest::SetSelection { handles: handles.to_vec() }) {
match self.client.request(PluginRequest::SetSelection {
handles: handles.to_vec(),
}) {
Ok(PluginResponse::SelectionResult(result)) => result,
Ok(PluginResponse::Error(error)) => Err(error),
Ok(other) => Err(format!("unexpected selection response: {other:?}")),
@@ -555,7 +588,10 @@ impl HostApi for PluginHostApi {
}
fn execute_command(&mut self, cmd: &str) -> bool {
match self.client.request(PluginRequest::ExecuteCommand(cmd.to_string())) {
match self
.client
.request(PluginRequest::ExecuteCommand(cmd.to_string()))
{
Ok(PluginResponse::Bool(b)) => b,
Ok(other) => {
eprintln!("[plugin] unexpected ExecuteCommand response: {other:?}");
@@ -662,7 +698,11 @@ mod tests {
},
other => panic!("unexpected: {other:?}"),
}
send(&mut peer, &HostToPlugin::Response(Box::new(PluginResponse::Ok))).unwrap();
send(
&mut peer,
&HostToPlugin::Response(Box::new(PluginResponse::Ok)),
)
.unwrap();
});
api.push_info("hello host");
peer_handle.join().unwrap();
@@ -719,7 +759,10 @@ mod tests {
EntityType::Point(Point::new()),
]);
peer_handle.join().unwrap();
assert_eq!(handles, vec![Handle::new(10), Handle::new(11), Handle::new(12)]);
assert_eq!(
handles,
vec![Handle::new(10), Handle::new(11), Handle::new(12)]
);
}
#[test]
@@ -734,7 +777,11 @@ mod tests {
},
other => panic!("unexpected: {other:?}"),
}
send(&mut peer, &HostToPlugin::Response(Box::new(PluginResponse::Bool(true)))).unwrap();
send(
&mut peer,
&HostToPlugin::Response(Box::new(PluginResponse::Bool(true))),
)
.unwrap();
});
assert!(api.update_entity(EntityType::Point(Point::new())));
peer_handle.join().unwrap();
@@ -754,7 +801,11 @@ mod tests {
},
other => panic!("unexpected: {other:?}"),
}
send(&mut peer, &HostToPlugin::Response(Box::new(PluginResponse::Bool(true)))).unwrap();
send(
&mut peer,
&HostToPlugin::Response(Box::new(PluginResponse::Bool(true))),
)
.unwrap();
});
assert!(api.remove_entity(Handle::new(7)));
peer_handle.join().unwrap();
+2 -2
View File
@@ -23,13 +23,13 @@ pub mod client;
#[cfg(feature = "host")]
pub mod protocol;
#[cfg(feature = "host")]
pub mod proxy;
#[cfg(feature = "host")]
pub mod server;
#[cfg(feature = "host")]
pub mod transport;
#[cfg(feature = "host")]
pub mod v4;
#[cfg(feature = "host")]
pub mod proxy;
#[cfg(all(test, feature = "host"))]
mod tests {
+40 -13
View File
@@ -21,9 +21,9 @@ use crate::host::{CommandSource, CommandStep, HostSettingValue};
use crate::manifest::ApiVersion;
use crate::ribbon::owned::{OwnedPluginManifest, OwnedRibbonGroup};
pub use crate::host::PreviewWire;
pub use codec::xdata::{ExtendedDataRecord, XDataValue};
pub use codec::{CadDocument, EntityType, Handle};
pub use crate::host::PreviewWire;
/// Events the host forwards to an active plugin `InteractiveCommand`.
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -50,7 +50,10 @@ pub enum InteractiveEvent {
#[derive(Debug, Serialize, Deserialize)]
pub enum RunnerHandshake {
Token(String),
TokenV4 { token: String, protocol_version: u32 },
TokenV4 {
token: String,
protocol_version: u32,
},
}
/// Environment variable through which the host passes the pre-shared
@@ -83,7 +86,9 @@ pub enum HostRequest {
tab_index: usize,
},
/// V7: release an interactive command after completion or cancellation.
DropInteractive { command_id: u64 },
DropInteractive {
command_id: u64,
},
/// V7: cursor move preview update during an interactive command.
CursorMove {
command_id: u64,
@@ -145,13 +150,19 @@ pub enum PluginRequest {
AddEntities(Vec<EntityType>),
/// V4: ask the host to create/refresh a tab-keyed shared-memory document
/// view and return the file path + current version.
OpenDocumentViewV4 { tab_id: u64 },
OpenDocumentViewV4 {
tab_id: u64,
},
/// V4: ask the host to close the tab-keyed shared-memory document view.
CloseDocumentViewV4 { tab_id: u64 },
CloseDocumentViewV4 {
tab_id: u64,
},
/// V4: ask the host for the stable tab identifier of the active tab.
GetTabId,
/// V5: ask the host for the filesystem path of the document in `tab_id`.
DocumentPath { tab_id: u64 },
DocumentPath {
tab_id: u64,
},
/// Add a layer to the active document with full initial properties.
AddLayer(crate::host::LayerConfig),
/// Modify specified properties of an existing layer in the active document.
@@ -159,20 +170,36 @@ pub enum PluginRequest {
/// Run a command on the active document tab's command line (AutoLISP style).
ExecuteCommand(String),
/// Read a host-managed setting without nested command dispatch.
GetSystemVariable { name: String },
GetSystemVariable {
name: String,
},
/// Change a host-managed setting without nested command dispatch.
SetSystemVariable { name: String, value: HostSettingValue },
SetSystemVariable {
name: String,
value: HostSettingValue,
},
/// V7: validate and replace existing entities in a single undo step.
UpdateEntitiesTransaction { label: String, entities: Vec<EntityType> },
UpdateEntitiesTransaction {
label: String,
entities: Vec<EntityType>,
},
/// V7: synchronous selection read/write for the dispatch tab.
GetSelection,
SetSelection { handles: Vec<Handle> },
SetSelection {
handles: Vec<Handle>,
},
/// V7 (additive): kernel-backed solid create or transform.
SolidOperation { operation: crate::host::SolidOperation },
SolidOperation {
operation: crate::host::SolidOperation,
},
/// V7 (additive): drawing table record create/modify/rename/delete.
TableOperation { operation: crate::host::TableOperation },
TableOperation {
operation: crate::host::TableOperation,
},
/// V7 (additive): drive an OCS command.
RunCommand { request: crate::host::CommandRequest },
RunCommand {
request: crate::host::CommandRequest,
},
}
/// Responses the host sends back for `PluginRequest`.
+15 -7
View File
@@ -50,7 +50,10 @@ impl From<ProxyError> for PluginRequestError {
}
/// Send a length-framed bincode message over a generic stream.
pub fn send_framed<W: Write>(writer: &mut W, msg: &impl serde::Serialize) -> Result<(), ProxyError> {
pub fn send_framed<W: Write>(
writer: &mut W,
msg: &impl serde::Serialize,
) -> Result<(), ProxyError> {
let bytes = bincode::serialize(msg)?;
if bytes.len() > MAX_MESSAGE_SIZE {
return Err(ProxyError::TooLarge(bytes.len()));
@@ -63,7 +66,9 @@ pub fn send_framed<W: Write>(writer: &mut W, msg: &impl serde::Serialize) -> Res
}
/// Receive a length-framed bincode message from a generic stream.
pub fn recv_framed<R: Read, T: serde::de::DeserializeOwned>(reader: &mut R) -> Result<T, ProxyError> {
pub fn recv_framed<R: Read, T: serde::de::DeserializeOwned>(
reader: &mut R,
) -> Result<T, ProxyError> {
let mut len_buf = [0u8; 8];
reader.read_exact(&mut len_buf)?;
let len = u64::from_le_bytes(len_buf) as usize;
@@ -114,10 +119,12 @@ fn read_with_poll<R: Read>(
let mut off = 0;
while off < buf.len() {
match reader.read(&mut buf[off..]) {
Ok(0) => return Err(PollError::Io(ProxyError::Io(std::io::Error::new(
std::io::ErrorKind::UnexpectedEof,
"proxy disconnected",
)))),
Ok(0) => {
return Err(PollError::Io(ProxyError::Io(std::io::Error::new(
std::io::ErrorKind::UnexpectedEof,
"proxy disconnected",
))))
}
Ok(n) => off += n,
Err(e) if e.kind() == ErrorKind::WouldBlock || e.kind() == ErrorKind::TimedOut => {
if let Err(err) = poll() {
@@ -386,7 +393,8 @@ mod tests {
run_request_proxy(listener, sender, token).ok();
});
let sender = ProxyPluginRequestSender::connect_with_token("127.0.0.1", port, &token).unwrap();
let sender =
ProxyPluginRequestSender::connect_with_token("127.0.0.1", port, &token).unwrap();
let resp = sender
.request(PluginRequest::PushInfo("hello proxy".to_string()))
.unwrap();
+6 -2
View File
@@ -110,8 +110,12 @@ pub fn handle_plugin_request(
),
GetSelection => PluginResponse::Selection(host.selection()),
SetSelection { handles } => PluginResponse::SelectionResult(host.set_selection(&handles)),
SolidOperation { operation } => PluginResponse::SolidResult(host.solid_operation(operation)),
TableOperation { operation } => PluginResponse::TableResult(host.table_operation(operation)),
SolidOperation { operation } => {
PluginResponse::SolidResult(host.solid_operation(operation))
}
TableOperation { operation } => {
PluginResponse::TableResult(host.table_operation(operation))
}
RunCommand { request } => PluginResponse::CommandResult(host.run_command(request)),
}
}
+72 -55
View File
@@ -16,8 +16,8 @@ use interprocess::local_socket::{GenericNamespaced, Stream, ToNsName};
use interprocess::TryClone;
use crate::host::{
DocumentReader, ExecutionResult, HostApi, HostNotification, InteractiveCommand,
PluginNotification, PluginRequestSender, PluginRequestError, ReaderEntity, HostSettingValue,
DocumentReader, ExecutionResult, HostApi, HostNotification, HostSettingValue,
InteractiveCommand, PluginNotification, PluginRequestError, PluginRequestSender, ReaderEntity,
};
use crate::ipc::protocol::{
HostRequest, HostResponse, PluginRequest, PluginResponse, RunnerHandshake,
@@ -26,7 +26,7 @@ use crate::ipc::transport::{recv, send, TransportError};
use crate::ipc::v4::protocol::{
HostToPluginV4, NotificationEnvelope, PluginToHostV4, V4_PROTOCOL_VERSION,
};
use crate::shm::{DocumentViewInfo, SharedDocumentReader, DocumentViewData};
use crate::shm::{DocumentViewData, DocumentViewInfo, SharedDocumentReader};
/// Default capacity of the bounded host→plugin notification queue.
const DEFAULT_NOTIFY_QUEUE_SIZE: usize = 1024;
@@ -89,8 +89,7 @@ impl V4Client {
)))
})?;
let (notify_tx, notify_rx) =
mpsc::sync_channel(notify_queue_size());
let (notify_tx, notify_rx) = mpsc::sync_channel(notify_queue_size());
let (runner_tx, runner_rx) = mpsc::channel();
let shared = Arc::new(Shared {
@@ -101,14 +100,7 @@ impl V4Client {
let shared_for_reader = Arc::clone(&shared);
let notifications = Arc::new(Mutex::new(notify_rx));
std::thread::spawn(move || {
reader_thread(
reader,
shared_for_reader,
notify_tx,
runner_tx,
)
});
std::thread::spawn(move || reader_thread(reader, shared_for_reader, notify_tx, runner_tx));
Ok(Self {
shared,
@@ -133,7 +125,11 @@ impl V4Client {
/// Non-blocking poll for host-to-plugin notifications.
pub fn try_recv_notification(&self) -> Option<(Option<u64>, HostNotification)> {
self.notifications.lock().unwrap_or_else(|e| e.into_inner()).try_recv().ok()
self.notifications
.lock()
.unwrap_or_else(|e| e.into_inner())
.try_recv()
.ok()
}
/// Send a plugin response for a host request.
@@ -143,18 +139,11 @@ impl V4Client {
resp: HostResponse,
) -> Result<(), crate::ipc::transport::TransportError> {
let mut writer = self.shared.writer.lock().unwrap_or_else(|e| e.into_inner());
send(
&mut writer,
&PluginToHostV4::Response { id, payload: resp },
)
send(&mut writer, &PluginToHostV4::Response { id, payload: resp })
}
/// Send a plugin-to-host notification.
pub fn notify_plugin(
&self,
command_id: Option<u64>,
notification: PluginNotification,
) {
pub fn notify_plugin(&self, command_id: Option<u64>, notification: PluginNotification) {
let envelope = NotificationEnvelope {
command_id,
payload: notification,
@@ -168,10 +157,7 @@ impl V4Client {
/// Build a callback that sends a delayed `CodeExecutionResult` response for
/// the given request id. Used by `start_execute_code` implementations that
/// run REPL code on a background thread.
pub fn execute_code_responder(
&self,
id: u64,
) -> Box<dyn FnOnce(ExecutionResult) + Send> {
pub fn execute_code_responder(&self, id: u64) -> Box<dyn FnOnce(ExecutionResult) + Send> {
let shared = Arc::clone(&self.shared);
Box::new(move |result| {
let mut writer = shared.writer.lock().unwrap_or_else(|e| e.into_inner());
@@ -235,7 +221,10 @@ fn reader_thread(
}
}
Ok(HostToPluginV4::Notification(envelope)) => {
if notify_tx.try_send((envelope.command_id, envelope.payload)).is_err() {
if notify_tx
.try_send((envelope.command_id, envelope.payload))
.is_err()
{
let now = Instant::now();
let should_log = last_drop_log
.map(|t| now.duration_since(t) >= DROP_LOG_INTERVAL)
@@ -247,7 +236,10 @@ fn reader_thread(
}
}
Ok(HostToPluginV4::Request { id, payload }) => {
if runner_tx.send(RunnerFrame::Request { id, payload }).is_err() {
if runner_tx
.send(RunnerFrame::Request { id, payload })
.is_err()
{
// Runner loop has exited; stop reading.
break;
}
@@ -510,9 +502,7 @@ impl HostApi for V4PluginHostApi {
fn write_record(&mut self, handle: Handle, record: ExtendedDataRecord) -> bool {
let app = record.application_name.clone();
match self
.request(PluginRequest::WriteRecord { handle, record })
{
match self.request(PluginRequest::WriteRecord { handle, record }) {
Ok(PluginResponse::Bool(b)) => {
if b {
self.record_cache.borrow_mut().remove(&(handle, app));
@@ -631,16 +621,18 @@ impl HostApi for V4PluginHostApi {
}
}
match self.doc_view.borrow().as_ref() {
Some(info) => match SharedDocumentReader::<DocumentViewData>::open(Path::new(&info.path)) {
Ok(reader) => Box::new(reader),
Err(e) => {
eprintln!(
"[plugin] failed to open document view at {}: {e}",
info.path
);
Box::new(EmptyDocumentReader)
Some(info) => {
match SharedDocumentReader::<DocumentViewData>::open(Path::new(&info.path)) {
Ok(reader) => Box::new(reader),
Err(e) => {
eprintln!(
"[plugin] failed to open document view at {}: {e}",
info.path
);
Box::new(EmptyDocumentReader)
}
}
},
}
None => Box::new(EmptyDocumentReader),
}
}
@@ -657,7 +649,11 @@ impl HostApi for V4PluginHostApi {
}
fn try_recv_notification(&mut self) -> Option<(Option<u64>, HostNotification)> {
self.notifications.lock().unwrap_or_else(|e| e.into_inner()).try_recv().ok()
self.notifications
.lock()
.unwrap_or_else(|e| e.into_inner())
.try_recv()
.ok()
}
fn plugin_request_sender(&self) -> Option<Box<dyn PluginRequestSender>> {
@@ -734,7 +730,9 @@ impl HostApi for V4PluginHostApi {
}
fn system_variable(&self, name: &str) -> Option<HostSettingValue> {
match self.request(PluginRequest::GetSystemVariable { name: name.to_owned() }) {
match self.request(PluginRequest::GetSystemVariable {
name: name.to_owned(),
}) {
Ok(PluginResponse::SystemVariable(value)) => value,
_ => None,
}
@@ -767,10 +765,13 @@ impl HostApi for V4PluginHostApi {
entities: Vec<EntityType>,
) -> Result<(), String> {
match self.request(PluginRequest::UpdateEntitiesTransaction {
label: label.to_owned(), entities,
label: label.to_owned(),
entities,
}) {
Ok(PluginResponse::EntityTransactionResult(result)) => {
if result.is_ok() { self.document_cache = OnceCell::new(); }
if result.is_ok() {
self.document_cache = OnceCell::new();
}
result
}
Ok(PluginResponse::Error(error)) => Err(error),
@@ -786,10 +787,15 @@ impl HostApi for V4PluginHostApi {
}
}
fn solid_operation(&mut self, operation: crate::host::SolidOperation) -> Result<Handle, String> {
fn solid_operation(
&mut self,
operation: crate::host::SolidOperation,
) -> Result<Handle, String> {
match self.request(PluginRequest::SolidOperation { operation }) {
Ok(PluginResponse::SolidResult(result)) => {
if result.is_ok() { self.document_cache = OnceCell::new(); }
if result.is_ok() {
self.document_cache = OnceCell::new();
}
result
}
Ok(PluginResponse::Error(error)) => Err(error),
@@ -798,7 +804,10 @@ impl HostApi for V4PluginHostApi {
}
}
fn run_command(&mut self, request: crate::host::CommandRequest) -> Result<crate::host::CommandOutcome, String> {
fn run_command(
&mut self,
request: crate::host::CommandRequest,
) -> Result<crate::host::CommandOutcome, String> {
match self.request(PluginRequest::RunCommand { request }) {
Ok(PluginResponse::CommandResult(result)) => {
self.document_cache = OnceCell::new();
@@ -810,10 +819,15 @@ impl HostApi for V4PluginHostApi {
}
}
fn table_operation(&mut self, operation: crate::host::TableOperation) -> Result<Handle, String> {
fn table_operation(
&mut self,
operation: crate::host::TableOperation,
) -> Result<Handle, String> {
match self.request(PluginRequest::TableOperation { operation }) {
Ok(PluginResponse::TableResult(result)) => {
if result.is_ok() { self.document_cache = OnceCell::new(); }
if result.is_ok() {
self.document_cache = OnceCell::new();
}
result
}
Ok(PluginResponse::Error(error)) => Err(error),
@@ -823,7 +837,9 @@ impl HostApi for V4PluginHostApi {
}
fn set_selection(&mut self, handles: &[Handle]) -> Result<(), String> {
match self.request(PluginRequest::SetSelection { handles: handles.to_vec() }) {
match self.request(PluginRequest::SetSelection {
handles: handles.to_vec(),
}) {
Ok(PluginResponse::SelectionResult(result)) => result,
Ok(PluginResponse::Error(error)) => Err(error),
Ok(other) => Err(format!("unexpected selection response: {other:?}")),
@@ -899,9 +915,7 @@ impl V4Client {
});
let shared_for_reader = Arc::clone(&shared);
let notifications = Arc::new(Mutex::new(notify_rx));
std::thread::spawn(move || {
reader_thread(reader, shared_for_reader, notify_tx, runner_tx)
});
std::thread::spawn(move || reader_thread(reader, shared_for_reader, notify_tx, runner_tx));
Self {
shared,
notifications,
@@ -1081,7 +1095,10 @@ mod tests {
});
assert!(matches!(first.join().unwrap(), PluginResponse::Bool(true)));
assert!(matches!(second.join().unwrap(), PluginResponse::Bool(false)));
assert!(matches!(
second.join().unwrap(),
PluginResponse::Bool(false)
));
runner.join().unwrap();
}
+192 -51
View File
@@ -53,7 +53,10 @@ pub enum PluginToHostV4 {
tab_id: Option<u64>,
payload: PluginRequest,
},
Response { id: u64, payload: HostResponse },
Response {
id: u64,
payload: HostResponse,
},
Notification(NotificationEnvelope<PluginNotification>),
}
@@ -95,11 +98,17 @@ mod tests {
let bytes = bincode::serialize(&notification).unwrap();
let decoded: HostNotification = bincode::deserialize(&bytes).unwrap();
assert_eq!(decoded, notification);
let stopped = HostNotification::CommandStateChanged { tab_id: 42, command: None };
let stopped = HostNotification::CommandStateChanged {
tab_id: 42,
command: None,
};
let bytes = bincode::serialize(&stopped).unwrap();
let decoded: HostNotification = bincode::deserialize(&bytes).unwrap();
assert_eq!(decoded, stopped);
let changed = HostNotification::DrawingChanged { tab_id: 42, epoch: 7 };
let changed = HostNotification::DrawingChanged {
tab_id: 42,
epoch: 7,
};
let bytes = bincode::serialize(&changed).unwrap();
let decoded: HostNotification = bincode::deserialize(&bytes).unwrap();
assert_eq!(decoded, changed);
@@ -109,19 +118,33 @@ mod tests {
fn command_request_and_outcome_roundtrip() {
use crate::host::{CommandOutcome, CommandRequest};
for request in [
CommandRequest::Run { line: "LINE 0,0 1,1".into() },
CommandRequest::Start { name: "OFFSET".into() },
CommandRequest::Point { point: [1.0, 2.0, 3.0] },
CommandRequest::Run {
line: "LINE 0,0 1,1".into(),
},
CommandRequest::Start {
name: "OFFSET".into(),
},
CommandRequest::Point {
point: [1.0, 2.0, 3.0],
},
CommandRequest::Text { text: "2".into() },
CommandRequest::Token { text: "R".into() },
CommandRequest::Entity { handle: codec::Handle::new(9), point: [0.0; 3] },
CommandRequest::Entity {
handle: codec::Handle::new(9),
point: [0.0; 3],
},
CommandRequest::Selection,
CommandRequest::Enter,
CommandRequest::Cancel,
] {
let bytes = bincode::serialize(&PluginRequest::RunCommand { request: request.clone() }).unwrap();
assert!(matches!(bincode::deserialize::<PluginRequest>(&bytes).unwrap(),
PluginRequest::RunCommand { request: decoded } if decoded == request));
let bytes = bincode::serialize(&PluginRequest::RunCommand {
request: request.clone(),
})
.unwrap();
assert!(
matches!(bincode::deserialize::<PluginRequest>(&bytes).unwrap(),
PluginRequest::RunCommand { request: decoded } if decoded == request)
);
}
let outcome = CommandOutcome {
status: "waiting_input".into(),
@@ -137,8 +160,10 @@ mod tests {
};
for result in [Ok(outcome), Err("refused".to_owned())] {
let bytes = bincode::serialize(&PluginResponse::CommandResult(result.clone())).unwrap();
assert!(matches!(bincode::deserialize::<PluginResponse>(&bytes).unwrap(),
PluginResponse::CommandResult(decoded) if decoded == result));
assert!(
matches!(bincode::deserialize::<PluginResponse>(&bytes).unwrap(),
PluginResponse::CommandResult(decoded) if decoded == result)
);
}
}
@@ -155,19 +180,60 @@ mod tests {
..Default::default()
},
},
TableOperation::LayerModify { config: LayerConfig { name: "Walls".into(), off: Some(true), ..Default::default() } },
TableOperation::LayerRename { from: "A".into(), to: "B".into() },
TableOperation::LayerDelete { name: "A".into(), erase_objects: true },
TableOperation::LayerModify {
config: LayerConfig {
name: "Walls".into(),
off: Some(true),
..Default::default()
},
},
TableOperation::LayerRename {
from: "A".into(),
to: "B".into(),
},
TableOperation::LayerDelete {
name: "A".into(),
erase_objects: true,
},
TableOperation::LayerSetCurrent { name: "A".into() },
TableOperation::TextStyleCreate {
config: crate::host::TextStyleConfig { name: "T".into(), height: Some(2.5), oblique_angle: Some(0.2), backward: Some(true), ..Default::default() },
config: crate::host::TextStyleConfig {
name: "T".into(),
height: Some(2.5),
oblique_angle: Some(0.2),
backward: Some(true),
..Default::default()
},
},
TableOperation::TextStyleModify {
config: crate::host::TextStyleConfig {
name: "T".into(),
font_file: Some("romans".into()),
..Default::default()
},
},
TableOperation::DimStyleCreate {
name: "D".into(),
copy_from: Some("Standard".into()),
properties: "{\"dimscale\":2}".into(),
},
TableOperation::DimStyleModify {
name: "D".into(),
properties: "{}".into(),
},
TableOperation::StyleRename {
kind: crate::host::TableStyleKind::Text,
from: "A".into(),
to: "B".into(),
},
TableOperation::StyleDelete {
kind: crate::host::TableStyleKind::Dim,
name: "A".into(),
},
TableOperation::StyleSetCurrent {
kind: crate::host::TableStyleKind::Dim,
name: "A".into(),
},
TableOperation::TextStyleModify { config: crate::host::TextStyleConfig { name: "T".into(), font_file: Some("romans".into()), ..Default::default() } },
TableOperation::DimStyleCreate { name: "D".into(), copy_from: Some("Standard".into()), properties: "{\"dimscale\":2}".into() },
TableOperation::DimStyleModify { name: "D".into(), properties: "{}".into() },
TableOperation::StyleRename { kind: crate::host::TableStyleKind::Text, from: "A".into(), to: "B".into() },
TableOperation::StyleDelete { kind: crate::host::TableStyleKind::Dim, name: "A".into() },
TableOperation::StyleSetCurrent { kind: crate::host::TableStyleKind::Dim, name: "A".into() },
TableOperation::BlockCreate {
name: "B".into(),
entities: vec![codec::Handle::new(4), codec::Handle::new(5)],
@@ -175,31 +241,67 @@ mod tests {
erase_originals: true,
description: Some("d".into()),
},
TableOperation::BlockModify { name: "B".into(), description: None, explodable: Some(false), scale_uniformly: Some(true) },
TableOperation::BlockRename { from: "B".into(), to: "C".into() },
TableOperation::BlockModify {
name: "B".into(),
description: None,
explodable: Some(false),
scale_uniformly: Some(true),
},
TableOperation::BlockRename {
from: "B".into(),
to: "C".into(),
},
TableOperation::BlockDelete { name: "C".into() },
TableOperation::BlockEntityAdd {
block: "C".into(),
entity: codec::EntityType::Line(codec::entities::Line::new()),
},
TableOperation::LinetypeCreate { name: "L".into(), description: "d".into(), pattern: vec![1.0, -1.0] },
TableOperation::LinetypeModify { name: "L".into(), description: None, pattern: Some(vec![2.0, -2.0]) },
TableOperation::LinetypeRename { from: "L".into(), to: "M".into() },
TableOperation::LinetypeCreate {
name: "L".into(),
description: "d".into(),
pattern: vec![1.0, -1.0],
},
TableOperation::LinetypeModify {
name: "L".into(),
description: None,
pattern: Some(vec![2.0, -2.0]),
},
TableOperation::LinetypeRename {
from: "L".into(),
to: "M".into(),
},
TableOperation::LinetypeDelete { name: "M".into() },
TableOperation::LayoutCreate { name: "S".into() },
TableOperation::LayoutRename { from: "S".into(), to: "T".into() },
TableOperation::LayoutRename {
from: "S".into(),
to: "T".into(),
},
TableOperation::LayoutDelete { name: "T".into() },
TableOperation::LayoutSetCurrent { name: "Model".into() },
TableOperation::LayoutSetPage { name: "S".into(), paper_size: Some([420.0, 297.0]), rotation: Some(90), scale: Some([1.0, 50.0]) },
TableOperation::LayoutSetCurrent {
name: "Model".into(),
},
TableOperation::LayoutSetPage {
name: "S".into(),
paper_size: Some([420.0, 297.0]),
rotation: Some(90),
scale: Some([1.0, 50.0]),
},
] {
let bytes = bincode::serialize(&PluginRequest::TableOperation { operation: operation.clone() }).unwrap();
assert!(matches!(bincode::deserialize::<PluginRequest>(&bytes).unwrap(),
PluginRequest::TableOperation { operation: decoded } if decoded == operation));
let bytes = bincode::serialize(&PluginRequest::TableOperation {
operation: operation.clone(),
})
.unwrap();
assert!(
matches!(bincode::deserialize::<PluginRequest>(&bytes).unwrap(),
PluginRequest::TableOperation { operation: decoded } if decoded == operation)
);
}
for result in [Ok(codec::Handle::new(9)), Err("refused".to_owned())] {
let bytes = bincode::serialize(&PluginResponse::TableResult(result.clone())).unwrap();
assert!(matches!(bincode::deserialize::<PluginResponse>(&bytes).unwrap(),
PluginResponse::TableResult(decoded) if decoded == result));
assert!(
matches!(bincode::deserialize::<PluginResponse>(&bytes).unwrap(),
PluginResponse::TableResult(decoded) if decoded == result)
);
}
}
@@ -208,12 +310,29 @@ mod tests {
use crate::host::{SolidOperation, SolidPrimitive};
for operation in [
SolidOperation::Create {
primitive: SolidPrimitive::Pyramid { center: [1.0, 2.0, 3.0], radius: 4.0, height: 5.0, sides: 6 },
primitive: SolidPrimitive::Pyramid {
center: [1.0, 2.0, 3.0],
radius: 4.0,
height: 5.0,
sides: 6,
},
layer: Some("SOLIDS".into()),
},
SolidOperation::Transform { handle: codec::Handle::new(7), matrix: [1.0; 16] },
SolidOperation::RegionFromProfile { source: codec::Handle::new(3), layer: None, delete_source: true },
SolidOperation::EmbedPicture { path: "p.png".into(), origin: [0.0; 3], width: 5.0, layer: None },
SolidOperation::Transform {
handle: codec::Handle::new(7),
matrix: [1.0; 16],
},
SolidOperation::RegionFromProfile {
source: codec::Handle::new(3),
layer: None,
delete_source: true,
},
SolidOperation::EmbedPicture {
path: "p.png".into(),
origin: [0.0; 3],
width: 5.0,
layer: None,
},
SolidOperation::Boolean {
first: codec::Handle::new(1),
second: codec::Handle::new(2),
@@ -221,30 +340,52 @@ mod tests {
layer: None,
keep_operands: false,
},
SolidOperation::SurfaceFromProfile { source: codec::Handle::new(4), layer: Some("S".into()), delete_source: false },
SolidOperation::Extrude { source: codec::Handle::new(5), direction: [0.0, 0.0, 2.0], layer: None, delete_source: true },
SolidOperation::SurfaceFromProfile {
source: codec::Handle::new(4),
layer: Some("S".into()),
delete_source: false,
},
SolidOperation::Extrude {
source: codec::Handle::new(5),
direction: [0.0, 0.0, 2.0],
layer: None,
delete_source: true,
},
] {
let bytes = bincode::serialize(&PluginRequest::SolidOperation { operation: operation.clone() }).unwrap();
assert!(matches!(bincode::deserialize::<PluginRequest>(&bytes).unwrap(),
PluginRequest::SolidOperation { operation: decoded } if decoded == operation));
let bytes = bincode::serialize(&PluginRequest::SolidOperation {
operation: operation.clone(),
})
.unwrap();
assert!(
matches!(bincode::deserialize::<PluginRequest>(&bytes).unwrap(),
PluginRequest::SolidOperation { operation: decoded } if decoded == operation)
);
}
for result in [Ok(codec::Handle::new(9)), Err("refused".to_owned())] {
let bytes = bincode::serialize(&PluginResponse::SolidResult(result.clone())).unwrap();
assert!(matches!(bincode::deserialize::<PluginResponse>(&bytes).unwrap(),
PluginResponse::SolidResult(decoded) if decoded == result));
assert!(
matches!(bincode::deserialize::<PluginResponse>(&bytes).unwrap(),
PluginResponse::SolidResult(decoded) if decoded == result)
);
}
}
#[test]
fn selection_request_and_response_roundtrip() {
let request = PluginRequest::SetSelection { handles: vec![codec::Handle::new(9)] };
let request = PluginRequest::SetSelection {
handles: vec![codec::Handle::new(9)],
};
let bytes = bincode::serialize(&request).unwrap();
assert!(matches!(bincode::deserialize::<PluginRequest>(&bytes).unwrap(),
PluginRequest::SetSelection { handles } if handles == vec![codec::Handle::new(9)]));
assert!(
matches!(bincode::deserialize::<PluginRequest>(&bytes).unwrap(),
PluginRequest::SetSelection { handles } if handles == vec![codec::Handle::new(9)])
);
let response = PluginResponse::Selection(vec![codec::Handle::new(9)]);
let bytes = bincode::serialize(&response).unwrap();
assert!(matches!(bincode::deserialize::<PluginResponse>(&bytes).unwrap(),
PluginResponse::Selection(handles) if handles == vec![codec::Handle::new(9)]));
assert!(
matches!(bincode::deserialize::<PluginResponse>(&bytes).unwrap(),
PluginResponse::Selection(handles) if handles == vec![codec::Handle::new(9)])
);
}
#[test]
+4 -1
View File
@@ -26,7 +26,10 @@ macro_rules! vlog {
/// A frame delivered from the V4 reader thread to the host main thread.
pub enum HostIncoming {
Response { id: u64, payload: crate::ipc::protocol::HostResponse },
Response {
id: u64,
payload: crate::ipc::protocol::HostResponse,
},
Request {
id: u64,
tab_id: Option<u64>,