nvme_test/command_match.rs
1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! A `CommandMatch` builder
5
6use nvme_resources::fault::CommandMatch;
7use nvme_spec::Command;
8use zerocopy::FromZeros;
9use zerocopy::IntoBytes;
10
11/// A builder that can be used to generate `CommandMatch` patterns.
12/// Usage:
13/// Match to any admin command with cid == 10
14/// ```rust
15/// # use nvme_spec::Cdw0;
16/// # use nvme_test::command_match::CommandMatchBuilder;
17/// CommandMatchBuilder::new().match_cdw0(
18/// Cdw0::new().with_cid(10).into(),
19/// Cdw0::new().with_cid(u16::MAX).into(), // Mask all the cid bits for an exact match on cid(10)
20/// )
21/// .build();
22/// ```
23///
24/// Match to any admin command with opcode == 0x01
25/// ```rust
26/// # use nvme_test::command_match::CommandMatchBuilder;
27/// CommandMatchBuilder::new().match_cdw0_opcode(0x01).build();
28/// ```
29pub struct CommandMatchBuilder {
30 command: Command,
31 mask: Command,
32}
33
34impl CommandMatchBuilder {
35 /// Generates a matcher for every command
36 pub fn new() -> Self {
37 CommandMatchBuilder {
38 command: Command::new_zeroed(),
39 mask: Command::new_zeroed(),
40 }
41 }
42
43 /// Configure to match to an opcode. See struct docs for usage
44 pub fn match_cdw0_opcode(&mut self, opcode: u8) -> &mut Self {
45 self.command.cdw0 = self.command.cdw0.with_opcode(opcode);
46 self.mask.cdw0 = self.mask.cdw0.with_opcode(u8::MAX);
47 self
48 }
49
50 /// Configure to match a cdw0 pattern. Mask specifies which bits to match on.
51 /// See struct docs for usage
52 pub fn match_cdw0(&mut self, cdw0: u32, mask: u32) -> &mut Self {
53 self.command.cdw0 = cdw0.into();
54 self.mask.cdw0 = mask.into();
55 self
56 }
57
58 /// Configure to match a cdw10 pattern. Mask specifies which bits to match on.
59 /// See struct docs for usage
60 pub fn match_cdw10(&mut self, cdw10: u32, mask: u32) -> &mut Self {
61 self.command.cdw10 = cdw10;
62 self.mask.cdw10 = mask;
63 self
64 }
65
66 /// Returns a `CommandMatch` corresponding to the builder configuration
67 pub fn build(&self) -> CommandMatch {
68 CommandMatch {
69 command: self.command,
70 mask: self
71 .mask
72 .as_bytes()
73 .try_into()
74 .expect("mask should be 64 bytes"),
75 }
76 }
77}
78
79/// Given a CommandMatch and a Command, return whether the command matches the pattern
80pub fn match_command_pattern(match_pattern: &CommandMatch, command: &Command) -> bool {
81 let command_lhs = match_pattern.command.as_bytes();
82 let mask_bytes = &match_pattern.mask;
83
84 let command_rhs = command.as_bytes();
85
86 !command_lhs
87 .iter()
88 .zip(command_rhs.iter())
89 .zip(mask_bytes.iter())
90 .any(|((lhs, rhs), mask)| ((lhs ^ rhs) & mask) != 0)
91}