Skip to main content

edgar_rs/
cik.rs

1use std::fmt;
2
3use serde::{Deserialize, Serialize};
4
5/// A Central Index Key (CIK) number identifying a company in SEC EDGAR.
6///
7/// CIK numbers are zero-padded to 10 digits in SEC URLs (e.g., `CIK0000320193`).
8/// This type handles formatting automatically.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10#[serde(transparent)]
11pub struct Cik(u64);
12
13impl Cik {
14    /// Creates a new CIK from a numeric value.
15    pub fn new(value: u64) -> Self {
16        Self(value)
17    }
18
19    /// Returns the raw numeric value.
20    pub fn as_u64(self) -> u64 {
21        self.0
22    }
23
24    /// Formats the CIK as a zero-padded 10-digit string (e.g., `"0000320193"`).
25    pub fn to_padded_string(self) -> String {
26        format!("{:010}", self.0)
27    }
28}
29
30impl fmt::Display for Cik {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        write!(f, "{}", self.0)
33    }
34}
35
36impl From<u64> for Cik {
37    fn from(value: u64) -> Self {
38        Self(value)
39    }
40}
41
42impl From<u32> for Cik {
43    fn from(value: u32) -> Self {
44        Self(value as u64)
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    #[test]
53    fn new_and_as_u64() {
54        let cik = Cik::new(320193);
55        assert_eq!(cik.as_u64(), 320193);
56    }
57
58    #[test]
59    fn to_padded_string_normal() {
60        assert_eq!(Cik::new(320193).to_padded_string(), "0000320193");
61    }
62
63    #[test]
64    fn to_padded_string_small() {
65        assert_eq!(Cik::new(1).to_padded_string(), "0000000001");
66    }
67
68    #[test]
69    fn to_padded_string_large() {
70        assert_eq!(Cik::new(1234567890).to_padded_string(), "1234567890");
71    }
72
73    #[test]
74    fn to_padded_string_zero() {
75        assert_eq!(Cik::new(0).to_padded_string(), "0000000000");
76    }
77
78    #[test]
79    fn display_shows_raw_number() {
80        assert_eq!(format!("{}", Cik::new(320193)), "320193");
81        assert_eq!(format!("{}", Cik::new(0)), "0");
82    }
83
84    #[test]
85    fn from_u64() {
86        let cik: Cik = 320193_u64.into();
87        assert_eq!(cik.as_u64(), 320193);
88    }
89
90    #[test]
91    fn from_u32() {
92        let cik: Cik = 320193_u32.into();
93        assert_eq!(cik.as_u64(), 320193);
94    }
95
96    #[test]
97    fn equality() {
98        assert_eq!(Cik::new(100), Cik::new(100));
99        assert_ne!(Cik::new(100), Cik::new(200));
100    }
101
102    #[test]
103    fn hash_consistent() {
104        use std::collections::HashSet;
105        let mut set = HashSet::new();
106        set.insert(Cik::new(320193));
107        assert!(set.contains(&Cik::new(320193)));
108        assert!(!set.contains(&Cik::new(1)));
109    }
110
111    #[test]
112    fn clone_and_copy() {
113        let a = Cik::new(42);
114        let b = a; // Copy
115        let c = a; // Also Copy
116        assert_eq!(a, b);
117        assert_eq!(a, c);
118    }
119
120    #[test]
121    fn serde_roundtrip() {
122        let cik = Cik::new(320193);
123        let json = serde_json::to_string(&cik).unwrap();
124        assert_eq!(json, "320193");
125        let deserialized: Cik = serde_json::from_str(&json).unwrap();
126        assert_eq!(deserialized, cik);
127    }
128
129    #[test]
130    fn serde_transparent_in_struct() {
131        #[derive(serde::Serialize, serde::Deserialize, PartialEq, Debug)]
132        struct Wrapper {
133            cik: Cik,
134        }
135        let w = Wrapper {
136            cik: Cik::new(320193),
137        };
138        let json = serde_json::to_string(&w).unwrap();
139        assert_eq!(json, r#"{"cik":320193}"#);
140        let back: Wrapper = serde_json::from_str(&json).unwrap();
141        assert_eq!(back, w);
142    }
143}