Skip to main content

tokio_dbus/body/
mod.rs

1pub use self::load_array::LoadArray;
2mod load_array;
3
4pub use self::as_body::AsBody;
5mod as_body;
6
7use core::fmt;
8
9#[cfg(feature = "alloc")]
10use crate::BodyBuf;
11use crate::buf::Aligned;
12use crate::error::Result;
13use crate::ty;
14use crate::{Endianness, Frame, Read, Signature};
15
16/// A read-only view into a buffer suitable for use as a body in a [`Message`].
17///
18/// [`Message`]: crate::Message
19///
20/// # Examples
21///
22/// ```
23/// use tokio_dbus::{Result, Body};
24///
25/// fn read(buf: &mut Body<'_>) -> Result<()> {
26///     assert_eq!(buf.load::<u32>()?, 7u32);
27///     assert_eq!(buf.load::<u8>()?, b'f');
28///     assert_eq!(buf.load::<u8>()?, b'o');
29///     assert_eq!(buf.get(), &[b'o', b' ', b'b', b'a', b'r', 0]);
30///     Ok(())
31/// }
32/// # Ok::<_, tokio_dbus::Error>(())
33/// ```
34pub struct Body<'a> {
35    data: Aligned<'a>,
36    endianness: Endianness,
37    signature: &'a Signature,
38}
39
40impl<'a> Body<'a> {
41    /// Construct an empty buffer.
42    pub(crate) const fn empty() -> Self {
43        Self::from_raw_parts(Aligned::empty(), Endianness::NATIVE, Signature::EMPTY)
44    }
45
46    /// Construct a new buffer wrapping pointed to data.
47    #[inline]
48    pub(crate) const fn from_raw_parts(
49        data: Aligned<'a>,
50        endianness: Endianness,
51        signature: &'a Signature,
52    ) -> Self {
53        Self {
54            data,
55            endianness,
56            signature,
57        }
58    }
59
60    /// Deconstruct into raw parts.
61    #[cfg(feature = "alloc")]
62    #[inline]
63    pub(crate) const fn into_raw_parts(self) -> (Aligned<'a>, Endianness, &'a Signature) {
64        (self.data, self.endianness, self.signature)
65    }
66
67    /// Get the endianness of the buffer.
68    ///
69    /// # Examples
70    ///
71    /// ```
72    /// use tokio_dbus::{Body, BodyBuf, Endianness};
73    ///
74    /// let buf = BodyBuf::new();
75    ///
76    /// let buf: Body<'_> = buf.as_body();
77    /// assert_eq!(buf.endianness(), Endianness::NATIVE);
78    ///
79    /// let buf = buf.with_endianness(Endianness::BIG);
80    /// assert_eq!(buf.endianness(), Endianness::BIG);
81    /// # Ok::<_, tokio_dbus::Error>(())
82    /// ```
83    pub fn endianness(&self) -> Endianness {
84        self.endianness
85    }
86
87    /// Adjust endianness of buffer.
88    ///
89    /// # Examples
90    ///
91    /// ```
92    /// use tokio_dbus::{Body, BodyBuf, Endianness};
93    ///
94    /// let buf = BodyBuf::new();
95    ///
96    /// let buf: Body<'_> = buf.as_body();
97    /// assert_eq!(buf.endianness(), Endianness::NATIVE);
98    ///
99    /// let buf = buf.with_endianness(Endianness::BIG);
100    /// assert_eq!(buf.endianness(), Endianness::BIG);
101    /// # Ok::<_, tokio_dbus::Error>(())
102    /// ```
103    pub fn with_endianness(self, endianness: Endianness) -> Self {
104        Self { endianness, ..self }
105    }
106
107    /// Get the signature of the buffer.
108    ///
109    /// # Examples
110    ///
111    /// ```
112    /// use tokio_dbus::{Body, BodyBuf};
113    ///
114    /// let mut buf = BodyBuf::new();
115    ///
116    /// buf.store(10u16)?;
117    /// buf.store(10u32)?;
118    ///
119    /// let buf: Body<'_> = buf.as_body();
120    ///
121    /// assert_eq!(buf.signature(), "qu");
122    /// # Ok::<_, tokio_dbus::Error>(())
123    /// ```
124    pub fn signature(&self) -> &'a Signature {
125        self.signature
126    }
127
128    /// Adjust the signature of buffer.
129    #[cfg(feature = "alloc")]
130    pub(crate) fn with_signature(self, signature: &'a Signature) -> Self {
131        Self { signature, ..self }
132    }
133
134    /// Get a slice out of the buffer that has ben written to.
135    ///
136    /// # Examples
137    ///
138    /// ```
139    /// use tokio_dbus::{Result, Body};
140    ///
141    /// fn read(buf: &mut Body<'_>) -> Result<()> {
142    ///     assert_eq!(buf.load::<u32>()?, 7u32);
143    ///     assert_eq!(buf.load::<u8>()?, b'f');
144    ///     assert_eq!(buf.load::<u8>()?, b'o');
145    ///     assert_eq!(buf.get(), &[b'o', b' ', b'b', b'a', b'r', 0]);
146    ///     Ok(())
147    /// }
148    /// # Ok::<_, tokio_dbus::Error>(())
149    /// ```
150    pub fn get(&self) -> &'a [u8] {
151        self.data.get()
152    }
153
154    /// Test if the buffer is empty.
155    ///
156    /// # Examples
157    ///
158    /// ```
159    /// use tokio_dbus::{Body, BodyBuf, Endianness};
160    ///
161    /// let mut buf = BodyBuf::with_endianness(Endianness::LITTLE);
162    /// let b: Body<'_> = buf.as_body();
163    /// assert!(b.is_empty());
164    ///
165    /// buf.store(10u16)?;
166    /// buf.store(10u32)?;
167    ///
168    /// let b: Body<'_> = buf.as_body();
169    /// assert!(!b.is_empty());
170    /// # Ok::<_, tokio_dbus::Error>(())
171    /// ```
172    #[inline]
173    pub fn is_empty(&self) -> bool {
174        self.data.is_empty()
175    }
176
177    /// Remaining data to be read from the buffer.
178    ///
179    /// # Examples
180    ///
181    /// ```
182    /// use tokio_dbus::{Body, BodyBuf, Endianness};
183    ///
184    /// let mut buf = BodyBuf::with_endianness(Endianness::LITTLE);
185    /// assert!(buf.is_empty());
186    ///
187    /// buf.store(10u16)?;
188    /// buf.store(10u32)?;
189    ///
190    /// let b: Body<'_> = buf.as_body();
191    /// assert_eq!(b.len(), 8);
192    /// # Ok::<_, tokio_dbus::Error>(())
193    /// ```
194    #[inline]
195    pub fn len(&self) -> usize {
196        self.data.len()
197    }
198
199    /// Read a reference from the buffer.
200    ///
201    /// This is possible for unaligned types such as `str` and `[u8]` which
202    /// implement [`Read`].
203    ///
204    /// # Examples
205    ///
206    /// ```
207    /// use tokio_dbus::{Result, Body};
208    ///
209    /// fn read(buf: &mut Body<'_>) -> Result<()> {
210    ///     assert_eq!(buf.load::<u32>()?, 4);
211    ///     assert_eq!(buf.read::<str>()?, "hi");
212    ///     assert!(buf.is_empty());
213    ///     Ok(())
214    /// }
215    /// # Ok::<_, tokio_dbus::Error>(())
216    /// ````
217    pub fn read<T>(&mut self) -> Result<&'a T>
218    where
219        T: ?Sized + Read,
220    {
221        T::read_from(self)
222    }
223
224    /// Read `len` bytes from the buffer and make accessible through another
225    /// [`Body`] instance constituting that sub-slice.
226    ///
227    /// # Panics
228    ///
229    /// This panics if `len` is larger than [`len()`].
230    ///
231    /// [`len()`]: Self::len
232    ///
233    /// # Examples
234    ///
235    /// ```
236    /// use tokio_dbus::{Result, Body};
237    ///
238    /// fn read(buf: &mut Body<'_>) -> Result<()> {
239    ///     let mut read_buf = buf.read_until(6);
240    ///     assert_eq!(read_buf.load::<u32>()?, 4);
241    ///
242    ///     let mut read_buf2 = read_buf.read_until(2);
243    ///     assert_eq!(read_buf2.load::<u8>()?, 1);
244    ///     assert_eq!(read_buf2.load::<u8>()?, 2);
245    ///
246    ///     assert!(read_buf.is_empty());
247    ///     assert!(read_buf2.is_empty());
248    ///
249    ///     assert_eq!(buf.get(), &[3, 4, 0]);
250    ///     Ok(())
251    /// }
252    /// ```
253    pub fn read_until(&mut self, len: usize) -> Body<'a> {
254        Body::from_raw_parts(self.data.read_until(len), self.endianness, self.signature)
255    }
256
257    /// Read an array from the buffer.
258    ///
259    /// # Examples
260    ///
261    /// ```
262    /// use tokio_dbus::{ty, BodyBuf, Endianness};
263    ///
264    /// let mut buf = BodyBuf::with_endianness(Endianness::LITTLE);
265    /// let mut array = buf.store_array::<u32>()?;
266    /// array.store(10u32);
267    /// array.store(20u32);
268    /// array.store(30u32);
269    /// array.finish();
270    ///
271    /// let mut array = buf.store_array::<ty::Array<ty::Str>>()?;
272    /// let mut inner = array.store_array();
273    /// inner.store("foo");
274    /// inner.store("bar");
275    /// inner.store("baz");
276    /// inner.finish();
277    /// array.finish();
278    ///
279    /// assert_eq!(buf.signature(), b"auaas");
280    ///
281    /// let mut buf = buf.as_body();
282    /// let mut array = buf.load_array::<u32>()?;
283    /// assert_eq!(array.load()?, Some(10));
284    /// assert_eq!(array.load()?, Some(20));
285    /// assert_eq!(array.load()?, Some(30));
286    /// assert_eq!(array.load()?, None);
287    ///
288    /// let mut array = buf.load_array::<ty::Array<ty::Str>>()?;
289    ///
290    /// let Some(mut inner) = array.load_array()? else {
291    ///     panic!("Missing inner array");
292    /// };
293    ///
294    /// assert_eq!(inner.read()?, Some("foo"));
295    /// assert_eq!(inner.read()?, Some("bar"));
296    /// assert_eq!(inner.read()?, Some("baz"));
297    /// assert_eq!(inner.read()?, None);
298    /// # Ok::<_, tokio_dbus::Error>(())
299    /// ```
300    pub fn load_array<E>(&mut self) -> Result<LoadArray<'a, E>>
301    where
302        E: ty::Marker,
303    {
304        LoadArray::from_mut(self)
305    }
306
307    /// Read a struct from the buffer.
308    ///
309    /// # Examples
310    ///
311    /// ```
312    /// use tokio_dbus::{ty, BodyBuf, Endianness};
313    ///
314    /// let mut buf = BodyBuf::with_endianness(Endianness::LITTLE);
315    /// buf.store(10u8);
316    ///
317    /// buf.store_struct::<(u16, u32, ty::Array<u8>, ty::Str)>()?
318    ///     .store(20u16)
319    ///     .store(30u32)
320    ///     .store_array(|w| {
321    ///         w.store(1u8);
322    ///         w.store(2u8);
323    ///         w.store(3u8);
324    ///     })
325    ///     .store("Hello World")
326    ///     .finish();
327    ///
328    /// assert_eq!(buf.signature(), "y(quays)");
329    ///
330    /// let mut buf = buf.as_body();
331    /// assert_eq!(buf.load::<u8>()?, 10u8);
332    ///
333    /// let (a, b, mut array, string) = buf.load_struct::<(u16, u32, ty::Array<u8>, ty::Str)>()?;
334    /// assert_eq!(a, 20u16);
335    /// assert_eq!(b, 30u32);
336    ///
337    /// assert_eq!(array.load()?, Some(1));
338    /// assert_eq!(array.load()?, Some(2));
339    /// assert_eq!(array.load()?, Some(3));
340    /// assert_eq!(array.load()?, None);
341    ///
342    /// assert_eq!(string, "Hello World");
343    /// # Ok::<_, tokio_dbus::Error>(())
344    /// ```
345    pub fn load_struct<E>(&mut self) -> Result<E::Return<'a>>
346    where
347        E: ty::Fields,
348    {
349        self.align::<u64>()?;
350        E::load_struct(self)
351    }
352
353    /// Read a struct whose fields are read by the given closure.
354    ///
355    /// This aligns the buffer as a struct and then hands it to `f`. It is an
356    /// escape hatch for structs which [`load_struct()`] cannot describe, such as
357    /// ones containing a variant of an unknown type.
358    ///
359    /// [`load_struct()`]: Self::load_struct
360    ///
361    /// # Examples
362    ///
363    /// ```
364    /// use tokio_dbus::{ty, BodyBuf, Signature};
365    ///
366    /// let mut buf = BodyBuf::new();
367    ///
368    /// buf.store_struct::<(u32, ty::Variant)>()?
369    ///     .store(42u32)
370    ///     .store_variant(Signature::new("as")?, |w| {
371    ///         w.store_array::<ty::Str>().store("Hello");
372    ///     })
373    ///     .finish();
374    ///
375    /// let mut buf = buf.as_body();
376    ///
377    /// let n = buf.load_struct_with(|b| {
378    ///     let n = b.load::<u32>()?;
379    ///     b.skip_variant()?;
380    ///     Ok(n)
381    /// })?;
382    ///
383    /// assert_eq!(n, 42);
384    /// # Ok::<_, tokio_dbus::Error>(())
385    /// ```
386    pub fn load_struct_with<F, O>(&mut self, f: F) -> Result<O>
387    where
388        F: FnOnce(&mut Body<'a>) -> Result<O>,
389    {
390        self.align::<u64>()?;
391        f(self)
392    }
393
394    /// Load a frame of the given type.
395    ///
396    /// This advances the read cursor of the buffer by the alignment and size of
397    /// the type. The return value has been endian-adjusted as per
398    /// [`endianness()`].
399    ///
400    /// [`endianness()`]: Self::endianness
401    ///
402    /// # Error
403    ///
404    /// Errors if the underlying buffer does not have enough space to represent
405    /// the type `T`.
406    ///
407    /// # Examples
408    ///
409    /// ```
410    /// use tokio_dbus::{Result, Body};
411    ///
412    /// fn read(buf: &mut Body<'_>) -> Result<()> {
413    ///     assert_eq!(buf.load::<u32>()?, 7u32);
414    ///     assert_eq!(buf.load::<u8>()?, b'f');
415    ///     assert_eq!(buf.load::<u8>()?, b'o');
416    ///     assert_eq!(buf.get(), &[b'o', b' ', b'b', b'a', b'r', 0]);
417    ///     Ok(())
418    /// }
419    /// # Ok::<_, tokio_dbus::Error>(())
420    /// ```
421    pub fn load<T>(&mut self) -> Result<T>
422    where
423        T: Frame,
424    {
425        let mut frame = self.data.load::<T>()?;
426        frame.adjust(self.endianness);
427        Ok(frame)
428    }
429
430    /// Load a [`bool`] from the buffer.
431    ///
432    /// The D-Bus `BOOLEAN` type is marshalled as a 32-bit integer, which is why
433    /// it cannot be loaded through [`load()`].
434    ///
435    /// [`load()`]: Self::load
436    ///
437    /// # Examples
438    ///
439    /// ```
440    /// use tokio_dbus::BodyBuf;
441    ///
442    /// let mut buf = BodyBuf::new();
443    /// buf.store(true)?;
444    /// buf.store(false)?;
445    ///
446    /// let mut buf = buf.as_body();
447    /// assert!(buf.load_bool()?);
448    /// assert!(!buf.load_bool()?);
449    /// # Ok::<_, tokio_dbus::Error>(())
450    /// ```
451    pub fn load_bool(&mut self) -> Result<bool> {
452        Ok(self.load::<u32>()? != 0)
453    }
454
455    /// Read a [`Variant`] holding a value of a basic type from the buffer.
456    ///
457    /// [`Variant`]: crate::Variant
458    ///
459    /// # Errors
460    ///
461    /// Errors if the variant holds a container. Use [`skip_variant()`] to skip
462    /// over a variant of an unknown type instead.
463    ///
464    /// [`skip_variant()`]: Self::skip_variant
465    ///
466    /// # Examples
467    ///
468    /// ```
469    /// use tokio_dbus::{BodyBuf, Variant};
470    ///
471    /// let mut buf = BodyBuf::new();
472    /// buf.store(Variant::U32(42))?;
473    ///
474    /// let mut buf = buf.as_body();
475    /// assert_eq!(buf.read_variant()?, Variant::U32(42));
476    /// # Ok::<_, tokio_dbus::Error>(())
477    /// ```
478    pub fn read_variant(&mut self) -> Result<crate::Variant<'a>> {
479        <ty::Variant as ty::Marker>::load_struct(self)
480    }
481
482    /// Read a variant which is expected to contain a value of type `T`.
483    ///
484    /// Unlike [`read_variant()`] this can read containers, but requires the
485    /// caller to know which type the variant contains.
486    ///
487    /// [`read_variant()`]: Self::read_variant
488    ///
489    /// # Errors
490    ///
491    /// Errors if the variant does not contain a value of type `T`.
492    ///
493    /// # Examples
494    ///
495    /// ```
496    /// use tokio_dbus::{ty, BodyBuf, Signature};
497    ///
498    /// let mut buf = BodyBuf::new();
499    ///
500    /// let mut array = buf.store_variant(Signature::new("as")?)?.store_array::<ty::Str>();
501    /// array.store("Hello");
502    /// array.store("World");
503    /// array.finish();
504    ///
505    /// let mut buf = buf.as_body();
506    /// let mut array = buf.read_variant_as::<ty::Array<ty::Str>>()?;
507    ///
508    /// assert_eq!(array.read()?, Some("Hello"));
509    /// assert_eq!(array.read()?, Some("World"));
510    /// assert_eq!(array.read()?, None);
511    /// # Ok::<_, tokio_dbus::Error>(())
512    /// ```
513    pub fn read_variant_as<T>(&mut self) -> Result<T::Return<'a>>
514    where
515        T: ty::Marker,
516    {
517        let signature = self.read::<Signature>()?;
518
519        let mut expected = crate::signature::SignatureBuilder::new();
520        T::write_signature(&mut expected)?;
521
522        if signature != expected.to_signature() {
523            #[cfg(feature = "alloc")]
524            return Err(crate::Error::new(
525                crate::error::ErrorKind::UnsupportedVariant(signature.into()),
526            ));
527            #[cfg(not(feature = "alloc"))]
528            return Err(crate::Error::new(
529                crate::error::ErrorKind::UnsupportedVariantNoAlloc,
530            ));
531        }
532
533        self.align::<T::Alignment>()?;
534        T::load_struct(self)
535    }
536
537    /// Skip over a variant of any type, returning the signature of the value it
538    /// contained.
539    ///
540    /// This is useful for arguments which are declared as variants but which
541    /// the receiver has no interest in, such as the `data` argument of the
542    /// `com.canonical.dbusmenu.Event` method.
543    ///
544    /// # Examples
545    ///
546    /// ```
547    /// use tokio_dbus::{ty, BodyBuf, Signature};
548    ///
549    /// let mut buf = BodyBuf::new();
550    ///
551    /// buf.store_variant(Signature::new("as")?)?
552    ///     .store_array::<ty::Str>()
553    ///     .store("Hello");
554    /// buf.store(42u32)?;
555    ///
556    /// assert_eq!(buf.signature(), "vu");
557    ///
558    /// let mut buf = buf.as_body();
559    /// assert_eq!(buf.skip_variant()?, Signature::new("as")?);
560    /// assert_eq!(buf.load::<u32>()?, 42);
561    /// # Ok::<_, tokio_dbus::Error>(())
562    /// ```
563    #[cfg(feature = "alloc")]
564    pub fn skip_variant(&mut self) -> Result<&'a Signature> {
565        let signature = self.read::<Signature>()?;
566        crate::signature::skip(signature, self)?;
567        Ok(signature)
568    }
569
570    /// Align the read cursor to the given alignment.
571    ///
572    /// This is the counterpart of [`Raw::align`], and is needed before reading
573    /// the fields of a struct or a dict entry whose shape is only known at
574    /// runtime.
575    ///
576    /// [`Raw::align`]: crate::Raw::align
577    ///
578    /// # Examples
579    ///
580    /// ```
581    /// use tokio_dbus::{ty, Alignment, BodyBuf};
582    ///
583    /// let mut buf = BodyBuf::new();
584    ///
585    /// buf.store(1u8)?;
586    /// buf.store_struct::<(u32, u32)>()?.store(2u32).store(3u32).finish();
587    ///
588    /// let mut buf = buf.as_body();
589    /// assert_eq!(buf.load::<u8>()?, 1);
590    ///
591    /// buf.align_to(Alignment::U64)?;
592    /// assert_eq!(buf.load::<u32>()?, 2);
593    /// assert_eq!(buf.load::<u32>()?, 3);
594    /// # Ok::<_, tokio_dbus::Error>(())
595    /// ```
596    #[cfg(feature = "alloc")]
597    pub fn align_to(&mut self, alignment: crate::Alignment) -> Result<()> {
598        self.data.align_to(alignment.in_bytes())
599    }
600
601    /// Read an array whose elements have the given alignment, returning a
602    /// [`Body`] over its contents.
603    ///
604    /// This is the counterpart of [`Raw::store_array`].
605    ///
606    /// [`Raw::store_array`]: crate::Raw::store_array
607    ///
608    /// # Examples
609    ///
610    /// ```
611    /// use tokio_dbus::{ty, Alignment, BodyBuf};
612    ///
613    /// let mut buf = BodyBuf::new();
614    ///
615    /// let mut array = buf.store_array::<ty::Str>()?;
616    /// array.store("Hello");
617    /// array.store("World");
618    /// array.finish();
619    ///
620    /// let mut buf = buf.as_body();
621    /// let mut array = buf.load_raw_array(Alignment::U32)?;
622    ///
623    /// let mut out = Vec::new();
624    ///
625    /// while !array.is_empty() {
626    ///     out.push(array.read::<str>()?);
627    /// }
628    ///
629    /// assert_eq!(out, ["Hello", "World"]);
630    /// # Ok::<_, tokio_dbus::Error>(())
631    /// ```
632    #[cfg(feature = "alloc")]
633    pub fn load_raw_array(&mut self, alignment: crate::Alignment) -> Result<Body<'a>> {
634        let bytes = self.load::<u32>()?;
635
636        if bytes > crate::buf::MAX_ARRAY_LENGTH {
637            return Err(crate::Error::new(crate::error::ErrorKind::ArrayTooLong(
638                bytes,
639            )));
640        }
641
642        self.align_to(alignment)?;
643        Ok(self.read_until(bytes as usize))
644    }
645
646    /// Advance the read cursor by `n`.
647    #[cfg(feature = "alloc")]
648    #[inline]
649    pub(crate) fn advance(&mut self, n: usize) -> Result<()> {
650        self.data.advance(n)
651    }
652
653    /// Align the read side of the buffer.
654    #[inline]
655    pub(crate) fn align<T>(&mut self) -> Result<()> {
656        self.data.align::<T>()
657    }
658
659    /// Load a slice.
660    #[inline]
661    pub(crate) fn load_slice(&mut self, len: usize) -> Result<&'a [u8]> {
662        self.data.load_slice(len)
663    }
664
665    /// Load a slice ending with a NUL byte, excluding the null byte.
666    #[inline]
667    pub(crate) fn load_slice_nul(&mut self, len: usize) -> Result<&'a [u8]> {
668        self.data.load_slice_nul(len)
669    }
670}
671
672// SAFETY: Body is equivalent to `&[u8]`.
673unsafe impl Send for Body<'_> {}
674// SAFETY: Body is equivalent to `&[u8]`.
675unsafe impl Sync for Body<'_> {}
676
677impl Clone for Body<'_> {
678    #[inline]
679    fn clone(&self) -> Self {
680        Self {
681            data: self.data.clone(),
682            endianness: self.endianness,
683            signature: self.signature,
684        }
685    }
686}
687
688impl fmt::Debug for Body<'_> {
689    #[inline]
690    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
691        f.debug_struct("Body")
692            .field("data", &self.data)
693            .field("endianness", &self.endianness)
694            .finish()
695    }
696}
697
698impl<'a> PartialEq<Body<'a>> for Body<'_> {
699    #[inline]
700    fn eq(&self, other: &Body<'a>) -> bool {
701        self.get() == other.get() && self.endianness == other.endianness
702    }
703}
704
705#[cfg(feature = "alloc")]
706impl PartialEq<BodyBuf> for Body<'_> {
707    #[inline]
708    fn eq(&self, other: &BodyBuf) -> bool {
709        self.get() == other.get() && self.endianness == other.endianness()
710    }
711}
712
713impl Eq for Body<'_> {}