1use core::ptr;
2
3use crate::{BitBuf, Error, Result, StorageMut, ensure};
4
5impl_write! {
6 u8;
7 bytes = 1;
8 bits = 8;
9 offset = 0;
10 [a];
11 [a, b];
12
13 write_u8_be_aligned_at_unchecked;
14 write_u8_be_aligned_unchecked;
15 write_u8_be_at_unchecked;
16 write_u8_be_unchecked;
17 try_write_u8_be_aligned_at;
18 try_write_u8_be_aligned;
19 try_write_u8_be_at;
20 try_write_u8_be;
21 write_u8_be_aligned_at;
22 write_u8_be_aligned;
23 write_u8_be_at;
24 write_u8_be;
25}
26
27impl_write! {
28 u16;
29 bytes = 2;
30 bits = 16;
31 offset = 1;
32 [a, b];
33 [a, [b], c];
34
35 write_u16_be_aligned_at_unchecked;
36 write_u16_be_aligned_unchecked;
37 write_u16_be_at_unchecked;
38 write_u16_be_unchecked;
39 try_write_u16_be_aligned_at;
40 try_write_u16_be_aligned;
41 try_write_u16_be_at;
42 try_write_u16_be;
43 write_u16_be_aligned_at;
44 write_u16_be_aligned;
45 write_u16_be_at;
46 write_u16_be;
47}
48
49impl_write! {
50 u32;
51 bytes = 4;
52 bits = 32;
53 offset = 3;
54 [a, b, c, d];
55 [a, [b, c, d], e];
56
57 write_u32_be_aligned_at_unchecked;
58 write_u32_be_aligned_unchecked;
59 write_u32_be_at_unchecked;
60 write_u32_be_unchecked;
61 try_write_u32_be_aligned_at;
62 try_write_u32_be_aligned;
63 try_write_u32_be_at;
64 try_write_u32_be;
65 write_u32_be_aligned_at;
66 write_u32_be_aligned;
67 write_u32_be_at;
68 write_u32_be;
69}
70
71impl_write! {
72 u64;
73 bytes = 8;
74 bits = 64;
75 offset = 7;
76 [a, b, c, d, e, f, g, h];
77 [a, [b, c, d, e, f, g, h], i];
78
79 write_u64_be_aligned_at_unchecked;
80 write_u64_be_aligned_unchecked;
81 write_u64_be_at_unchecked;
82 write_u64_be_unchecked;
83 try_write_u64_be_aligned_at;
84 try_write_u64_be_aligned;
85 try_write_u64_be_at;
86 try_write_u64_be;
87 write_u64_be_aligned_at;
88 write_u64_be_aligned;
89 write_u64_be_at;
90 write_u64_be;
91}
92
93impl_write! {
94 u128;
95 bytes = 16;
96 bits = 128;
97 offset = 15;
98 [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p];
99 [a, [b, c, d, e, f, g, h, i, j, k, l, m, n, o, p], q];
100
101 write_u128_be_aligned_at_unchecked;
102 write_u128_be_aligned_unchecked;
103 write_u128_be_at_unchecked;
104 write_u128_be_unchecked;
105 try_write_u128_be_aligned_at;
106 try_write_u128_be_aligned;
107 try_write_u128_be_at;
108 try_write_u128_be;
109 write_u128_be_aligned_at;
110 write_u128_be_aligned;
111 write_u128_be_at;
112 write_u128_be;
113}
114
115pub trait Write: Sized {
116 unsafe fn write_be_aligned_at_unchecked<S: StorageMut>(
117 buf: &mut BitBuf<S>,
118 byte_offset: usize,
119 v: Self,
120 ) -> &mut BitBuf<S>;
121
122 unsafe fn write_be_aligned_unchecked<S: StorageMut>(
123 buf: &mut BitBuf<S>,
124 v: Self,
125 ) -> &mut BitBuf<S>;
126
127 unsafe fn write_be_at_unchecked<S: StorageMut>(
128 buf: &mut BitBuf<S>,
129 offset: usize,
130 v: Self,
131 ) -> &mut BitBuf<S>;
132
133 unsafe fn write_be_unchecked<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> &mut BitBuf<S>;
134
135 fn try_write_be_aligned_at<S: StorageMut>(
136 buf: &mut BitBuf<S>,
137 byte_offset: usize,
138 v: Self,
139 ) -> Result<&mut BitBuf<S>>;
140
141 fn try_write_be_aligned<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> Result<&mut BitBuf<S>>;
142
143 fn try_write_be_at<S: StorageMut>(
144 buf: &mut BitBuf<S>,
145 offset: usize,
146 v: Self,
147 ) -> Result<&mut BitBuf<S>>;
148
149 fn try_write_be<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> Result<&mut BitBuf<S>>;
150
151 fn write_be_aligned_at<S: StorageMut>(
152 buf: &mut BitBuf<S>,
153 offset: usize,
154 v: Self,
155 ) -> &mut BitBuf<S>;
156
157 fn write_be_aligned<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> &mut BitBuf<S>;
158
159 fn write_be_at<S: StorageMut>(buf: &mut BitBuf<S>, offset: usize, v: Self) -> &mut BitBuf<S>;
160
161 fn write_be<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> &mut BitBuf<S>;
162}
163
164impl<S: StorageMut> BitBuf<S> {
165 #[inline(always)]
175 pub unsafe fn write_be_aligned_at_unchecked<T: Write>(
176 &mut self,
177 byte_offset: usize,
178 v: T,
179 ) -> &mut Self {
180 unsafe { T::write_be_aligned_at_unchecked(self, byte_offset, v) }
181 }
182
183 #[inline(always)]
193 pub unsafe fn write_be_aligned_unchecked<T: Write>(&mut self, v: T) -> &mut Self {
194 unsafe { T::write_be_aligned_unchecked(self, v) }
195 }
196
197 #[inline(always)]
207 pub unsafe fn write_be_at_unchecked<T: Write>(&mut self, offset: usize, v: T) -> &mut Self {
208 unsafe { T::write_be_at_unchecked(self, offset, v) }
209 }
210
211 #[inline(always)]
221 pub unsafe fn write_be_unchecked<T: Write>(&mut self, v: T) -> &mut Self {
222 unsafe { T::write_be_unchecked(self, v) }
223 }
224
225 #[inline(always)]
231 pub fn try_write_be_aligned_at<T: Write>(
232 &mut self,
233 byte_offset: usize,
234 v: T,
235 ) -> Result<&mut Self> {
236 T::try_write_be_aligned_at(self, byte_offset, v)
237 }
238
239 #[inline(always)]
245 pub fn try_write_be_aligned<T: Write>(&mut self, v: T) -> Result<&mut Self> {
246 T::try_write_be_aligned(self, v)
247 }
248
249 #[inline(always)]
255 pub fn try_write_be_at<T: Write>(&mut self, offset: usize, v: T) -> Result<&mut Self> {
256 T::try_write_be_at(self, offset, v)
257 }
258
259 #[inline(always)]
265 pub fn try_write_be<T: Write>(&mut self, v: T) -> Result<&mut Self> {
266 T::try_write_be(self, v)
267 }
268
269 #[inline(always)]
275 pub fn write_be_aligned_at<T: Write>(&mut self, byte_offset: usize, v: T) -> &mut Self {
276 T::write_be_aligned_at(self, byte_offset, v)
277 }
278
279 #[inline(always)]
285 pub fn write_be_aligned<T: Write>(&mut self, v: T) -> &mut Self {
286 T::write_be_aligned(self, v)
287 }
288
289 #[inline(always)]
295 pub fn write_be_at<T: Write>(&mut self, offset: usize, v: T) -> &mut Self {
296 T::write_be_at(self, offset, v)
297 }
298
299 #[inline(always)]
305 pub fn write_be<T: Write>(&mut self, v: T) -> &mut Self {
306 T::write_be(self, v)
307 }
308}
309
310macro_rules! impl_write {
311 (
312 $ty:ident;
313 bytes = $bytes:literal;
314 bits = $bits:literal;
315 offset = $offset:literal;
316 [$($byte:ident),*];
317 [$first:ident, $([$($middle:ident),*],)? $last:ident];
318
319 $write_be_aligned_at_unchecked:ident;
320 $write_be_aligned_unchecked:ident;
321 $write_be_at_unchecked:ident;
322 $write_be_unchecked:ident;
323 $try_write_be_aligned_at:ident;
324 $try_write_be_aligned:ident;
325 $try_write_be_at:ident;
326 $try_write_be:ident;
327 $write_be_aligned_at:ident;
328 $write_be_aligned:ident;
329 $write_be_at:ident;
330 $write_be:ident;
331 ) => {
332 impl<S: StorageMut> BitBuf<S> {
333
334 #[doc = concat!("Write a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order at `byte_offset` without performing bound checks")]
335 #[doc = concat!("* This is UB if <code>byte_offset + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
339 #[doc = concat!("* Panics in debug mode if <code>byte_offset + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
343 #[inline(always)]
344 pub unsafe fn $write_be_aligned_at_unchecked(&mut self, byte_offset: usize, v: $ty) -> &mut Self {
345 let bytes = self.bytes_mut();
346 let len = bytes.len();
347
348 ensure!(
349 byte_offset + $offset < len;
350
351 concat!(
352 "BitBuf::",
353 stringify!($write_be_aligned_at_unchecked),
354 ": index out of bounds! len is {}, offset is {}"
355 ),
356 len,
357 byte_offset + $offset,
358 );
359
360 let src_bytes = v.to_be_bytes();
361
362 #[allow(clippy::macro_metavars_in_unsafe)]
363 unsafe {
364 ptr::copy_nonoverlapping(
365 src_bytes.as_ptr(),
366 bytes.as_mut_ptr().add(byte_offset),
367 $bytes,
368 );
369 }
370
371 self
372 }
373
374 #[doc = concat!("Write the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order without performing bound checks, advancing the internal cursor")]
375 #[doc = concat!("* This is UB if <code>[self.byte_pos()][Self::byte_pos] + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
380 #[doc = concat!("* Panics in debug mode if <code>[self.byte_pos()][Self::byte_pos] + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
385 #[inline(always)]
386 pub unsafe fn $write_be_aligned_unchecked(&mut self, v: $ty) -> &mut Self {
387 ensure!(
388 self.is_aligned();
389
390 concat!(
391 "BitBuf::",
392 stringify!($write_be_aligned_unchecked),
393 " called at unaligned bit position: {}",
394 ),
395 self.pos(),
396 );
397
398 unsafe { self.$write_be_aligned_at_unchecked(self.byte_pos(), v) };
399 self.advance_bytes($bytes);
400 self
401 }
402
403 #[doc = concat!("Write a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order at `offset` without performing bound checks")]
404 #[doc = concat!("* This is UB if <code>(offset / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
408 #[doc = concat!("* This is UB if <code>(offset % 8 != 0) && (offset / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
409 #[doc = concat!("* Panics in debug mode if <code>(offset / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
413 #[doc = concat!("* Panics in debug mode if <code>(offset % 8 != 0) && (offset / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
414 #[inline(always)]
415 pub unsafe fn $write_be_at_unchecked(&mut self, offset: usize, v: $ty) -> &mut Self {
416 let byte_idx = offset / 8;
417 let shift = offset % 8;
418
419 let bytes = self.bytes_mut();
420 let len = bytes.len();
421
422 ensure!(
423 byte_idx + $offset < len;
424
425 concat!(
426 "BitBuf::",
427 stringify!($write_be_at_unchecked),
428 ": index out of bounds! len is {}, byte_idx is {}",
429 ),
430 len,
431 byte_idx + $offset,
432 );
433
434 if shift == 0 {
435 unsafe { self.$write_be_aligned_at_unchecked(byte_idx, v) };
436 } else {
437 ensure!(
438 byte_idx + $bytes < len;
439
440 concat!(
441 "BitBuf::",
442 stringify!($write_be_at_unchecked),
443 ": lookahead index out of bounds! len is {}, lookahead byte_idx is {}",
444 ),
445 len,
446 byte_idx + $bytes,
447 );
448
449 let src_bytes = v.to_be_bytes();
450
451 unsafe {
452 let mask = !0 << (8 - shift);
453 let b = bytes.get_unchecked(byte_idx) & mask;
454 let new = src_bytes[0] >> shift;
455 *bytes.get_unchecked_mut(byte_idx) = b | new;
456 }
457
458 $(
459 let mut i = 0;
460
461 #[expect(unused)]
462 unsafe {
463 $(
464 let $middle: ();
465 let hi = src_bytes[i];
466 let lo = src_bytes[i + 1];
467 *bytes.get_unchecked_mut(byte_idx + 1 + i) = hi << (8 - shift) | lo >> shift;
468 i += 1;
469 )*
470 }
471 )?
472
473 #[allow(clippy::macro_metavars_in_unsafe)]
474 unsafe {
475 let mask = !0 >> shift;
476 let b = bytes.get_unchecked(byte_idx + $bytes) & mask;
477 let new = src_bytes[$offset] << (8 - shift);
478 *bytes.get_unchecked_mut(byte_idx + $bytes) = b | new;
479 }
480 }
481
482 self
483 }
484
485 #[doc = concat!("Write the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order without performing bound checks, advancing the internal cursor")]
486 #[doc = concat!("* This is UB if <code>([self.pos()][Self::pos] / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
490 #[doc = concat!("* This is UB if <code>([self.pos()][Self::pos] % 8 != 0) && ([self.pos()][Self::pos] / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
491 #[doc = concat!("* Panics in debug mode if <code>([self.pos()][Self::pos] / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
495 #[doc = concat!("* Panics in debug mode if <code>([self.pos()][Self::pos] % 8 != 0) && ([self.pos()][Self::pos] / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
496 #[inline(always)]
497 pub unsafe fn $write_be_unchecked(&mut self, v: $ty) -> &mut Self {
498 unsafe { self.$write_be_at_unchecked(self.pos(), v) };
499 self.advance_bytes($bytes);
500 self
501 }
502
503 #[doc = concat!("Write a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order at `byte_offset` while performing bound checks")]
504 #[doc = concat!(" * if <code>byte_offset + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
509 #[inline(always)]
510 pub fn $try_write_be_aligned_at(&mut self, byte_offset: usize, v: $ty) -> Result<&mut Self> {
511 let len = self.bytes().len();
512
513 if byte_offset + $offset >= len {
514 return Err(Error::OutOfBounds);
515 }
516
517 Ok(unsafe { self.$write_be_aligned_at_unchecked(byte_offset, v) })
518 }
519
520 #[doc = concat!("Write the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order while performing alignment and bound checks, advancing the internal cursor")]
521 #[doc = concat!(" * if <code>[self.byte_pos()][Self::byte_pos] + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
528 #[inline(always)]
529 pub fn $try_write_be_aligned(&mut self, v: $ty) -> Result<&mut Self> {
530 if !self.is_aligned() {
531 return Err(Error::Unaligned);
532 }
533
534 self.$try_write_be_aligned_at(self.byte_pos(), v)?;
535 self.advance_bytes($bytes);
536 Ok(self)
537 }
538
539 #[doc = concat!("Write a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order at `offset` while performing bound checks")]
540 #[doc = concat!(" * if <code>(offset / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
545 #[doc = concat!(" * if <code>(offset % 8 != 0) && (offset / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
546 #[inline(always)]
547 pub fn $try_write_be_at(&mut self, offset: usize, v: $ty) -> Result<&mut Self> {
548 let byte_idx = offset / 8;
549 let shift = offset % 8;
550
551 let len = self.bytes().len();
552
553 if byte_idx + $offset >= len {
554 return Err(Error::OutOfBounds);
555 }
556
557 if shift != 0 && byte_idx + $bytes >= len {
558 return Err(Error::OutOfBounds);
559 }
560
561 Ok(unsafe { self.$write_be_at_unchecked(offset, v) })
562 }
563
564 #[doc = concat!("Write the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order while performing bound checks, advancing the internal cursor")]
565 #[doc = concat!(" * if <code>([self.pos()][Self::pos] / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
570 #[doc = concat!(" * if <code>([self.pos()][Self::pos] % 8 != 0) && ([self.pos()][Self::pos] / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
571 #[inline(always)]
572 pub fn $try_write_be(&mut self, v: $ty) -> Result<&mut Self> {
573 self.$try_write_be_at(self.pos(), v)?;
574 self.advance_bytes($bytes);
575 Ok(self)
576 }
577
578 #[doc = concat!("Write a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order at `byte_offset` panicking on out of bounds")]
579 #[doc = concat!("* Panics if <code>byte_offset + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
583 #[inline(always)]
584 pub fn $write_be_aligned_at(&mut self, byte_offset: usize, v: $ty) -> &mut Self {
585 self
586 .$try_write_be_aligned_at(byte_offset, v)
587 .expect(concat!("BitBuf::", stringify!($write_be_aligned_at), " out of bounds"))
588 }
589
590 #[doc = concat!("Write the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order panicking on an unaligned cursor or out of bounds, advancing the internal cursor")]
591 #[doc = concat!(" * if <code>[self.byte_pos()][Self::byte_pos] + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
596 #[inline(always)]
597 pub fn $write_be_aligned(&mut self, v: $ty) -> &mut Self {
598 self
599 .$try_write_be_aligned(v)
600 .expect(concat!("BitBuf::", stringify!($write_be_aligned), " unaligned cursor or out of bounds"))
601 }
602
603 #[doc = concat!("Write a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order at `offset` panicking on out of bounds")]
604 #[doc = concat!("* Panics if <code>(offset / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
608 #[doc = concat!("* Panics if <code>(offset % 8 != 0) && (offset / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
609 #[inline(always)]
610 pub fn $write_be_at(&mut self, offset: usize, v: $ty) -> &mut Self {
611 self
612 .$try_write_be_at(offset, v)
613 .expect(concat!("BitBuf::", stringify!($write_be_at), " out of bounds"))
614 }
615
616 #[doc = concat!("Write the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order panicking on out of bounds")]
617 #[doc = concat!("* Panics if <code>([self.pos()][Self::pos] / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
621 #[doc = concat!("* Panics if <code>([self.pos()][Self::pos] % 8 != 0) && ([self.pos()][Self::pos] / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
622 #[inline(always)]
623 pub fn $write_be(&mut self, v: $ty) -> &mut Self {
624 self
625 .$try_write_be(v)
626 .expect(concat!("BitBuf::", stringify!($write_be), " out of bounds"))
627 }
628 }
629
630 impl Write for $ty {
631 #[inline(always)]
632 unsafe fn write_be_aligned_at_unchecked<S: StorageMut>(
633 buf: &mut BitBuf<S>,
634 byte_offset: usize,
635 v: Self,
636 ) -> &mut BitBuf<S> {
637 unsafe { buf.$write_be_aligned_at_unchecked(byte_offset, v) }
638 }
639
640 #[inline(always)]
641 unsafe fn write_be_aligned_unchecked<S: StorageMut>(
642 buf: &mut BitBuf<S>,
643 v: Self,
644 ) -> &mut BitBuf<S> {
645 unsafe { buf.$write_be_aligned_unchecked(v) }
646 }
647
648 #[inline(always)]
649 unsafe fn write_be_at_unchecked<S: StorageMut>(
650 buf: &mut BitBuf<S>,
651 offset: usize,
652 v: Self,
653 ) -> &mut BitBuf<S> {
654 unsafe { buf.$write_be_at_unchecked(offset, v) }
655 }
656
657 #[inline(always)]
658 unsafe fn write_be_unchecked<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> &mut BitBuf<S> {
659 unsafe { buf.$write_be_unchecked(v) }
660 }
661
662 #[inline(always)]
663 fn try_write_be_aligned_at<S: StorageMut>(
664 buf: &mut BitBuf<S>,
665 byte_offset: usize,
666 v: Self,
667 ) -> Result<&mut BitBuf<S>> {
668 buf.$try_write_be_aligned_at(byte_offset, v)
669 }
670
671 #[inline(always)]
672 fn try_write_be_aligned<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> Result<&mut BitBuf<S>> {
673 buf.$try_write_be_aligned(v)
674 }
675
676 #[inline(always)]
677 fn try_write_be_at<S: StorageMut>(
678 buf: &mut BitBuf<S>,
679 offset: usize,
680 v: Self,
681 ) -> Result<&mut BitBuf<S>> {
682 buf.$try_write_be_at(offset, v)
683 }
684
685 #[inline(always)]
686 fn try_write_be<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> Result<&mut BitBuf<S>> {
687 buf.$try_write_be(v)
688 }
689
690 #[inline(always)]
691 fn write_be_aligned_at<S: StorageMut>(buf: &mut BitBuf<S>, byte_offset: usize, v: Self) -> &mut BitBuf<S> {
692 buf.$write_be_aligned_at(byte_offset, v)
693 }
694
695 #[inline(always)]
696 fn write_be_aligned<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> &mut BitBuf<S> {
697 buf.$write_be_aligned(v)
698 }
699
700 #[inline(always)]
701 fn write_be_at<S: StorageMut>(buf: &mut BitBuf<S>, offset: usize, v: Self) -> &mut BitBuf<S> {
702 buf.$write_be_at(offset, v)
703 }
704
705 #[inline(always)]
706 fn write_be<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> &mut BitBuf<S> {
707 buf.$write_be(v)
708 }
709 }
710 };
711}
712
713use impl_write;