• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

davidcole1340 / ext-php-rs / 16431384382

22 Jul 2025 12:30AM UTC coverage: 27.022% (-0.1%) from 27.144%
16431384382

Pull #535

github

web-flow
Merge ccce30c62 into 6869625f4
Pull Request #535: feat(array): introducing BTreeMap conversion and refactoring HashMap conversion

7 of 36 new or added lines in 4 files covered. (19.44%)

78 existing lines in 1 file now uncovered.

1126 of 4167 relevant lines covered (27.02%)

5.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

51.43
/src/types/array/array_key.rs
1
use crate::{convert::FromZval, error::Error, flags::DataType, types::Zval};
2
use std::str::FromStr;
3
use std::{convert::TryFrom, fmt::Display};
4

5
/// Represents the key of a PHP array, which can be either a long or a string.
6
#[derive(Debug, Clone, PartialEq)]
7
pub enum ArrayKey<'a> {
8
    /// A numerical key.
9
    /// In Zend API it's represented by `u64` (`zend_ulong`), so the value needs
10
    /// to be cast to `zend_ulong` before passing into Zend functions.
11
    Long(i64),
12
    /// A string key.
13
    String(String),
14
    /// A string key by reference.
15
    Str(&'a str),
16
}
17

18
impl From<String> for ArrayKey<'_> {
19
    fn from(value: String) -> Self {
×
NEW
20
        if let Ok(index) = i64::from_str(value.as_str()) {
×
NEW
21
            Self::Long(index)
×
22
        } else {
NEW
23
            Self::String(value)
×
24
        }
25
    }
26
}
27

28
impl TryFrom<ArrayKey<'_>> for String {
29
    type Error = Error;
30

31
    fn try_from(value: ArrayKey<'_>) -> Result<Self, Self::Error> {
14✔
32
        match value {
14✔
33
            ArrayKey::String(s) => Ok(s),
16✔
34
            ArrayKey::Str(s) => Ok(s.to_string()),
2✔
35
            ArrayKey::Long(l) => Ok(l.to_string()),
5✔
36
        }
37
    }
38
}
39

40
impl TryFrom<ArrayKey<'_>> for i64 {
41
    type Error = Error;
42

43
    fn try_from(value: ArrayKey<'_>) -> Result<Self, Self::Error> {
11✔
44
        match value {
11✔
45
            ArrayKey::Long(i) => Ok(i),
6✔
46
            ArrayKey::String(s) => s.parse::<i64>().map_err(|_| Error::InvalidProperty),
9✔
47
            ArrayKey::Str(s) => s.parse::<i64>().map_err(|_| Error::InvalidProperty),
8✔
48
        }
49
    }
50
}
51

52
impl ArrayKey<'_> {
53
    /// Check if the key is an integer.
54
    ///
55
    /// # Returns
56
    ///
57
    /// Returns true if the key is an integer, false otherwise.
58
    #[must_use]
59
    pub fn is_long(&self) -> bool {
×
60
        match self {
×
61
            ArrayKey::Long(_) => true,
×
62
            ArrayKey::String(_) | ArrayKey::Str(_) => false,
×
63
        }
64
    }
65
}
66

67
impl Display for ArrayKey<'_> {
68
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
×
69
        match self {
×
70
            ArrayKey::Long(key) => write!(f, "{key}"),
×
71
            ArrayKey::String(key) => write!(f, "{key}"),
×
72
            ArrayKey::Str(key) => write!(f, "{key}"),
×
73
        }
74
    }
75
}
76

77
impl<'a> From<&'a str> for ArrayKey<'a> {
78
    fn from(value: &'a str) -> ArrayKey<'a> {
27✔
79
        if let Ok(index) = i64::from_str(value) {
32✔
NEW
80
            Self::Long(index)
×
81
        } else {
82
            ArrayKey::Str(value)
22✔
83
        }
84
    }
85
}
86

87
impl<'a> From<i64> for ArrayKey<'a> {
88
    fn from(index: i64) -> ArrayKey<'a> {
20✔
89
        ArrayKey::Long(index)
20✔
90
    }
91
}
92

93
impl<'a> FromZval<'a> for ArrayKey<'_> {
94
    const TYPE: DataType = DataType::String;
95

96
    fn from_zval(zval: &'a Zval) -> Option<Self> {
22✔
97
        if let Some(key) = zval.long() {
35✔
98
            return Some(ArrayKey::Long(key));
×
99
        }
100
        if let Some(key) = zval.string() {
18✔
101
            return Some(ArrayKey::String(key));
×
102
        }
103
        None
×
104
    }
105
}
106

107
#[cfg(test)]
108
#[cfg(feature = "embed")]
109
#[allow(clippy::unwrap_used)]
110
mod tests {
111
    use crate::error::Error;
112
    use crate::types::ArrayKey;
113

114
    #[test]
115
    fn test_string_try_from_array_key() {
116
        let key = ArrayKey::String("test".to_string());
117
        let result: crate::error::Result<String, _> = key.try_into();
118
        assert!(result.is_ok());
119
        assert_eq!(result.unwrap(), "test".to_string());
120

121
        let key = ArrayKey::Str("test");
122
        let result: crate::error::Result<String, _> = key.try_into();
123
        assert!(result.is_ok());
124
        assert_eq!(result.unwrap(), "test".to_string());
125

126
        let key = ArrayKey::Long(42);
127
        let result: crate::error::Result<String, _> = key.try_into();
128
        assert_eq!(result.unwrap(), "42".to_string());
129

130
        let key = ArrayKey::String("42".to_string());
131
        let result: crate::error::Result<String, _> = key.try_into();
132
        assert!(result.is_ok());
133
        assert_eq!(result.unwrap(), "42".to_string());
134

135
        let key = ArrayKey::Str("123");
136
        let result: crate::error::Result<i64, _> = key.try_into();
137
        assert!(result.is_ok());
138
        assert_eq!(result.unwrap(), 123);
139
    }
140

141
    #[test]
142
    fn test_i64_try_from_array_key() {
143
        let key = ArrayKey::Long(42);
144
        let result: crate::error::Result<i64, _> = key.try_into();
145
        assert!(result.is_ok());
146
        assert_eq!(result.unwrap(), 42);
147

148
        let key = ArrayKey::String("42".to_string());
149
        let result: crate::error::Result<i64, _> = key.try_into();
150
        assert!(result.is_ok());
151
        assert_eq!(result.unwrap(), 42);
152

153
        let key = ArrayKey::Str("123");
154
        let result: crate::error::Result<i64, _> = key.try_into();
155
        assert!(result.is_ok());
156
        assert_eq!(result.unwrap(), 123);
157

158
        let key = ArrayKey::String("not a number".to_string());
159
        let result: crate::error::Result<i64, _> = key.try_into();
160
        assert!(result.is_err());
161
        assert!(matches!(result.unwrap_err(), Error::InvalidProperty));
162
    }
163
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc