sledgehammer/
channel.rs

1//! This module contains the [`MsgChannel`] type which is used to send batched dom manipulation operations.
2//! The main way to add operations to a [`MsgChannel`] is by dirrectly calling the methods on it, and then calling [`MsgChannel::flush`] to send the operations to the browser.
3//!
4//!
5
6use std::{fmt::Arguments, io::Write};
7
8use web_sys::Node;
9
10use crate::{
11    batch::{Batch, Op, PreparedBatch},
12    last_needs_memory, update_last_memory, work_last_created, ElementBuilder, IntoAttribue,
13    IntoElement, JsInterpreter, MSG_METADATA_PTR, MSG_PTR_PTR, STR_LEN_PTR, STR_PTR_PTR,
14};
15
16/// Tracks if a interpreter has been created. Used to prevent multiple interpreters from being created.
17static mut INTERPRETER_EXISTS: bool = false;
18
19/// An id that may be either the last node or a node with an assigned id.
20#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
21pub enum MaybeId {
22    /// The last node that was created or navigated to.
23    LastNode,
24    /// A node that was created and stored with an id
25    Node(NodeId),
26}
27
28impl MaybeId {
29    #[inline(always)]
30    pub(crate) const fn encoded_size(&self) -> u8 {
31        match self {
32            MaybeId::LastNode => 0,
33            MaybeId::Node(_) => 4,
34        }
35    }
36}
37
38/// A node that was created and stored with an id
39/// It is recommended to create and store ids with a slab allocator with an exposed slab index for example the excellent [slab](https://docs.rs/slab) crate.
40#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
41pub struct NodeId(pub u32);
42
43/// The [`MsgChannel`] handles communication with the dom. It allows you to send batched operations to the dom.
44/// All of the functions that are not marked otherwise are qued and not exicuted imidately. When you want to exicute the que you have to call [`MsgChannel::flush`].
45/// There should only be one [`MsgChannel`] per application.
46pub struct MsgChannel {
47    pub(crate) js_interpreter: JsInterpreter,
48    batch: Batch,
49}
50
51impl Default for MsgChannel {
52    fn default() -> Self {
53        unsafe {
54            assert!(
55                !INTERPRETER_EXISTS,
56                "Found another MsgChannel. Only one MsgChannel can be created"
57            );
58            INTERPRETER_EXISTS = true;
59        }
60        debug_assert!(0x1F > Op::NoOp as u8);
61        format!(
62            "init: {:?}, {:?}, {:?}",
63            unsafe { MSG_PTR_PTR as usize },
64            unsafe { STR_PTR_PTR as usize },
65            unsafe { STR_LEN_PTR as usize }
66        );
67        let js_interpreter = unsafe {
68            JsInterpreter::new(
69                wasm_bindgen::memory(),
70                MSG_METADATA_PTR as usize,
71                MSG_PTR_PTR as usize,
72                STR_PTR_PTR as usize,
73                STR_LEN_PTR as usize,
74            )
75        };
76
77        Self {
78            js_interpreter,
79            batch: Batch::default(),
80        }
81    }
82}
83
84impl MsgChannel {
85    /// IMPORTANT: This method is exicuted immediatly and does not wait for the next flush
86    ///
87    /// Example:
88    /// ```no_run
89    /// let window = web_sys::window().unwrap();
90    /// let document = window.document().unwrap();
91    /// let body = document.body().unwrap();
92    /// let mut channel = MsgChannel::default();
93    /// // assign the NodeId(0) to the body element from web-sys
94    /// channel.set_node(NodeId(0), JsCast::dyn_into(body).unwrap());
95    /// // no need to call flush here because set_node is exicuted immediatly
96    /// ```
97    pub fn set_node(&mut self, id: NodeId, node: Node) {
98        self.js_interpreter.SetNode(id.0, node);
99    }
100
101    /// IMPORTANT: This method is exicuted immediatly and does not wait for the next flush
102    ///
103    /// Example:
104    /// ```no_run
105    /// let mut channel = MsgChannel::default();
106    /// channel.create_element("div", Some(NodeId(0)));
107    /// channel.flush();
108    /// let element = channel.get_node(NodeId(0));
109    /// let text = element.text_content().map(|t| t + " + web-sys");
110    /// element.set_text_content(text.as_deref());
111    /// // no need to call flush here because get_node is exicuted immediatly
112    /// ```
113    pub fn get_node(&mut self, id: NodeId) -> Node {
114        self.js_interpreter.GetNode(id.0)
115    }
116
117    /// Exicutes any queued operations in the order they were added
118    ///
119    /// Example:
120    ///
121    /// ```no_run
122    /// let mut channel = MsgChannel::default();
123    /// // this does not immediatly create a <div> or <p>
124    /// channel.create_element("div", None);
125    /// channel.create_element("p", None);
126    /// // this creates the <div> and <p> elements
127    /// channel.flush();
128    /// ```
129    pub fn flush(&mut self) {
130        self.batch.encode_op(Op::Stop);
131        run_batch(&self.batch.msg, &self.batch.str_buf);
132        self.batch.msg.clear();
133        self.batch.current_op_batch_idx = 0;
134        self.batch.current_op_byte_idx = 3;
135        self.batch.str_buf.clear();
136    }
137
138    /// Appends a number of nodes as children of the given node.
139    ///
140    /// Example:
141    ///
142    /// ```no_run
143    /// let mut channel = MsgChannel::default();
144    /// channel.create_element("div", Some(NodeId(0)));
145    /// channel.create_element("p", None);
146    /// // append the <p> element to the <div> element
147    /// channel.append_child(MaybeId::Node(NodeId(0)), MaybeId::LastNode);
148    /// channel.flush();
149    /// ```
150    pub fn append_child(&mut self, root: MaybeId, child: MaybeId) {
151        self.batch.append_child(root, child)
152    }
153
154    /// Replace a node with another node
155    ///
156    /// Example:
157    /// ```no_run
158    /// let mut channel = MsgChannel::default();
159    /// channel.create_element("div", Some(NodeId(0)));
160    /// channel.create_element("p", None);
161    /// // replace the <p> element with the <div> element
162    /// channel.replace_with(MaybeId::Node(NodeId(0)), MaybeId::LastNode);
163    /// channel.flush();
164    /// ```
165    pub fn replace_with(&mut self, root: MaybeId, node: MaybeId) {
166        self.batch.replace_with(root, node)
167    }
168
169    /// Insert a single node after a given node.
170    ///
171    /// Example:
172    /// ```no_run
173    /// let mut channel = MsgChannel::default();
174    /// channel.create_element("div", Some(NodeId(0)));
175    /// channel.create_element("p", None);
176    /// // insert the <p> element after the <div> element
177    /// channel.insert_after(MaybeId::Node(NodeId(0)), MaybeId::LastNode);
178    /// channel.flush();
179    /// ```
180    pub fn insert_after(&mut self, root: MaybeId, node: MaybeId) {
181        self.batch.insert_after(root, node)
182    }
183
184    /// Insert a single node before a given node.
185    ///
186    /// Example:
187    /// ```no_run
188    /// let mut channel = MsgChannel::default();
189    /// channel.create_element("div", Some(NodeId(0)));
190    /// channel.create_element("p", None);
191    /// // insert the <p> element before the <div> element
192    /// channel.insert_before(MaybeId::Node(NodeId(0)), MaybeId::LastNode);
193    /// channel.flush();
194    /// ```
195    pub fn insert_before(&mut self, root: MaybeId, node: MaybeId) {
196        self.batch.insert_before(root, node)
197    }
198
199    /// Remove a node from the DOM.
200    ///
201    /// Example:
202    /// ```no_run
203    /// let mut channel = MsgChannel::default();
204    /// channel.create_element("p", None);
205    /// // remove the <p> element
206    /// channel.remove(MaybeId::LastNode);
207    /// channel.flush();
208    /// ```
209    pub fn remove(&mut self, id: MaybeId) {
210        self.batch.remove(id)
211    }
212
213    /// Create a new text node
214    ///
215    /// Example:
216    /// ```no_run
217    /// let mut channel = MsgChannel::default();
218    /// // create a text node with the text "Hello World"
219    /// channel.create_text_node("Hello World", None);
220    /// channel.flush();
221    pub fn create_text_node(&mut self, text: impl WritableText, id: MaybeId) {
222        self.batch.create_text_node(text, id)
223    }
224
225    /// Create a new element node
226    ///
227    /// Example:
228    /// ```no_run
229    /// let mut channel = MsgChannel::default();
230    /// // create a <div> element
231    /// channel.create_element("div", None);
232    /// channel.flush();
233    /// ```
234    pub fn create_element<'a, 'b>(&mut self, tag: impl IntoElement<'a, 'b>, id: Option<NodeId>) {
235        self.batch.create_element(tag, id)
236    }
237
238    /// Set the textcontent of a node.
239    ///
240    /// Example:
241    /// ```no_run
242    /// let mut channel = MsgChannel::default();
243    /// // create a text node with the text "Hello World"
244    /// channel.create_text_node("Hello ", None);
245    /// // set the text content of the text node to "Hello World!!!"
246    /// channel.set_text_content("World!!!", MaybeId::LastNode);
247    /// channel.flush();
248    /// ```
249    pub fn set_text(&mut self, text: impl WritableText, root: MaybeId) {
250        self.batch.set_text(text, root)
251    }
252
253    /// Set the value of a node's attribute.
254    ///
255    /// Example:
256    /// ```no_run
257    /// let mut channel = MsgChannel::default();
258    /// // create a <div> element
259    /// channel.create_element("div", None);
260    /// // set the attribute "id" to "my-div" on the <div> element
261    /// channel.set_attribute(Attribute::id, "my-div", MaybeId::LastNode);
262    /// channel.flush();
263    /// ```
264    pub fn set_attribute<'a, 'b>(
265        &mut self,
266        attr: impl IntoAttribue<'a, 'b>,
267        value: impl WritableText,
268        root: MaybeId,
269    ) {
270        self.batch.set_attribute(attr, value, root)
271    }
272
273    /// Remove an attribute from a node.
274    ///
275    /// Example:
276    /// ```no_run
277    /// let mut channel = MsgChannel::default();
278    /// // create a <div> element
279    /// channel.create_element("div", None);
280    /// channel.set_attribute(Attribute::id, "my-div", MaybeId::LastNode);
281    /// // remove the attribute "id" from the <div> element
282    /// channel.remove_attribute(Attribute::id, MaybeId::LastNode);
283    /// channel.flush();
284    /// ```
285    pub fn remove_attribute<'a, 'b>(&mut self, attr: impl IntoAttribue<'a, 'b>, root: MaybeId) {
286        self.batch.remove_attribute(attr, root)
287    }
288
289    /// Clone a node and store it with a new id.
290    ///
291    /// Example:
292    /// ```no_run
293    /// let mut channel = MsgChannel::default();
294    /// // create a <div> element
295    /// channel.create_element("div", None);
296    /// // clone the <div> element and store it with the id 1
297    /// channel.clone_node(MaybeId::LastNode, Some(NodeId(1)));
298    /// channel.flush();
299    /// ```
300    pub fn clone_node(&mut self, id: MaybeId, new_id: MaybeId) {
301        self.batch.clone_node(id, new_id)
302    }
303
304    /// Move the last node to the first child
305    ///
306    /// Example:
307    /// ```no_run
308    /// let mut channel = MsgChannel::default();
309    /// // create a element: <div><p></p></div>
310    /// channel.build_full_element(
311    ///     ElementBuilder::new("div".into())
312    ///         .children(&[
313    ///             ElementBuilder::new(Element::p.into())
314    ///                 .into(),
315    ///         ]),
316    /// );
317    /// // move from the <div> to the <p>
318    /// channel.first_child();
319    /// // operatons modifing the <p> element...
320    /// channel.flush();
321    /// ```
322    pub fn first_child(&mut self) {
323        self.batch.first_child()
324    }
325
326    /// Move the last node to the next sibling
327    ///
328    /// Example:
329    /// ```no_run
330    /// let mut channel = MsgChannel::default();
331    /// // create a element: <div><h1></h1><p></p></div>
332    /// channel.build_full_element(
333    ///     ElementBuilder::new("div".into())
334    ///         .children(&[
335    ///             ElementBuilder::new(Element::h1.into())
336    ///                 .into(),
337    ///             ElementBuilder::new(Element::p.into())
338    ///         ]),
339    /// );
340    /// // move from the <div> to the <h1>
341    /// channel.first_child();
342    /// // move from the <h1> to the <p>
343    /// channel.next_sibling();
344    /// // operatons modifing the <p> element...
345    /// channel.flush();
346    /// ```
347    pub fn next_sibling(&mut self) {
348        self.batch.next_sibling()
349    }
350
351    /// Move the last node to the parent node
352    ///
353    /// Example:
354    /// ```no_run
355    /// let mut channel = MsgChannel::default();
356    /// // create a element: <div><p></p></div>
357    /// channel.build_full_element(
358    ///     ElementBuilder::new("div".into())
359    ///         .children(&[
360    ///             ElementBuilder::new(Element::p.into())
361    ///                 .id(NodeId(0))
362    ///                 .into(),
363    ///         ]),
364    /// );
365    /// // move to the <p> element
366    /// channel.set_last_node(NodeId(0));
367    /// // move from the <p> to the <div>
368    /// channel.parent_node();
369    /// // operatons modifing the <p> element...
370    /// channel.flush();
371    /// ```
372    pub fn parent_node(&mut self) {
373        self.batch.parent_node()
374    }
375
376    /// Store the last node with the given id. This is useful when traversing the document tree.
377    ///
378    /// Example:
379    /// ```no_run
380    /// let mut channel = MsgChannel::default();
381    /// // create a element without an id
382    /// channel.create_element("div", None);
383    /// // store the <div> element with the id 0
384    /// channel.set_last_node(NodeId(0));
385    /// channel.flush();
386    /// ```
387    pub fn store_with_id(&mut self, id: NodeId) {
388        self.batch.store_with_id(id)
389    }
390
391    /// Set the last node to the given id. The last node can be used to traverse the document tree without passing objects between wasm and js every time.
392    ///
393    /// Example:
394    /// ```no_run
395    /// let mut channel = MsgChannel::default();
396    /// // create a element: <div><h1><h2></h2></h1><p></p></div>
397    /// channel.build_full_element(
398    ///     ElementBuilder::new("div".into())
399    ///         .children(&[
400    ///             ElementBuilder::new(Element::h1.into())
401    ///                 .children(&[
402    ///                     ElementBuilder::new(Element::h2.into())
403    ///                         .into(),
404    ///                 ]).into(),
405    ///             ElementBuilder::new(Element::p.into())
406    ///                 .into(),
407    ///         ]),
408    /// );
409    /// // move from the <div> to the <h1>
410    /// channel.first_child();
411    /// // store the <h1> element with the id 0
412    /// channel.store_with_id(NodeId(0));
413    /// // move from the <h1> to the <h2>
414    /// channel.first_child();
415    /// // update something in the <h2> element...
416    /// // restore the <h1> element
417    /// channel.set_last_node(NodeId(0));
418    /// // move from the <h1> to the <p>
419    /// channel.next_sibling();
420    /// // operatons modifing the <p> element...
421    /// channel.flush();
422    /// ```
423    pub fn set_last_node(&mut self, id: NodeId) {
424        self.batch.set_last_node(id)
425    }
426
427    /// Build a full element, slightly more efficent than creating the element creating the element with `create_element` and then setting the attributes.
428    ///
429    /// Example:
430    /// ```rust
431    /// let mut channel = MsgChannel::default();
432    /// // create an element using sledgehammer
433    /// channel.build_full_element(
434    ///     ElementBuilder::new("div".into())
435    ///         .id(NodeId(0))
436    ///         .attrs(&[(Attribute::style.into(), "color: blue")])
437    ///         .children(&[
438    ///             ElementBuilder::new(Element::p.into())
439    ///                 .into(),
440    ///             TextBuilder::new("Hello from sledgehammer!").into(),
441    ///         ]),
442    /// );
443    /// channel.flush();
444    /// ```
445    pub fn build_full_element(&mut self, el: ElementBuilder) {
446        self.batch.build_full_element(el)
447    }
448
449    /// Set a style property on a node.
450    ///
451    /// Example:
452    /// ```rust
453    /// let mut channel = MsgChannel::default();
454    /// channel.create_element("div", None);
455    /// // set the style property "color" to "blue"
456    /// channel.set_style("color", "blue", MaybeId::LastNode);
457    /// channel.flush();
458    /// ```
459    pub fn set_style(&mut self, style: &str, value: &str, id: MaybeId) {
460        self.batch.set_style(style, value, id)
461    }
462
463    /// Remove a style property from a node.
464    ///
465    /// Example:
466    /// ```rust
467    /// let mut channel = MsgChannel::default();
468    /// channel.create_element("div", None);
469    /// channel.set_style("color", "blue", MaybeId::LastNode);
470    /// // remove the color style
471    /// channel.remove_style("color", MaybeId::LastNode);
472    /// channel.flush();
473    /// ```
474    pub fn remove_style(&mut self, style: &str, id: MaybeId) {
475        self.batch.remove_style(style, id)
476    }
477
478    /// Adds a batch of operations to the current batch.
479    ///
480    /// Example:
481    /// ```rust
482    /// let mut channel = MsgChannel::default();
483    /// let mut batch = Batch::default();
484    /// batch.create_element("div", None);
485    /// // add the batch to the channel
486    /// channel.append(batch);
487    /// channel.flush();
488    /// ```
489    pub fn append(&mut self, batch: Batch) {
490        self.batch.append(batch);
491    }
492
493    /// IMPORTANT: This method is exicuted immediatly and does not wait for the next flush
494    ///
495    /// Run a batch of operations on the DOM immediately. This only runs the operations that are in the batch, not the operations that are queued in the [`MsgChannel`].
496    ///
497    /// Example:
498    /// ```rust
499    /// let mut channel = MsgChannel::default();
500    /// let mut batch = Batch::default();
501    /// batch.create_element("div", None);
502    /// // add the batch to the channel
503    /// channel.run_batch(&batch.finalize());
504    /// ```
505    pub fn run_batch(&mut self, batch: impl PreparedBatch) {
506        run_batch(batch.msg(), batch.str());
507    }
508}
509
510fn run_batch(msg: &[u8], str_buf: &[u8]) {
511    debug_assert_eq!(0usize.to_le_bytes().len(), 32 / 8);
512    let msg_ptr = msg.as_ptr() as usize;
513    let str_ptr = str_buf.as_ptr() as usize;
514    // the pointer will only be updated when the message vec is resized, so we have a flag to check if the pointer has changed to avoid unnecessary decoding
515    if unsafe { *MSG_METADATA_PTR } == 255 {
516        // this is the first message, so we need to encode all the metadata
517        unsafe {
518            let mut_ptr_ptr: *mut usize = std::mem::transmute(MSG_PTR_PTR);
519            *mut_ptr_ptr = msg_ptr;
520            let mut_metadata_ptr: *mut u8 = std::mem::transmute(MSG_METADATA_PTR);
521            // the first bit encodes if the msg pointer has changed
522            *mut_metadata_ptr = 1;
523            let mut_str_ptr_ptr: *mut usize = std::mem::transmute(STR_PTR_PTR);
524            *mut_str_ptr_ptr = str_ptr as usize;
525            // the second bit encodes if the str pointer has changed
526            *mut_metadata_ptr |= 2;
527        }
528    } else {
529        if unsafe { *MSG_PTR_PTR } != msg_ptr {
530            unsafe {
531                let mut_ptr_ptr: *mut usize = std::mem::transmute(MSG_PTR_PTR);
532                *mut_ptr_ptr = msg_ptr;
533                let mut_ptr_ptr: *mut u8 = std::mem::transmute(MSG_METADATA_PTR);
534                // the first bit encodes if the msg pointer has changed
535                *mut_ptr_ptr = 1;
536            }
537        } else {
538            unsafe {
539                let mut_ptr_ptr: *mut u8 = std::mem::transmute(MSG_METADATA_PTR);
540                // the first bit encodes if the msg pointer has changed
541                *mut_ptr_ptr = 0;
542            }
543        }
544        if unsafe { *STR_PTR_PTR } != str_ptr {
545            unsafe {
546                let mut_str_ptr_ptr: *mut usize = std::mem::transmute(STR_PTR_PTR);
547                *mut_str_ptr_ptr = str_ptr as usize;
548                let mut_metadata_ptr: *mut u8 = std::mem::transmute(MSG_METADATA_PTR);
549                // the second bit encodes if the str pointer has changed
550                *mut_metadata_ptr |= 1 << 1;
551            }
552        }
553    }
554    unsafe {
555        let mut_metadata_ptr: *mut u8 = std::mem::transmute(MSG_METADATA_PTR);
556        if !str_buf.is_empty() {
557            // the third bit encodes if there is any strings
558            *mut_metadata_ptr |= 1 << 2;
559            let mut_str_len_ptr: *mut usize = std::mem::transmute(STR_LEN_PTR);
560            *mut_str_len_ptr = str_buf.len() as usize;
561            if *mut_str_len_ptr < 100 {
562                // the fourth bit encodes if the strings are entirely ascii and small
563                *mut_metadata_ptr |= (str_buf.is_ascii() as u8) << 3;
564            }
565        }
566    }
567    if last_needs_memory() {
568        update_last_memory(wasm_bindgen::memory());
569    }
570    work_last_created();
571}
572
573/// Something that can be written as a utf-8 string to a buffer
574pub trait WritableText {
575    fn write_as_text(self, to: &mut Vec<u8>);
576}
577
578impl WritableText for char {
579    fn write_as_text(self, to: &mut Vec<u8>) {
580        to.push(self as u8);
581    }
582}
583
584impl<'a> WritableText for &'a str {
585    #[inline(always)]
586    fn write_as_text(self, to: &mut Vec<u8>) {
587        let len = self.len();
588        to.reserve(len);
589        let old_len = to.len();
590        #[allow(clippy::uninit_vec)]
591        unsafe {
592            let ptr = to.as_mut_ptr();
593            let bytes = self.as_bytes();
594            let str_ptr = bytes.as_ptr();
595            for o in 0..len {
596                *ptr.add(old_len + o) = *str_ptr.add(o);
597            }
598            to.set_len(old_len + len);
599        }
600        // let _ = to.write(self.as_bytes());
601    }
602}
603
604impl WritableText for Arguments<'_> {
605    fn write_as_text(self, to: &mut Vec<u8>) {
606        let _ = to.write_fmt(self);
607    }
608}
609
610impl<F> WritableText for F
611where
612    F: FnOnce(&mut Vec<u8>),
613{
614    fn write_as_text(self, to: &mut Vec<u8>) {
615        self(to);
616    }
617}
618
619macro_rules! write_unsized {
620    ($t: ty) => {
621        impl WritableText for $t {
622            fn write_as_text(self, to: &mut Vec<u8>) {
623                let mut n = self;
624                let mut n2 = n;
625                let mut num_digits = 0;
626                while n2 > 0 {
627                    n2 /= 10;
628                    num_digits += 1;
629                }
630                let len = num_digits;
631                to.reserve(len);
632                let ptr = to.as_mut_ptr().cast::<u8>();
633                let old_len = to.len();
634                let mut i = len - 1;
635                loop {
636                    unsafe { ptr.add(old_len + i).write((n % 10) as u8 + b'0') }
637                    n /= 10;
638
639                    if n == 0 {
640                        break;
641                    } else {
642                        i -= 1;
643                    }
644                }
645
646                #[allow(clippy::uninit_vec)]
647                unsafe {
648                    to.set_len(old_len + (len - i));
649                }
650            }
651        }
652    };
653}
654
655macro_rules! write_sized {
656    ($t: ty) => {
657        impl WritableText for $t {
658            fn write_as_text(self, to: &mut Vec<u8>) {
659                let neg = self < 0;
660                let mut n = if neg {
661                    match self.checked_abs() {
662                        Some(n) => n,
663                        None => <$t>::MAX / 2 + 1,
664                    }
665                } else {
666                    self
667                };
668                let mut n2 = n;
669                let mut num_digits = 0;
670                while n2 > 0 {
671                    n2 /= 10;
672                    num_digits += 1;
673                }
674                let len = if neg { num_digits + 1 } else { num_digits };
675                to.reserve(len);
676                let ptr = to.as_mut_ptr().cast::<u8>();
677                let old_len = to.len();
678                let mut i = len - 1;
679                loop {
680                    unsafe { ptr.add(old_len + i).write((n % 10) as u8 + b'0') }
681                    n /= 10;
682
683                    if n == 0 {
684                        break;
685                    } else {
686                        i -= 1;
687                    }
688                }
689
690                if neg {
691                    i -= 1;
692                    unsafe { ptr.add(old_len + i).write(b'-') }
693                }
694
695                #[allow(clippy::uninit_vec)]
696                unsafe {
697                    to.set_len(old_len + (len - i));
698                }
699            }
700        }
701    };
702}
703
704write_unsized!(u8);
705write_unsized!(u16);
706write_unsized!(u32);
707write_unsized!(u64);
708write_unsized!(u128);
709write_unsized!(usize);
710
711write_sized!(i8);
712write_sized!(i16);
713write_sized!(i32);
714write_sized!(i64);
715write_sized!(i128);
716write_sized!(isize);