Skip to content

Commit 21b753c

Browse files
authored
Require Send for T in Queue instead of Copy (#75)
By requiring items to be `Copy` we reduce the queue to only work with primitives. What is more appropriate here is to require that the item is `Send` and use move semantics instead of copy.
1 parent 953b580 commit 21b753c

File tree

3 files changed

+87
-58
lines changed

3 files changed

+87
-58
lines changed

freertos-rust/src/patterns/processor.rs

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ pub trait ReplyableMessage {
1515
#[derive(Copy, Clone)]
1616
pub struct InputMessage<I>
1717
where
18-
I: Copy,
18+
I: Copy + Send,
1919
{
2020
val: I,
2121
reply_to_client_id: Option<usize>,
2222
}
2323

2424
impl<I> InputMessage<I>
2525
where
26-
I: Copy,
26+
I: Copy + Send,
2727
{
2828
pub fn request(val: I) -> Self {
2929
InputMessage {
@@ -46,7 +46,7 @@ where
4646

4747
impl<I> ReplyableMessage for InputMessage<I>
4848
where
49-
I: Copy,
49+
I: Copy + Send,
5050
{
5151
fn reply_to_client_id(&self) -> Option<usize> {
5252
self.reply_to_client_id
@@ -55,17 +55,17 @@ where
5555

5656
pub struct Processor<I, O>
5757
where
58-
I: ReplyableMessage + Copy,
59-
O: Copy,
58+
I: ReplyableMessage + Copy + Send,
59+
O: Copy + Send,
6060
{
6161
queue: Arc<Queue<I>>,
6262
inner: Arc<Mutex<ProcessorInner<O>>>,
6363
}
6464

6565
impl<I, O> Processor<I, O>
6666
where
67-
I: ReplyableMessage + Copy,
68-
O: Copy,
67+
I: ReplyableMessage + Copy + Send,
68+
O: Copy + Send,
6969
{
7070
pub fn new(queue_size: usize) -> Result<Self, FreeRtosError> {
7171
let p = ProcessorInner {
@@ -141,7 +141,10 @@ where
141141
.flat_map(|ref x| x.1.upgrade().into_iter())
142142
.find(|x| x.id == client_id)
143143
{
144-
client.receive_queue.send(reply, max_wait)?;
144+
client
145+
.receive_queue
146+
.send(reply, max_wait)
147+
.map_err(|err| err.error())?;
145148
return Ok(true);
146149
}
147150
}
@@ -152,8 +155,8 @@ where
152155

153156
impl<I, O> Processor<InputMessage<I>, O>
154157
where
155-
I: Copy,
156-
O: Copy,
158+
I: Copy + Send,
159+
O: Copy + Send,
157160
{
158161
pub fn reply_val<D: DurationTicks>(
159162
&self,
@@ -167,15 +170,15 @@ where
167170

168171
struct ProcessorInner<O>
169172
where
170-
O: Copy,
173+
O: Copy + Send,
171174
{
172175
clients: Vec<(usize, Weak<ClientWithReplyQueue<O>>)>,
173176
next_client_id: usize,
174177
}
175178

176179
impl<O> ProcessorInner<O>
177180
where
178-
O: Copy,
181+
O: Copy + Send,
179182
{
180183
fn remove_client_reply(&mut self, client: &ClientWithReplyQueue<O>) {
181184
self.clients.retain(|ref x| x.0 != client.id)
@@ -184,22 +187,24 @@ where
184187

185188
pub struct ProcessorClient<I, C>
186189
where
187-
I: ReplyableMessage + Copy,
190+
I: ReplyableMessage + Copy + Send,
188191
{
189192
processor_queue: Weak<Queue<I>>,
190193
client_reply: C,
191194
}
192195

193196
impl<I, O> ProcessorClient<I, O>
194197
where
195-
I: ReplyableMessage + Copy,
198+
I: ReplyableMessage + Copy + Send,
196199
{
197200
pub fn send<D: DurationTicks>(&self, message: I, max_wait: D) -> Result<(), FreeRtosError> {
198201
let processor_queue = self
199202
.processor_queue
200203
.upgrade()
201204
.ok_or(FreeRtosError::ProcessorHasShutDown)?;
202-
processor_queue.send(message, max_wait)?;
205+
processor_queue
206+
.send(message, max_wait)
207+
.map_err(|err| err.error())?;
203208
Ok(())
204209
}
205210

@@ -212,13 +217,15 @@ where
212217
.processor_queue
213218
.upgrade()
214219
.ok_or(FreeRtosError::ProcessorHasShutDown)?;
215-
processor_queue.send_from_isr(context, message)
220+
processor_queue
221+
.send_from_isr(context, message)
222+
.map_err(|err| err.error())
216223
}
217224
}
218225

219226
impl<I> ProcessorClient<InputMessage<I>, ()>
220227
where
221-
I: Copy,
228+
I: Copy + Send,
222229
{
223230
pub fn send_val<D: DurationTicks>(&self, val: I, max_wait: D) -> Result<(), FreeRtosError> {
224231
self.send(InputMessage::request(val), max_wait)
@@ -235,8 +242,8 @@ where
235242

236243
impl<I, O> ProcessorClient<I, SharedClientWithReplyQueue<O>>
237244
where
238-
I: ReplyableMessage + Copy,
239-
O: Copy,
245+
I: ReplyableMessage + Copy + Send,
246+
O: Copy + Send,
240247
{
241248
pub fn call<D: DurationTicks>(&self, message: I, max_wait: D) -> Result<O, FreeRtosError> {
242249
self.send(message, max_wait)?;
@@ -250,8 +257,8 @@ where
250257

251258
impl<I, O> ProcessorClient<InputMessage<I>, SharedClientWithReplyQueue<O>>
252259
where
253-
I: Copy,
254-
O: Copy,
260+
I: Copy + Send,
261+
O: Copy + Send,
255262
{
256263
pub fn send_val<D: DurationTicks>(&self, val: I, max_wait: D) -> Result<(), FreeRtosError> {
257264
self.send(InputMessage::request(val), max_wait)
@@ -268,7 +275,7 @@ where
268275

269276
impl<I, C> Clone for ProcessorClient<I, C>
270277
where
271-
I: ReplyableMessage + Copy,
278+
I: ReplyableMessage + Copy + Send,
272279
C: Clone,
273280
{
274281
fn clone(&self) -> Self {
@@ -281,7 +288,7 @@ where
281288

282289
pub struct ClientWithReplyQueue<O>
283290
where
284-
O: Copy,
291+
O: Copy + Send,
285292
{
286293
id: usize,
287294
processor_inner: Arc<Mutex<ProcessorInner<O>>>,
@@ -290,7 +297,7 @@ where
290297

291298
impl<O> Drop for ClientWithReplyQueue<O>
292299
where
293-
O: Copy,
300+
O: Copy + Send,
294301
{
295302
fn drop(&mut self) {
296303
if let Ok(mut p) = self.processor_inner.lock(Duration::ms(1000)) {

freertos-rust/src/patterns/pub_sub.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@ use crate::queue::*;
55
use crate::units::*;
66

77
/// A pub-sub queue. An item sent to the publisher is sent to every subscriber.
8-
pub struct QueuePublisher<T: Sized + Copy> {
8+
pub struct QueuePublisher<T: Sized + Copy + Send> {
99
inner: Arc<Mutex<PublisherInner<T>>>,
1010
}
1111

1212
/// A subscribtion to the publisher.
13-
pub struct QueueSubscriber<T: Sized + Copy> {
13+
pub struct QueueSubscriber<T: Sized + Copy + Send> {
1414
inner: Arc<SubscriberInner<T>>,
1515
}
1616

17-
impl<T: Sized + Copy> QueuePublisher<T> {
17+
impl<T: Sized + Copy + Send> QueuePublisher<T> {
1818
/// Create a new publisher
1919
pub fn new() -> Result<QueuePublisher<T>, FreeRtosError> {
2020
let inner = PublisherInner {
@@ -69,41 +69,41 @@ impl<T: Sized + Copy> QueuePublisher<T> {
6969
}
7070
}
7171

72-
impl<T: Sized + Copy> Clone for QueuePublisher<T> {
72+
impl<T: Sized + Copy + Send> Clone for QueuePublisher<T> {
7373
fn clone(&self) -> Self {
7474
QueuePublisher {
7575
inner: self.inner.clone(),
7676
}
7777
}
7878
}
7979

80-
impl<T: Sized + Copy> Drop for QueueSubscriber<T> {
80+
impl<T: Sized + Copy + Send> Drop for QueueSubscriber<T> {
8181
fn drop(&mut self) {
8282
if let Ok(mut l) = self.inner.publisher.lock(Duration::infinite()) {
8383
l.unsubscribe(&self.inner);
8484
}
8585
}
8686
}
8787

88-
impl<T: Sized + Copy> QueueSubscriber<T> {
88+
impl<T: Sized + Copy + Send> QueueSubscriber<T> {
8989
/// Wait for an item to be posted from the publisher.
9090
pub fn receive<D: DurationTicks>(&self, max_wait: D) -> Result<T, FreeRtosError> {
9191
self.inner.queue.receive(max_wait)
9292
}
9393
}
9494

95-
struct PublisherInner<T: Sized + Copy> {
95+
struct PublisherInner<T: Sized + Copy + Send> {
9696
subscribers: Vec<Arc<SubscriberInner<T>>>,
9797
queue_next_id: usize,
9898
}
9999

100-
impl<T: Sized + Copy> PublisherInner<T> {
100+
impl<T: Sized + Copy + Send> PublisherInner<T> {
101101
fn unsubscribe(&mut self, subscriber: &SubscriberInner<T>) {
102102
self.subscribers.retain(|ref x| x.id != subscriber.id);
103103
}
104104
}
105105

106-
struct SubscriberInner<T: Sized + Copy> {
106+
struct SubscriberInner<T: Sized + Copy + Send> {
107107
id: usize,
108108
queue: Queue<T>,
109109
publisher: Arc<Mutex<PublisherInner<T>>>,

freertos-rust/src/queue.rs

Lines changed: 47 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,39 @@
1+
use mem::ManuallyDrop;
2+
use mem::MaybeUninit;
3+
14
use crate::base::*;
25
use crate::isr::*;
36
use crate::prelude::v1::*;
47
use crate::shim::*;
58
use crate::units::*;
69

7-
unsafe impl<T: Sized + Copy> Send for Queue<T> {}
8-
unsafe impl<T: Sized + Copy> Sync for Queue<T> {}
10+
unsafe impl<T: Sized + Send> Send for Queue<T> {}
11+
unsafe impl<T: Sized + Send> Sync for Queue<T> {}
12+
13+
#[derive(Debug)]
14+
pub struct SendError<T> {
15+
err: FreeRtosError,
16+
item: T,
17+
}
18+
19+
impl<T> SendError<T> {
20+
pub fn error(&self) -> FreeRtosError {
21+
self.err
22+
}
23+
24+
pub fn into_item(self) -> T {
25+
self.item
26+
}
27+
}
928

10-
/// A queue with a finite size. The items are owned by the queue and are
11-
/// copied.
29+
/// A queue with a finite size.
1230
#[derive(Debug)]
13-
pub struct Queue<T: Sized + Copy> {
31+
pub struct Queue<T: Sized + Send> {
1432
queue: FreeRtosQueueHandle,
1533
item_type: PhantomData<T>,
1634
}
1735

18-
impl<T: Sized + Copy> Queue<T> {
36+
impl<T: Sized + Send> Queue<T> {
1937
pub fn new(max_size: usize) -> Result<Queue<T>, FreeRtosError> {
2038
let item_size = mem::size_of::<T>();
2139

@@ -49,15 +67,16 @@ impl<T: Sized + Copy> Queue<T> {
4967
}
5068

5169
/// Send an item to the end of the queue. Wait for the queue to have empty space for it.
52-
pub fn send<D: DurationTicks>(&self, item: T, max_wait: D) -> Result<(), FreeRtosError> {
70+
pub fn send<D: DurationTicks>(&self, item: T, max_wait: D) -> Result<(), SendError<T>> {
71+
let item = ManuallyDrop::new(item);
72+
let ptr = &item as *const _ as FreeRtosVoidPtr;
73+
5374
unsafe {
54-
if freertos_rs_queue_send(
55-
self.queue,
56-
&item as *const _ as FreeRtosVoidPtr,
57-
max_wait.to_ticks(),
58-
) != 0
59-
{
60-
Err(FreeRtosError::QueueSendTimeout)
75+
if freertos_rs_queue_send(self.queue, ptr, max_wait.to_ticks()) != 0 {
76+
Err(SendError {
77+
err: FreeRtosError::QueueSendTimeout,
78+
item: ManuallyDrop::into_inner(item),
79+
})
6180
} else {
6281
Ok(())
6382
}
@@ -69,15 +88,16 @@ impl<T: Sized + Copy> Queue<T> {
6988
&self,
7089
context: &mut InterruptContext,
7190
item: T,
72-
) -> Result<(), FreeRtosError> {
91+
) -> Result<(), SendError<T>> {
92+
let item = ManuallyDrop::new(item);
93+
let ptr = &item as *const _ as FreeRtosVoidPtr;
94+
7395
unsafe {
74-
if freertos_rs_queue_send_isr(
75-
self.queue,
76-
&item as *const _ as FreeRtosVoidPtr,
77-
context.get_task_field_mut(),
78-
) != 0
79-
{
80-
Err(FreeRtosError::QueueFull)
96+
if freertos_rs_queue_send_isr(self.queue, ptr, context.get_task_field_mut()) != 0 {
97+
Err(SendError {
98+
err: FreeRtosError::QueueFull,
99+
item: ManuallyDrop::into_inner(item),
100+
})
81101
} else {
82102
Ok(())
83103
}
@@ -87,14 +107,16 @@ impl<T: Sized + Copy> Queue<T> {
87107
/// Wait for an item to be available on the queue.
88108
pub fn receive<D: DurationTicks>(&self, max_wait: D) -> Result<T, FreeRtosError> {
89109
unsafe {
90-
let mut buff = mem::zeroed::<T>();
110+
// Use `MaybeUninit` to avoid calling drop on
111+
// uninitialized struct in case of timeout
112+
let mut buff = MaybeUninit::uninit();
91113
let r = freertos_rs_queue_receive(
92114
self.queue,
93115
&mut buff as *mut _ as FreeRtosMutVoidPtr,
94116
max_wait.to_ticks(),
95117
);
96118
if r == 0 {
97-
return Ok(buff);
119+
return Ok(buff.assume_init());
98120
} else {
99121
return Err(FreeRtosError::QueueReceiveTimeout);
100122
}
@@ -107,7 +129,7 @@ impl<T: Sized + Copy> Queue<T> {
107129
}
108130
}
109131

110-
impl<T: Sized + Copy> Drop for Queue<T> {
132+
impl<T: Sized + Send> Drop for Queue<T> {
111133
fn drop(&mut self) {
112134
unsafe {
113135
freertos_rs_queue_delete(self.queue);

0 commit comments

Comments
 (0)