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