Skip to content

Commit d8b7f32

Browse files
authored
Support empty IpcSharedMemory (#335)
* Add tests for empty shared mem * Simple empty slice * Bump version to 0.18.1
1 parent 25040c9 commit d8b7f32

File tree

3 files changed

+78
-27
lines changed

3 files changed

+78
-27
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "ipc-channel"
3-
version = "0.18.0"
3+
version = "0.18.1"
44
description = "A multiprocess drop-in replacement for Rust channels"
55
authors = ["The Servo Project Developers"]
66
license = "MIT OR Apache-2.0"

src/ipc.rs

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -553,15 +553,20 @@ impl IpcReceiverSet {
553553
derive(PartialEq)
554554
)]
555555
pub struct IpcSharedMemory {
556-
os_shared_memory: OsIpcSharedMemory,
556+
/// None represents no data (empty slice)
557+
os_shared_memory: Option<OsIpcSharedMemory>,
557558
}
558559

559560
impl Deref for IpcSharedMemory {
560561
type Target = [u8];
561562

562563
#[inline]
563564
fn deref(&self) -> &[u8] {
564-
&self.os_shared_memory
565+
if let Some(os_shared_memory) = &self.os_shared_memory {
566+
os_shared_memory
567+
} else {
568+
&[]
569+
}
565570
}
566571
}
567572

@@ -571,16 +576,22 @@ impl<'de> Deserialize<'de> for IpcSharedMemory {
571576
D: Deserializer<'de>,
572577
{
573578
let index: usize = Deserialize::deserialize(deserializer)?;
574-
let os_shared_memory = OS_IPC_SHARED_MEMORY_REGIONS_FOR_DESERIALIZATION.with(
575-
|os_ipc_shared_memory_regions_for_deserialization| {
576-
// FIXME(pcwalton): This could panic if the data was corrupt and the index was out
577-
// of bounds. We should return an `Err` result instead.
578-
os_ipc_shared_memory_regions_for_deserialization.borrow_mut()[index]
579-
.take()
580-
.unwrap()
581-
},
582-
);
583-
Ok(IpcSharedMemory { os_shared_memory })
579+
if index == usize::MAX {
580+
Ok(IpcSharedMemory::empty())
581+
} else {
582+
let os_shared_memory = OS_IPC_SHARED_MEMORY_REGIONS_FOR_DESERIALIZATION.with(
583+
|os_ipc_shared_memory_regions_for_deserialization| {
584+
// FIXME(pcwalton): This could panic if the data was corrupt and the index was out
585+
// of bounds. We should return an `Err` result instead.
586+
os_ipc_shared_memory_regions_for_deserialization.borrow_mut()[index]
587+
.take()
588+
.unwrap()
589+
},
590+
);
591+
Ok(IpcSharedMemory {
592+
os_shared_memory: Some(os_shared_memory),
593+
})
594+
}
584595
}
585596
}
586597

@@ -589,32 +600,52 @@ impl Serialize for IpcSharedMemory {
589600
where
590601
S: Serializer,
591602
{
592-
let index = OS_IPC_SHARED_MEMORY_REGIONS_FOR_SERIALIZATION.with(
593-
|os_ipc_shared_memory_regions_for_serialization| {
594-
let mut os_ipc_shared_memory_regions_for_serialization =
595-
os_ipc_shared_memory_regions_for_serialization.borrow_mut();
596-
let index = os_ipc_shared_memory_regions_for_serialization.len();
597-
os_ipc_shared_memory_regions_for_serialization.push(self.os_shared_memory.clone());
598-
index
599-
},
600-
);
601-
index.serialize(serializer)
603+
if let Some(os_shared_memory) = &self.os_shared_memory {
604+
let index = OS_IPC_SHARED_MEMORY_REGIONS_FOR_SERIALIZATION.with(
605+
|os_ipc_shared_memory_regions_for_serialization| {
606+
let mut os_ipc_shared_memory_regions_for_serialization =
607+
os_ipc_shared_memory_regions_for_serialization.borrow_mut();
608+
let index = os_ipc_shared_memory_regions_for_serialization.len();
609+
os_ipc_shared_memory_regions_for_serialization.push(os_shared_memory.clone());
610+
index
611+
},
612+
);
613+
debug_assert!(index < usize::MAX);
614+
index
615+
} else {
616+
usize::MAX
617+
}
618+
.serialize(serializer)
602619
}
603620
}
604621

605622
impl IpcSharedMemory {
623+
const fn empty() -> Self {
624+
Self {
625+
os_shared_memory: None,
626+
}
627+
}
628+
606629
/// Create shared memory initialized with the bytes provided.
607630
pub fn from_bytes(bytes: &[u8]) -> IpcSharedMemory {
608-
IpcSharedMemory {
609-
os_shared_memory: OsIpcSharedMemory::from_bytes(bytes),
631+
if bytes.is_empty() {
632+
IpcSharedMemory::empty()
633+
} else {
634+
IpcSharedMemory {
635+
os_shared_memory: Some(OsIpcSharedMemory::from_bytes(bytes)),
636+
}
610637
}
611638
}
612639

613640
/// Create a chunk of shared memory that is filled with the byte
614641
/// provided.
615642
pub fn from_byte(byte: u8, length: usize) -> IpcSharedMemory {
616-
IpcSharedMemory {
617-
os_shared_memory: OsIpcSharedMemory::from_byte(byte, length),
643+
if length == 0 {
644+
IpcSharedMemory::empty()
645+
} else {
646+
IpcSharedMemory {
647+
os_shared_memory: Some(OsIpcSharedMemory::from_byte(byte, length)),
648+
}
618649
}
619650
}
620651
}

src/test.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,26 @@ fn shared_memory() {
465465
.all(|byte| *byte == 0xba));
466466
}
467467

468+
#[test]
469+
fn shared_memory_slice() {
470+
let (tx, rx) = ipc::channel().unwrap();
471+
// test byte of size 0
472+
let shared_memory = IpcSharedMemory::from_byte(42, 0);
473+
tx.send(shared_memory.clone()).unwrap();
474+
let received_shared_memory = rx.recv().unwrap();
475+
assert_eq!(*received_shared_memory, *shared_memory);
476+
// test empty slice
477+
let shared_memory = IpcSharedMemory::from_bytes(&[]);
478+
tx.send(shared_memory.clone()).unwrap();
479+
let received_shared_memory = rx.recv().unwrap();
480+
assert_eq!(*received_shared_memory, *shared_memory);
481+
// test non-empty slice
482+
let shared_memory = IpcSharedMemory::from_bytes(&[4, 2, 42]);
483+
tx.send(shared_memory.clone()).unwrap();
484+
let received_shared_memory = rx.recv().unwrap();
485+
assert_eq!(*received_shared_memory, *shared_memory);
486+
}
487+
468488
#[test]
469489
#[cfg(any(
470490
not(target_os = "windows"),

0 commit comments

Comments
 (0)