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}