1use crate::serialize::writer::*;
9use crate::serialize::writer_unchecked::*;
10use crate::valid_u32::*;
11use core::convert::Infallible;
12
13pub trait WriteXDR {
40 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()>;
45
46 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W);
68}
69
70#[inline]
86pub fn write_xdr<T, F, W>(this: &T, w: &mut W) -> WriteResult<()>
87where
88 T: WriteXDR,
89 W: Writer<F>,
90{
91 this.write_xdr(w)
92}
93
94#[inline]
105pub unsafe fn write_xdr_unchecked<T, F, W>(this: &T, w: &mut W)
106where
107 T: WriteXDR,
108 W: WriterUnchecked<F>,
109{
110 unsafe { this.write_xdr_unchecked(w) }
112}
113
114macro_rules! write_xdr_int_impls {
115 { $( $write_method:ident for $int_ty:ty ),* $(,)? } => { $(
116
117 impl WriteXDR for $int_ty {
118 #[inline]
119 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
120 w.$write_method(*self)
121 }
122
123 #[inline]
124 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
125 unsafe { w.$write_method(*self) }
127 }
128 }
129
130 )* };
131}
132
133write_xdr_int_impls! {
134 write_i64 for i64,
135 write_i32 for i32,
136 write_i16 for i16,
137
138 write_u64 for u64,
139 write_u32 for u32,
140 write_u16 for u16,
141
142 write_bool for bool,
143 write_f32 for f32,
144 write_f64 for f64,
145}
146
147impl WriteXDR for [u8] {
148 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
149 w.write_opaque_variable(self)
150 }
151
152 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
153 unsafe { w.write_opaque_variable(self) }
155 }
156}
157
158impl<const N: usize> WriteXDR for [u8; N] {
159 #[inline]
160 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
161 let () = ValidU32::<N>::OK;
162
163 w.write_opaque_fixed(self)
164 }
165
166 #[inline]
167 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
168 let () = ValidU32::<N>::OK;
169
170 unsafe { w.write_opaque_fixed(self) }
172 }
173}
174
175impl<T: WriteXDR, const N: usize> WriteXDR for [T; N] {
176 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
177 let () = ValidU32::<N>::OK;
178
179 for elt in self {
180 elt.write_xdr(w)?;
181 }
182 Ok(())
183 }
184
185 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
186 let () = ValidU32::<N>::OK;
187
188 for elt in self {
189 unsafe { elt.write_xdr_unchecked(w) };
191 }
192 }
193}
194
195impl<T: WriteXDR> WriteXDR for [T] {
196 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
197 if self.len() > u32::MAX as usize {
198 return Err(WriteError::InvalidArrayLength);
199 }
200 let len = self.len() as u32;
201 w.write_u32(len)?;
202
203 for elt in self {
204 elt.write_xdr(w)?;
205 }
206 Ok(())
207 }
208
209 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
210 debug_assert!(self.len() <= u32::MAX as usize);
211 unsafe {
214 w.write_u32(self.len() as u32);
215 for elt in self {
216 elt.write_xdr_unchecked(w);
217 }
218 }
219 }
220}
221
222impl<T: WriteXDR + ?Sized> WriteXDR for &T {
226 #[inline]
227 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
228 (*self).write_xdr(w)
229 }
230
231 #[inline]
232 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
233 unsafe { (*self).write_xdr_unchecked(w) }
235 }
236}
237
238impl<T: WriteXDR + ?Sized> WriteXDR for &mut T {
239 #[inline]
240 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
241 (**self).write_xdr(w)
242 }
243
244 #[inline]
245 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
246 unsafe { (**self).write_xdr_unchecked(w) }
248 }
249}
250
251impl WriteXDR for str {
252 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
253 w.write_opaque_variable(self.as_bytes())
254 }
255
256 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
257 unsafe { w.write_opaque_variable(self.as_bytes()) }
259 }
260}
261
262#[cfg(feature = "alloc")]
263#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
264impl WriteXDR for alloc::string::String {
265 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
266 self.as_str().write_xdr(w)
267 }
268
269 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
270 unsafe { self.as_str().write_xdr_unchecked(w) }
272 }
273}
274
275impl WriteXDR for () {
276 fn write_xdr<F, W: Writer<F>>(&self, _w: &mut W) -> WriteResult<()> {
277 Ok(())
278 }
279
280 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, _w: &mut W) {}
281}
282
283impl WriteXDR for Infallible {
284 fn write_xdr<F, W: Writer<F>>(&self, _w: &mut W) -> WriteResult<()> {
285 unreachable!()
286 }
287
288 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, _w: &mut W) {
289 match *self {}
290 }
291}
292
293macro_rules! write_tuple {
294 { $( ($v:ident, $t:ident) ),+ } => {
295
296 impl<$($t),+> WriteXDR for ($($t),+)
297 where
298 $( $t: WriteXDR, )+
299 {
300 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
301 let ( $($v),+ ) = self;
302 $( write_xdr($v, w)?; )+
303 Ok(())
304 }
305
306 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
307 let ( $($v),+ ) = self;
308 unsafe { $( write_xdr_unchecked($v, w); )+ }
310 }
311 }
312
313 };
314}
315
316write_tuple! { (t0, T0), (t1, T1) }
317write_tuple! { (t0, T0), (t1, T1), (t2, T2) }
318write_tuple! { (t0, T0), (t1, T1), (t2, T2), (t3, T3) }
319write_tuple! { (t0, T0), (t1, T1), (t2, T2), (t3, T3), (t4, T4) }
320write_tuple! { (t0, T0), (t1, T1), (t2, T2), (t3, T3), (t4, T4), (t5, T5) }
321write_tuple! { (t0, T0), (t1, T1), (t2, T2), (t3, T3), (t4, T4), (t5, T5), (t6, T6) }
322write_tuple! { (t0, T0), (t1, T1), (t2, T2), (t3, T3), (t4, T4), (t5, T5), (t6, T6), (t7, T7) }
323write_tuple! { (t0, T0), (t1, T1), (t2, T2), (t3, T3), (t4, T4), (t5, T5), (t6, T6), (t7, T7), (t8, T8) }
324write_tuple! { (t0, T0), (t1, T1), (t2, T2), (t3, T3), (t4, T4), (t5, T5), (t6, T6), (t7, T7), (t8, T8), (t9, T9) }
325write_tuple! { (t0, T0), (t1, T1), (t2, T2), (t3, T3), (t4, T4), (t5, T5), (t6, T6), (t7, T7), (t8, T8), (t9, T9), (t10, T10) }
326write_tuple! { (t0, T0), (t1, T1), (t2, T2), (t3, T3), (t4, T4), (t5, T5), (t6, T6), (t7, T7), (t8, T8), (t9, T9), (t10, T10), (t11, T11) }
327write_tuple! { (t0, T0), (t1, T1), (t2, T2), (t3, T3), (t4, T4), (t5, T5), (t6, T6), (t7, T7), (t8, T8), (t9, T9), (t10, T10), (t11, T11), (t12, T12) }
328write_tuple! { (t0, T0), (t1, T1), (t2, T2), (t3, T3), (t4, T4), (t5, T5), (t6, T6), (t7, T7), (t8, T8), (t9, T9), (t10, T10), (t11, T11), (t12, T12), (t13, T13) }
329write_tuple! { (t0, T0), (t1, T1), (t2, T2), (t3, T3), (t4, T4), (t5, T5), (t6, T6), (t7, T7), (t8, T8), (t9, T9), (t10, T10), (t11, T11), (t12, T12), (t13, T13), (t14, T14) }
330write_tuple! { (t0, T0), (t1, T1), (t2, T2), (t3, T3), (t4, T4), (t5, T5), (t6, T6), (t7, T7), (t8, T8), (t9, T9), (t10, T10), (t11, T11), (t12, T12), (t13, T13), (t14, T14), (t15, T15) }
331
332impl<T: WriteXDR> WriteXDR for (T,) {
334 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
335 let (t,) = self;
336 t.write_xdr(w)
337 }
338
339 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
340 let (t,) = self;
341 unsafe { t.write_xdr_unchecked(w) }
343 }
344}
345
346impl<T: WriteXDR> WriteXDR for Option<T> {
347 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
348 if let Some(val) = self {
349 w.write_i32(1)?;
350 val.write_xdr(w)
351 } else {
352 w.write_i32(0)
353 }
354 }
355
356 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
357 unsafe {
359 if let Some(val) = self {
360 w.write_i32(1);
361 val.write_xdr_unchecked(w);
362 } else {
363 w.write_i32(0);
364 }
365 }
366 }
367}
368
369const _: () = {
370 use super::*;
371 use crate::serialize::writer::Writer;
372 use crate::serialize::writer_unchecked::WriterUnchecked;
373 use xdr_common::*;
374
375 impl<const MAX: u32> WriteXDR for BytesM<MAX> {
376 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
377 if self.0.len() > MAX as usize {
378 return Err(WriteError::InvalidArrayLength);
379 }
380 self.0.write_xdr(w)
381 }
382
383 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
384 debug_assert!(
385 self.0.len() <= MAX as usize,
386 "BytesM exceeds declared bound"
387 );
388 unsafe { self.0.write_xdr_unchecked(w) }
391 }
392 }
393
394 #[cfg(feature = "alloc")]
396 impl<const MAX: u32> WriteXDR for VecM<u8, MAX> {
397 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
398 if self.0.len() > MAX as usize {
399 return Err(WriteError::InvalidArrayLength);
400 }
401 self.0.write_xdr(w)
402 }
403
404 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
405 debug_assert!(self.0.len() <= MAX as usize, "VecM exceeds declared bound");
406 unsafe { self.0.write_xdr_unchecked(w) }
409 }
410 }
411 #[cfg(not(feature = "alloc"))]
412 impl<const MAX: u32> WriteXDR for VecM<u8, MAX> {
413 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
414 if self.len() > MAX as usize {
415 return Err(WriteError::InvalidArrayLength);
416 }
417 <Self as AsRef<[u8]>>::as_ref(self).write_xdr(w)
418 }
419
420 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
421 debug_assert!(self.len() <= MAX as usize, "VecM exceeds declared bound");
422 unsafe { <Self as AsRef<[u8]>>::as_ref(self).write_xdr_unchecked(w) }
425 }
426 }
427
428 impl<const MAX: u32> WriteXDR for StringM<MAX> {
429 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
430 if self.0.len() > MAX as usize {
431 return Err(WriteError::InvalidArrayLength);
432 }
433 self.0.write_xdr(w)
434 }
435
436 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
437 debug_assert!(
438 self.0.len() <= MAX as usize,
439 "StringM exceeds declared bound"
440 );
441 unsafe { self.0.write_xdr_unchecked(w) }
444 }
445 }
446
447 #[cfg(feature = "alloc")]
448 impl<const MAX: u32, T> WriteXDR for VecM<T, MAX>
449 where
450 T: WriteXDR,
451 {
452 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
453 if self.len() > MAX as usize {
454 return Err(WriteError::InvalidArrayLength);
455 }
456 <Self as AsRef<[T]>>::as_ref(self).write_xdr(w)
457 }
458
459 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
460 debug_assert!(self.len() <= MAX as usize, "VecM exceeds declared bound");
461 unsafe { <Self as AsRef<[T]>>::as_ref(self).write_xdr_unchecked(w) }
464 }
465 }
466
467 #[cfg(not(feature = "alloc"))]
468 impl<const MAX: u32, T> WriteXDR for VecM<T, MAX>
469 where
470 T: WriteXDR + 'static,
471 {
472 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
473 if self.len() > MAX as usize {
474 return Err(WriteError::InvalidArrayLength);
475 }
476 <Self as AsRef<[T]>>::as_ref(self).write_xdr(w)
477 }
478
479 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
480 debug_assert!(self.len() <= MAX as usize, "VecM exceeds declared bound");
481 unsafe { <Self as AsRef<[T]>>::as_ref(self).write_xdr_unchecked(w) }
484 }
485 }
486
487 #[cfg(feature = "alloc")]
491 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
492 impl<T: WriteXDR + ?Sized> WriteXDR for alloc::boxed::Box<T> {
493 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
494 (**self).write_xdr(w)
495 }
496
497 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
498 unsafe { (**self).write_xdr_unchecked(w) }
500 }
501 }
502};
503
504#[cfg(not(feature = "alloc"))]
505impl<T: WriteXDR> WriteXDR for xdr_common::Box<T> {
506 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
507 (**self).write_xdr(w)
508 }
509
510 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
511 unsafe { (**self).write_xdr_unchecked(w) }
513 }
514}
515
516impl<T, E> WriteXDR for Result<T, E>
517where
518 T: WriteXDR,
519 E: WriteXDR,
520{
521 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
522 match self {
523 Ok(x) => {
524 w.write_i32(0)?;
525 x.write_xdr(w)
526 }
527 Err(e) => {
528 w.write_i32(1)?;
529 e.write_xdr(w)
530 }
531 }
532 }
533
534 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
535 unsafe {
537 match self {
538 Ok(x) => {
539 w.write_i32(0);
540 x.write_xdr_unchecked(w);
541 }
542 Err(e) => {
543 w.write_i32(1);
544 e.write_xdr_unchecked(w);
545 }
546 }
547 }
548 }
549}
550
551impl<T> WriteXDR for core::marker::PhantomData<T> {
552 fn write_xdr<F, W: Writer<F>>(&self, _w: &mut W) -> WriteResult<()> {
553 Ok(())
554 }
555
556 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, _w: &mut W) {}
557}
558
559#[cfg(feature = "alloc")]
560#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
561const _: () = {
562 use crate::serialize::writer_unchecked::WriterUnchecked;
563 use alloc::vec::Vec;
564
565 impl WriteXDR for Vec<u8> {
566 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
567 w.write_opaque_variable(self.as_ref())
568 }
569
570 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
571 unsafe { w.write_opaque_variable(self.as_ref()) }
573 }
574 }
575
576 impl<T> WriteXDR for Vec<T>
577 where
578 T: WriteXDR,
579 {
580 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
581 let slice: &[T] = self.as_ref();
582 slice.write_xdr(w)
583 }
584
585 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
586 let slice: &[T] = self.as_ref();
587 unsafe { slice.write_xdr_unchecked(w) }
589 }
590 }
591
592 #[cfg(target_has_atomic = "ptr")]
594 impl<T: WriteXDR + ?Sized> WriteXDR for alloc::sync::Arc<T> {
595 #[inline]
596 fn write_xdr<F, W: Writer<F>>(&self, w: &mut W) -> WriteResult<()> {
597 (**self).write_xdr(w)
598 }
599
600 #[inline]
601 unsafe fn write_xdr_unchecked<F, W: WriterUnchecked<F>>(&self, w: &mut W) {
602 unsafe { (**self).write_xdr_unchecked(w) }
604 }
605 }
606};
607
608#[cfg(test)]
609mod tests {
610 use super::*;
611 use core::mem::MaybeUninit;
612
613 #[test]
614 fn tuple_unchecked_writes_txs() {
615 let mut buf = [MaybeUninit::uninit(); 8];
616 let mut w = crate::txs::unchecked_buf_writer::UncheckedBufWriter::new(&mut buf);
617 unsafe { (1u32, 2u32).write_xdr_unchecked(&mut w) };
619 assert_eq!(w.written(), 8);
620 let bytes = unsafe { buf[..8].assume_init_ref() };
622 assert_eq!(bytes, [0, 0, 0, 1, 0, 0, 0, 2]);
623 }
624}