From fd5ee524bbb1373c39fa44085ed1fcb8ff20e08c Mon Sep 17 00:00:00 2001 From: amtoaer Date: Sat, 30 Mar 2024 21:00:39 +0800 Subject: [PATCH] =?UTF-8?q?test:=20=E5=8A=A0=E5=85=A5=20status=20=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E7=9A=84=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/status.rs | 60 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/src/core/status.rs b/src/core/status.rs index 7ea0c0f..af60d5f 100644 --- a/src/core/status.rs +++ b/src/core/status.rs @@ -7,6 +7,7 @@ static STATUS_OK: u32 = 0b111; /// 从低位开始,固定每三位表示一种数据的状态,从 0b000 开始,每失败一次加一,最多 0b100(即重试 4 次), /// 如果成功,将对应的三位设置为 0b111。 /// 当所有任务都成功或者由于尝试次数过多失败,为 status 最高位打上标记 1,将来不再继续尝试。 +#[derive(Clone)] pub struct Status(u32); impl Status { @@ -20,13 +21,7 @@ impl Status { Self(status) } - /// 从低到高检查状态,如果该位置的任务应该继续尝试执行,则返回 true,否则返回 false - fn should_run(&self, size: usize) -> Vec { - assert!(size < 10, "u32 can only store 10 status"); - (0..size).map(|x| self.check_continue(x)).collect() - } - - /// 一般仅需要被内部调用 + /// 一般仅需要被内部调用,用来设置最高位的标记 fn set_flag(&mut self, handled: bool) { if handled { self.0 |= 1 << 31; @@ -35,6 +30,19 @@ impl Status { } } + /// 从低到高检查状态,如果该位置的任务应该继续尝试执行,则返回 true,否则返回 false + fn should_run(&self, size: usize) -> Vec { + assert!(size < 10, "u32 can only store 10 status"); + (0..size).map(|x| self.check_continue(x)).collect() + } + + /// 如果任务的执行次数小于 STATUS_MAX_RETRY,说明可以继续运行 + fn check_continue(&self, offset: usize) -> bool { + assert!(offset < 10, "u32 can only store 10 status"); + self.get_status(offset) < STATUS_MAX_RETRY + } + + /// 根据任务结果更新状态,如果任务成功,设置为 STATUS_OK,否则加一 fn update_status(&mut self, result: &[Result<()>]) { assert!(result.len() < 10, "u32 can only store 10 status"); for (i, res) in result.iter().enumerate() { @@ -46,16 +54,12 @@ impl Status { } } - fn check_continue(&self, offset: usize) -> bool { - assert!(offset < 10, "u32 can only store 10 status"); - let helper = !0u32; - let sub_status = self.0 & (helper << (offset * 3)) & (helper >> (32 - 3 * offset - 3)); - sub_status < STATUS_MAX_RETRY - } - fn set_result(&mut self, result: &Result<()>, offset: usize) { if result.is_ok() { - self.set_ok(offset); + // 如果任务已经执行到最大次数,那么此时 Result 也是 Ok,此时不应该更新状态 + if self.get_status(offset) < STATUS_MAX_RETRY { + self.set_ok(offset); + } } else { self.plus_one(offset); } @@ -68,6 +72,11 @@ impl Status { fn set_ok(&mut self, offset: usize) { self.0 |= STATUS_OK << (3 * offset); } + + fn get_status(&self, offset: usize) -> u32 { + let helper = !0u32; + self.0 & (helper << (offset * 3)) & (helper >> (32 - 3 * offset - 3)) + } } impl From for u32 { @@ -77,6 +86,7 @@ impl From for u32 { } /// 从前到后分别表示:视频封面、分页下载、视频信息 +#[derive(Clone)] pub struct VideoStatus(Status); impl VideoStatus { @@ -101,6 +111,7 @@ impl From for u32 { } /// 从前到后分别表示:视频封面、视频内容、视频信息 +#[derive(Clone)] pub struct PageStatus(Status); impl PageStatus { @@ -123,3 +134,22 @@ impl From for u32 { status.0.into() } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_status() { + let mut status = Status::new(0); + assert_eq!(status.should_run(3), vec![true, true, true]); + for count in 1..=3 { + status.update_status(&[Err("".into()), Ok(()), Ok(())]); + assert_eq!(status.should_run(3), vec![true, false, false]); + assert_eq!(u32::from(status.clone()), 0b111_111_000 + count); + } + status.update_status(&[Err("".into()), Ok(()), Ok(())]); + assert_eq!(status.should_run(3), vec![false, false, false]); + assert_eq!(u32::from(status), 0b111_111_100 | Status::handled()); + } +}