1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use core::fmt::Debug;
15 use core::pin::Pin;
16 use core::task::{Context, Poll};
17 use std::io::Read;
18 
19 use crate::body::async_impl::{self, DataFuture};
20 use crate::body::mime::common::{data_copy, SizeResult, TokenStatus};
21 use crate::body::sync_impl;
22 use crate::{AsyncRead, ReadBuf};
23 
24 // Uses Box<dyn trait> so that it can be put into a list(like vec) with
25 // different T.
26 pub(crate) enum MixFrom<'a> {
27     // the read content is Vec<u8>
28     Owned { bytes: Vec<u8>, index: usize },
29     // the read content is from memory
30     Slice { bytes: &'a [u8], index: usize },
31     // the read content is from a synchronous reader
32     Reader(Box<dyn Read + Send + Sync>),
33     // the read content is from an asynchronous reader
34     AsyncReader(Box<dyn AsyncRead + Send + Sync + Unpin>),
35 }
36 
37 impl<'a> MixFrom<'a> {
38     // Usually needs owned.
new() -> Self39     pub(crate) fn new() -> Self {
40         MixFrom::Owned {
41             bytes: vec![],
42             index: 0,
43         }
44     }
45 
new_as_bytes() -> Self46     pub(crate) fn new_as_bytes() -> Self {
47         MixFrom::Slice {
48             bytes: &[],
49             index: 0,
50         }
51     }
52 
is_empty(&self) -> bool53     pub(crate) fn is_empty(&self) -> bool {
54         match self {
55             MixFrom::Owned { bytes, index: _ } => bytes.is_empty(),
56             MixFrom::Slice { bytes, index: _ } => bytes.is_empty(),
57             _ => false,
58         }
59     }
60 
set_owned(&mut self, bytes: Vec<u8>)61     pub(crate) fn set_owned(&mut self, bytes: Vec<u8>) {
62         *self = MixFrom::Owned { bytes, index: 0 };
63     }
64 
set_bytes(&mut self, bytes: &'a [u8])65     pub(crate) fn set_bytes(&mut self, bytes: &'a [u8]) {
66         *self = MixFrom::Slice { bytes, index: 0 };
67     }
68 
set_reader<T>(&mut self, data: T) where T: Read + Send + Sync + 'static,69     pub(crate) fn set_reader<T>(&mut self, data: T)
70     where
71         T: Read + Send + Sync + 'static,
72     {
73         *self = MixFrom::Reader(Box::new(data));
74     }
75 
set_async_reader<T>(&mut self, data: T) where T: AsyncRead + Send + Sync + Unpin + 'static,76     pub(crate) fn set_async_reader<T>(&mut self, data: T)
77     where
78         T: AsyncRead + Send + Sync + Unpin + 'static,
79     {
80         *self = MixFrom::AsyncReader(Box::new(data));
81     }
82 
owned_encode(&mut self, dst: &mut [u8]) -> SizeResult83     fn owned_encode(&mut self, dst: &mut [u8]) -> SizeResult {
84         if let MixFrom::Owned { bytes, index } = self {
85             match data_copy(bytes, index, dst)? {
86                 TokenStatus::Partial(size) => Ok(size),
87                 TokenStatus::Complete(size) => Ok(size),
88             }
89         } else {
90             Ok(0)
91         }
92     }
93 
bytes_encode(&mut self, dst: &mut [u8]) -> SizeResult94     fn bytes_encode(&mut self, dst: &mut [u8]) -> SizeResult {
95         if let MixFrom::Slice { bytes, index } = self {
96             match data_copy(bytes, index, dst)? {
97                 TokenStatus::Partial(size) => Ok(size),
98                 TokenStatus::Complete(size) => Ok(size),
99             }
100         } else {
101             Ok(0)
102         }
103     }
104 
read_encode(&mut self, dst: &mut [u8]) -> SizeResult105     fn read_encode(&mut self, dst: &mut [u8]) -> SizeResult {
106         if let MixFrom::Reader(data) = self {
107             let size = data.read(dst)?;
108             Ok(size)
109         } else {
110             Ok(0)
111         }
112     }
113 }
114 
115 impl Default for MixFrom<'_> {
default() -> Self116     fn default() -> Self {
117         MixFrom::new()
118     }
119 }
120 
121 impl Debug for MixFrom<'_> {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result122     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123         match self {
124             Self::Owned { bytes, index } => f
125                 .debug_struct("Owned")
126                 .field("bytes", bytes)
127                 .field("index", index)
128                 .finish(),
129             Self::Slice { bytes, index } => f
130                 .debug_struct("Slice")
131                 .field("bytes", bytes)
132                 .field("index", index)
133                 .finish(),
134             Self::Reader(_) => f.debug_tuple("Reader").finish(),
135             Self::AsyncReader(_) => f.debug_tuple("AsyncReader").finish(),
136         }
137     }
138 }
139 
140 // It is not a complete implementation, only implements for MixFrom::Owned &&
141 // MixFrom::Slice.
142 impl PartialEq for MixFrom<'_> {
eq(&self, other: &Self) -> bool143     fn eq(&self, other: &Self) -> bool {
144         match (self, other) {
145             (
146                 Self::Owned {
147                     bytes: l_bytes,
148                     index: l_index,
149                 },
150                 Self::Owned {
151                     bytes: r_bytes,
152                     index: r_index,
153                 },
154             ) => l_bytes == r_bytes && l_index == r_index,
155             (
156                 Self::Slice {
157                     bytes: l_bytes,
158                     index: l_index,
159                 },
160                 Self::Slice {
161                     bytes: r_bytes,
162                     index: r_index,
163                 },
164             ) => l_bytes == r_bytes && l_index == r_index,
165             // Dyn trait object can not impl PartialEq
166             (Self::Reader(_l0), Self::Reader(_r0)) => false,
167             (Self::AsyncReader(_l0), Self::AsyncReader(_r0)) => false,
168             _ => false,
169         }
170     }
171 }
172 
173 impl sync_impl::Body for MixFrom<'_> {
174     type Error = std::io::Error;
175 
data(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>176     fn data(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
177         if buf.is_empty() {
178             return Ok(0);
179         }
180 
181         match self {
182             MixFrom::Owned { bytes: _, index: _ } => self.owned_encode(buf),
183             MixFrom::Slice { bytes: _, index: _ } => self.bytes_encode(buf),
184             MixFrom::Reader(_) => self.read_encode(buf),
185             MixFrom::AsyncReader(_) => Ok(0),
186         }
187     }
188 }
189 
190 impl async_impl::Body for MixFrom<'_> {
191     type Error = std::io::Error;
192 
poll_data( mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll<Result<usize, Self::Error>>193     fn poll_data(
194         mut self: Pin<&mut Self>,
195         cx: &mut Context<'_>,
196         buf: &mut [u8],
197     ) -> Poll<Result<usize, Self::Error>> {
198         if buf.is_empty() {
199             return Poll::Ready(Ok(0));
200         }
201 
202         match &mut *self {
203             MixFrom::Owned { bytes: _, index: _ } => Poll::Ready(self.owned_encode(buf)),
204             MixFrom::Slice { bytes: _, index: _ } => Poll::Ready(self.bytes_encode(buf)),
205             MixFrom::Reader(_) => Poll::Ready(Ok(0)),
206             MixFrom::AsyncReader(data) => {
207                 let mut buf = ReadBuf::new(buf);
208                 match Pin::new(data).poll_read(cx, &mut buf) {
209                     Poll::Ready(Ok(())) => Poll::Ready(Ok(buf.filled().len())),
210                     Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
211                     Poll::Pending => Poll::Pending,
212                 }
213             }
214         }
215     }
216 }
217 
218 #[cfg(test)]
219 mod ut_mix {
220     use crate::body::mime::common::mix::MixFrom;
221     use crate::body::{async_impl, sync_impl};
222 
223     /// Builds a `MixFrom`.
224     macro_rules! mix_build {
225         (
226             MixFrom: {
227                 $(BodyOwned: $body1: expr,)?
228                 $(BodySlice: $body2: expr,)?
229                 $(BodyReader: $body3: expr,)?
230                 $(BodyAsyncReader: $body4: expr,)?
231             },
232         ) => {
233             {
234                 #[allow(unused_mut)]
235                 let mut mix = MixFrom::new_as_bytes();
236 
237                 $(mix.set_owned($body1);)?
238                 $(mix.set_bytes($body2);)?
239                 $(mix.set_reader($body3);)?
240                 $(mix.set_async_reader($body4);)?
241                 mix
242             }
243         }
244     }
245 
246     /// Builds a `Mimepart`, encodes it, Compares with result.
247     macro_rules! mix_encode_compare {
248         (
249             MixFrom: {
250                 $(BodyOwned: $body1: expr,)?
251                 $(BodySlice: $body2: expr,)?
252                 $(BodyReader: $body3: expr,)?
253                 $(BodyAsyncReader: $body4: expr,)?
254             },
255             $(BufSize: $size: expr,)?
256             $(ResultSize: $v_size: expr,)?
257             $(ResultData: $v_data: expr,)?
258             Sync,
259         ) => {
260             let mut mix = mix_build!(
261                 MixFrom: {
262                     $(BodyOwned: $body1,)?
263                     $(BodySlice: $body2,)?
264                     $(BodyReader: $body3,)?
265                     $(BodyAsyncReader: $body4,)?
266                 },
267             );
268             // default 1
269             #[allow(unused_assignments, unused_mut)]
270             let mut len = 1;
271 
272             $(len = $size;)?
273             let mut buf = vec![0u8; len];
274             let mut v_data = vec![];
275             let mut v_size = vec![];
276 
277             loop {
278                 let size = sync_impl::Body::data(&mut mix, &mut buf).expect("MixFrom encode failed");
279                 if size == 0 {
280                     break;
281                 }
282                 v_size.push(size);
283                 v_data.extend_from_slice(&buf[..size]);
284             }
285             $(assert_eq!(v_size, $v_size);)?
286             $(assert_eq!(v_data, $v_data);)?
287         };
288 
289         (
290             MixFrom: {
291                 $(BodyOwned: $body1: expr,)?
292                 $(BodySlice: $body2: expr,)?
293                 $(BodyReader: $body3: expr,)?
294                 $(BodyAsyncReader: $body4: expr,)?
295             },
296             $(BufSize: $size: expr,)?
297             $(ResultSize: $v_size: expr,)?
298             $(ResultData: $v_data: expr,)?
299             Async,
300         ) => {
301             let mut mix = mix_build!(
302                 MixFrom: {
303                     $(BodyOwned: $body1,)?
304                     $(BodySlice: $body2,)?
305                     $(BodyReader: $body3,)?
306                     $(BodyAsyncReader: $body4,)?
307                 },
308             );
309 
310             // default 1
311             #[allow(unused_assignments, unused_mut)]
312             let mut len = 1;
313 
314             $(len = $size;)?
315             let mut buf = vec![0u8; len];
316             let mut v_data = vec![];
317             let mut v_size = vec![];
318 
319             loop {
320                 let size = async_impl::Body::data(&mut mix, &mut buf).await.expect("MixFrom encode failed");
321                 if size == 0 {
322                     break;
323                 }
324                 v_size.push(size);
325                 v_data.extend_from_slice(&buf[..size]);
326             }
327             $(assert_eq!(v_size, $v_size);)?
328             $(assert_eq!(v_data, $v_data);)?
329         };
330     }
331 
332     /// UT test cases for `MixFrom::new`.
333     ///
334     /// # Brief
335     /// 1. Creates a `MixFrom` by `MixFrom::new`.
336     /// 2. Checks whether the result is correct.
337     #[test]
ut_mix_new()338     fn ut_mix_new() {
339         mix_encode_compare!(
340             MixFrom: {
341             },
342             ResultData: b"",
343             Sync,
344         );
345     }
346 
347     /// UT test cases for `MixFrom::set_owned`.
348     ///
349     /// # Brief
350     /// 1. Creates a `MixFrom` from Vec<u8> by `MixFrom::set_owned`.
351     /// 2. Checks whether the result is correct.
352     #[test]
ut_mix_set_owned()353     fn ut_mix_set_owned() {
354         mix_encode_compare!(
355             MixFrom: {
356                 BodyOwned: b"123456".to_vec(),
357             },
358             BufSize: 5,
359             ResultSize: vec![5, 1],
360             ResultData: b"123456",
361             Sync,
362         );
363     }
364 
365     /// UT test cases for `MixFrom::set_bytes`.
366     ///
367     /// # Brief
368     /// 1. Creates a `MixFrom` from bytes by `MixFrom::set_bytes`.
369     /// 2. Checks whether the result is correct.
370     #[test]
ut_mix_set_bytes()371     fn ut_mix_set_bytes() {
372         mix_encode_compare!(
373             MixFrom: {
374                 BodySlice: b"123456",
375             },
376             ResultData: b"123456",
377             Sync,
378         );
379     }
380 
381     /// UT test cases for `MixFrom::set_reader`.
382     ///
383     /// # Brief
384     /// 1. Creates a `MixFrom` from synchronous read content by
385     ///    `MixFrom::set_reader`.
386     /// 2. Checks whether the result is correct.
387     #[test]
ut_mix_set_reader()388     fn ut_mix_set_reader() {
389         mix_encode_compare!(
390             MixFrom: {
391                 BodyReader: "12345678".as_bytes(),
392             },
393             ResultData: b"12345678",
394             Sync,
395         );
396     }
397 
398     /// UT test cases for `MixFrom::set_async_reader`.
399     ///
400     /// # Brief
401     /// 1. Creates a `MixFrom` from asynchronous read content by
402     ///    `MixFrom::set_async_reader`.
403     /// 2. Encodes by synchronous encoding.
404     /// 3. Checks whether the result is correct.
405     #[test]
ut_mix_set_async_reader_then_sync_data()406     fn ut_mix_set_async_reader_then_sync_data() {
407         mix_encode_compare!(
408             MixFrom: {
409                 BodyAsyncReader: "123456".as_bytes(),
410             },
411             ResultData: b"",
412             Sync,
413         );
414     }
415 
416     /// UT test cases for `MixFrom::set_async_reader`.
417     ///
418     /// # Brief
419     /// 1. Creates a `MixFrom` from asynchronous read content by
420     ///    `MixFrom::set_async_reader`.
421     /// 2. Encodes by asynchronous encoding.
422     /// 3. Checks whether the result is correct.
423     #[cfg(feature = "ylong_base")]
424     #[test]
ut_mix_set_async_reader()425     fn ut_mix_set_async_reader() {
426         let handle = ylong_runtime::spawn(async move {
427             mix_set_async_reader().await;
428         });
429         ylong_runtime::block_on(handle).unwrap();
430     }
431 
432     #[cfg(feature = "ylong_base")]
mix_set_async_reader()433     async fn mix_set_async_reader() {
434         mix_encode_compare!(
435             MixFrom: {
436                 BodyAsyncReader: "12345678".as_bytes(),
437             },
438             ResultData: b"12345678",
439             Async,
440         );
441     }
442 
443     /// UT test cases for `MixFrom::set_reader`.
444     ///
445     /// # Brief
446     /// 1. Creates a `MixFrom` from synchronous read content by
447     ///    `MixFrom::set_reader`.
448     /// 2. Encodes by asynchronous encoding.
449     /// 3. Checks whether the result is correct.
450     #[cfg(feature = "ylong_base")]
451     #[test]
ut_mix_set_reader_then_async_data()452     fn ut_mix_set_reader_then_async_data() {
453         let handle = ylong_runtime::spawn(async move {
454             mix_set_reader_then_async_data().await;
455         });
456         ylong_runtime::block_on(handle).unwrap();
457     }
458 
459     #[cfg(feature = "ylong_base")]
mix_set_reader_then_async_data()460     async fn mix_set_reader_then_async_data() {
461         mix_encode_compare!(
462             MixFrom: {
463                 BodyReader: "12345678".as_bytes(),
464             },
465             ResultData: b"",
466             Async,
467         );
468     }
469 
470     /// UT test cases for `MixFrom::set_bytes`.
471     ///
472     /// # Brief
473     /// 1. Creates a `MixFrom` from synchronous read content by
474     ///    `MixFrom::set_bytes`.
475     /// 2. Encodes by asynchronous encoding.
476     /// 3. Checks whether the result is correct.
477     #[cfg(feature = "ylong_base")]
478     #[test]
ut_mix_set_bytes_then_async_data()479     fn ut_mix_set_bytes_then_async_data() {
480         let handle = ylong_runtime::spawn(async move {
481             mix_set_bytes_then_async_data().await;
482         });
483         ylong_runtime::block_on(handle).unwrap();
484     }
485 
486     #[cfg(feature = "ylong_base")]
mix_set_bytes_then_async_data()487     async fn mix_set_bytes_then_async_data() {
488         mix_encode_compare!(
489             MixFrom: {
490                 BodyReader: "12345678".as_bytes(),
491             },
492             ResultData: b"",
493             Async,
494         );
495     }
496 
497     /// UT test cases for `MixFrom::set_owned`.
498     ///
499     /// # Brief
500     /// 1. Creates a `MixFrom` from synchronous read content by
501     ///    `MixFrom::set_owned`.
502     /// 2. Encodes by asynchronous encoding.
503     /// 3. Checks whether the result is correct.
504     #[cfg(feature = "ylong_base")]
505     #[test]
ut_mix_set_owned_then_async_data()506     fn ut_mix_set_owned_then_async_data() {
507         let handle = ylong_runtime::spawn(async move {
508             mix_set_owned_then_async_data().await;
509         });
510         ylong_runtime::block_on(handle).unwrap();
511     }
512 
513     #[cfg(feature = "ylong_base")]
mix_set_owned_then_async_data()514     async fn mix_set_owned_then_async_data() {
515         mix_encode_compare!(
516             MixFrom: {
517                 BodyOwned: b"12345678".to_vec(),
518             },
519             ResultData: b"12345678",
520             Async,
521         );
522     }
523 }
524