mz_repr/
network_policy_id.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10use std::fmt;
11use std::str::FromStr;
12
13use anyhow::{Error, anyhow};
14use columnation::{Columnation, CopyRegion};
15use mz_lowertest::MzReflect;
16use proptest_derive::Arbitrary;
17use serde::{Deserialize, Serialize};
18
19const SYSTEM_CHAR: char = 's';
20const USER_CHAR: char = 'u';
21
22/// The identifier for a network policy.
23#[derive(
24    Arbitrary,
25    Clone,
26    Copy,
27    Debug,
28    Eq,
29    PartialEq,
30    Ord,
31    PartialOrd,
32    Hash,
33    Serialize,
34    Deserialize,
35    MzReflect,
36)]
37pub enum NetworkPolicyId {
38    System(u64),
39    User(u64),
40}
41
42impl NetworkPolicyId {
43    pub fn is_system(&self) -> bool {
44        matches!(self, Self::System(_))
45    }
46
47    pub fn is_user(&self) -> bool {
48        matches!(self, Self::User(_))
49    }
50
51    pub fn is_builtin(&self) -> bool {
52        self.is_system()
53    }
54}
55
56impl FromStr for NetworkPolicyId {
57    type Err = Error;
58
59    fn from_str(s: &str) -> Result<Self, Self::Err> {
60        fn parse_u64(s: &str) -> Result<u64, Error> {
61            if s.len() < 2 {
62                return Err(anyhow!("couldn't parse network policy id '{s}'"));
63            }
64            s[1..]
65                .parse()
66                .map_err(|_| anyhow!("couldn't parse network policy  id '{s}'"))
67        }
68
69        match s.chars().next() {
70            Some(SYSTEM_CHAR) => {
71                let val = parse_u64(s)?;
72                Ok(Self::System(val))
73            }
74            Some(USER_CHAR) => {
75                let val = parse_u64(s)?;
76                Ok(Self::User(val))
77            }
78            _ => Err(anyhow!("couldn't parse network policy  id '{s}'")),
79        }
80    }
81}
82
83impl fmt::Display for NetworkPolicyId {
84    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85        match self {
86            Self::System(id) => write!(f, "{SYSTEM_CHAR}{id}"),
87            Self::User(id) => write!(f, "{USER_CHAR}{id}"),
88        }
89    }
90}
91
92impl Columnation for NetworkPolicyId {
93    type InnerRegion = CopyRegion<NetworkPolicyId>;
94}
95
96#[mz_ore::test]
97fn test_network_policy_id_parsing() {
98    let s = "s42";
99    let network_policy_id: NetworkPolicyId = s.parse().unwrap();
100    assert_eq!(NetworkPolicyId::System(42), network_policy_id);
101    assert_eq!(s, network_policy_id.to_string());
102
103    let s = "u666";
104    let network_policy_id: NetworkPolicyId = s.parse().unwrap();
105    assert_eq!(NetworkPolicyId::User(666), network_policy_id);
106    assert_eq!(s, network_policy_id.to_string());
107
108    let s = "d23";
109    mz_ore::assert_err!(s.parse::<NetworkPolicyId>());
110
111    let s = "asfje90uf23i";
112    mz_ore::assert_err!(s.parse::<NetworkPolicyId>());
113
114    let s = "";
115    mz_ore::assert_err!(s.parse::<NetworkPolicyId>());
116}