php_literal_parser/
lib.rs

1//! Parser for php literals.
2//!
3//! Allows parsing of php string, bool, number and array literals.
4//!
5//! ## Usage
6//!
7//! Parse into a generic representation
8//!
9//! ```rust
10//! use php_literal_parser::{from_str, Value};
11//! # use std::fmt::Debug;
12//! # use std::error::Error;
13//!
14//! # fn main() -> Result<(), Box<dyn Error>> {
15//! let map = from_str::<Value>(r#"["foo" => true, "nested" => ['foo' => false]]"#)?;
16//!
17//! assert_eq!(map["foo"], true);
18//! assert_eq!(map["nested"]["foo"], false);
19//! # Ok(())
20//! # }
21//! ```
22//!
23//! Or parse into a specific struct using serde
24//!
25//! ```rust
26//! use php_literal_parser::from_str;
27//! use serde::Deserialize;
28//! # use std::fmt::Debug;
29//! # use std::error::Error;
30//!
31//! #[derive(Debug, Deserialize, PartialEq)]
32//! struct Target {
33//!     foo: bool,
34//!     bars: Vec<u8>
35//! }
36//!
37//! # fn main() -> Result<(), Box<dyn Error>> {
38//! let target = from_str(r#"["foo" => true, "bars" => [1, 2, 3, 4,]]"#)?;
39//!
40//! assert_eq!(Target {
41//!     foo: true,
42//!     bars: vec![1,2,3,4]
43//! }, target);
44//! # Ok(())
45//! # }
46//! ```
47//!
48#![forbid(unsafe_code)]
49mod error;
50mod lexer;
51mod num;
52mod parser;
53mod serde_impl;
54mod string;
55
56use crate::string::is_array_key_numeric;
57pub use error::ParseError;
58use indexmap::IndexMap;
59use serde::de::{self, MapAccess, SeqAccess, Visitor};
60use serde::ser::{SerializeMap, SerializeSeq};
61use serde::{Deserialize, Deserializer, Serialize, Serializer};
62pub use serde_impl::from_str;
63use std::borrow::Borrow;
64use std::cmp::Ordering;
65use std::collections::HashMap;
66use std::convert::TryInto;
67use std::fmt::{Debug, Display, Formatter};
68use std::hash::{Hash, Hasher};
69use std::ops::Index;
70
71/// A php value, can be either a bool, int, float, string, an array or null
72///
73/// note that in php all arrays are associative and thus represented by a map in rust.
74///
75/// You can convert a `Value` into a regular rust type by pattern matching or using the `into_` functions.
76///
77/// ## Indexing
78///
79/// If the value is a php array, you can directly index into the `Value`, this will null if the `Value` is not an array
80/// or the key is not found
81///
82/// ```rust
83/// # use indexmap::indexmap;
84/// # use php_literal_parser::Value;
85/// #
86/// # fn main() {
87/// let value = Value::Array(indexmap!{
88///     "key".into() => "value".into(),
89///     10.into() => false.into()
90/// });
91/// assert_eq!(value["key"], "value");
92/// assert_eq!(value[10], false);
93/// assert!(value["not"]["found"].is_null());
94/// # }
95/// ```
96#[derive(Debug, PartialEq, Clone)]
97pub enum Value {
98    Bool(bool),
99    Int(i64),
100    Float(f64),
101    String(String),
102    Array(IndexMap<Key, Value>),
103    Null,
104}
105
106impl Value {
107    /// Check if the value is a bool
108    pub fn is_bool(&self) -> bool {
109        matches!(self, Value::Bool(_))
110    }
111
112    /// Check if the value is an integer
113    pub fn is_int(&self) -> bool {
114        matches!(self, Value::Int(_))
115    }
116
117    /// Check if the value is a float
118    pub fn is_float(&self) -> bool {
119        matches!(self, Value::Float(_))
120    }
121
122    /// Check if the value is a string
123    pub fn is_string(&self) -> bool {
124        matches!(self, Value::String(_))
125    }
126
127    /// Check if the value is an array
128    pub fn is_array(&self) -> bool {
129        matches!(self, Value::Array(_))
130    }
131
132    /// Check if the value is null
133    pub fn is_null(&self) -> bool {
134        matches!(self, Value::Null)
135    }
136
137    /// Convert the value into a bool if it is one
138    pub fn into_bool(self) -> Option<bool> {
139        match self {
140            Value::Bool(bool) => Some(bool),
141            _ => None,
142        }
143    }
144
145    /// Convert the value into a int if it is one
146    pub fn into_int(self) -> Option<i64> {
147        match self {
148            Value::Int(int) => Some(int),
149            _ => None,
150        }
151    }
152
153    /// Convert the value into a float if it is one
154    pub fn into_float(self) -> Option<f64> {
155        match self {
156            Value::Float(float) => Some(float),
157            _ => None,
158        }
159    }
160
161    /// Convert the value into a string if it is one
162    pub fn into_string(self) -> Option<String> {
163        match self {
164            Value::String(string) => Some(string),
165            _ => None,
166        }
167    }
168
169    /// Convert the value into a map if it is one
170    pub fn into_map(self) -> Option<IndexMap<Key, Value>> {
171        match self {
172            Value::Array(map) => Some(map),
173            _ => None,
174        }
175    }
176
177    /// Get the value as &str if it is a string
178    pub fn as_str(&self) -> Option<&str> {
179        match self {
180            Value::String(str) => Some(str.as_str()),
181            _ => None,
182        }
183    }
184
185    /// Get the value as i64 if it is an int
186    pub fn as_int(&self) -> Option<i64> {
187        match self {
188            Value::Int(int) => Some(*int),
189            _ => None,
190        }
191    }
192
193    /// Get the value as f64 if it is a float
194    pub fn as_float(&self) -> Option<f64> {
195        match self {
196            Value::Float(float) => Some(*float),
197            _ => None,
198        }
199    }
200
201    /// Iterate over array key and value pairs if it is an array
202    pub fn iter(&self) -> impl Iterator<Item = (&Key, &Value)> {
203        let map = match self {
204            Value::Array(map) => Some(map),
205            _ => None,
206        };
207        map.into_iter().flat_map(|map| map.iter())
208    }
209
210    /// Iterate over array keys if it is an array
211    pub fn keys(&self) -> impl Iterator<Item = &Key> {
212        self.iter().map(|(key, _value)| key)
213    }
214
215    /// Iterate over array values if it is an array
216    pub fn values(&self) -> impl Iterator<Item = &Value> {
217        self.iter().map(|(_key, value)| value)
218    }
219}
220
221impl PartialEq<bool> for Value {
222    fn eq(&self, other: &bool) -> bool {
223        match self {
224            Value::Bool(bool) => bool == other,
225            _ => false,
226        }
227    }
228}
229
230impl PartialEq<i64> for Value {
231    fn eq(&self, other: &i64) -> bool {
232        match self {
233            Value::Int(int) => int == other,
234            _ => false,
235        }
236    }
237}
238
239impl PartialEq<f64> for Value {
240    fn eq(&self, other: &f64) -> bool {
241        match self {
242            Value::Float(float) => float == other,
243            _ => false,
244        }
245    }
246}
247
248impl PartialEq<String> for Value {
249    fn eq(&self, other: &String) -> bool {
250        match self {
251            Value::String(str) => str == other,
252            _ => false,
253        }
254    }
255}
256
257impl PartialEq<&str> for Value {
258    fn eq(&self, other: &&str) -> bool {
259        match self {
260            Value::String(str) => str.as_str() == *other,
261            _ => false,
262        }
263    }
264}
265
266impl From<bool> for Value {
267    fn from(value: bool) -> Self {
268        Value::Bool(value)
269    }
270}
271
272impl From<i64> for Value {
273    fn from(value: i64) -> Self {
274        Value::Int(value)
275    }
276}
277
278impl From<f64> for Value {
279    fn from(value: f64) -> Self {
280        Value::Float(value)
281    }
282}
283
284impl From<String> for Value {
285    fn from(value: String) -> Self {
286        Value::String(value)
287    }
288}
289
290impl From<&str> for Value {
291    fn from(value: &str) -> Self {
292        Value::String(value.into())
293    }
294}
295
296impl From<IndexMap<Key, Value>> for Value {
297    fn from(value: IndexMap<Key, Value>) -> Self {
298        Value::Array(value)
299    }
300}
301
302impl From<HashMap<Key, Value>> for Value {
303    fn from(value: HashMap<Key, Value>) -> Self {
304        Value::Array(value.into_iter().collect())
305    }
306}
307
308impl Display for Value {
309    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
310        match self {
311            Value::Bool(val) => write!(f, "{val}"),
312            Value::Int(val) => write!(f, "{val}"),
313            Value::Float(val) => write!(f, "{val}"),
314            Value::String(val) => write!(f, "{val}"),
315            Value::Array(val) => {
316                writeln!(f, "[")?;
317                for (key, value) in val.iter() {
318                    write!(f, "\t{key} => {value},")?;
319                }
320                write!(f, "]")
321            }
322            Value::Null => write!(f, "null"),
323        }
324    }
325}
326
327/// A php array key, can be either an int or string
328#[derive(Debug, Eq, Clone)]
329pub enum Key {
330    Int(i64),
331    String(String),
332}
333
334impl Hash for Key {
335    // a hash implementation which doesn't include the enum discriminant
336    // that hash hash("foo") == hash(Key::String("foo"))
337    fn hash<H: Hasher>(&self, state: &mut H) {
338        match self {
339            Key::Int(int) => int.hash(state),
340            Key::String(str) => str.hash(state),
341        }
342    }
343}
344
345impl From<i64> for Key {
346    fn from(int: i64) -> Self {
347        Key::Int(int)
348    }
349}
350
351impl From<String> for Key {
352    fn from(str: String) -> Self {
353        Key::String(str)
354    }
355}
356
357impl From<&str> for Key {
358    fn from(str: &str) -> Self {
359        Key::String(str.into())
360    }
361}
362
363impl Serialize for Key {
364    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
365    where
366        S: Serializer,
367    {
368        match self {
369            Key::Int(i) => serializer.serialize_i64(*i),
370            Key::String(s) => serializer.serialize_str(s),
371        }
372    }
373}
374
375impl Key {
376    /// Check if the key is an integer
377    pub fn is_int(&self) -> bool {
378        matches!(self, Key::Int(_))
379    }
380
381    /// Check if the key is a string
382    pub fn is_string(&self) -> bool {
383        matches!(self, Key::String(_))
384    }
385
386    /// Convert the key into a bool if it is one
387    pub fn into_int(self) -> Option<i64> {
388        match self {
389            Key::Int(int) => Some(int),
390            _ => None,
391        }
392    }
393
394    /// Convert the key into a string if it is one
395    pub fn into_string(self) -> Option<String> {
396        match self {
397            Key::String(string) => Some(string),
398            _ => None,
399        }
400    }
401
402    /// Get the key as &str if it is a string
403    pub fn as_str(&self) -> Option<&str> {
404        match self {
405            Key::String(str) => Some(str.as_str()),
406            _ => None,
407        }
408    }
409
410    /// Get the key as i64 if it is an int
411    pub fn as_int(&self) -> Option<i64> {
412        match self {
413            Key::Int(int) => Some(*int),
414            _ => None,
415        }
416    }
417}
418
419impl PartialOrd for Key {
420    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
421        Some(self.cmp(other))
422    }
423}
424
425impl Ord for Key {
426    fn cmp(&self, other: &Self) -> Ordering {
427        match (self, other) {
428            (Key::Int(self_int), Key::Int(other_int)) => self_int.cmp(other_int),
429            (Key::String(self_string), Key::String(other_string)) => self_string.cmp(other_string),
430            (Key::String(self_string), Key::Int(other_int)) => {
431                self_string.cmp(&other_int.to_string())
432            }
433            (Key::Int(self_int), Key::String(other_string)) => {
434                self_int.to_string().cmp(other_string)
435            }
436        }
437    }
438}
439
440impl PartialEq for Key {
441    fn eq(&self, other: &Self) -> bool {
442        match (self, other) {
443            (Key::Int(self_int), Key::Int(other_int)) => self_int.eq(other_int),
444            (Key::String(self_string), Key::String(other_string)) => self_string.eq(other_string),
445            (Key::String(self_string), Key::Int(other_int)) => {
446                self_string.eq(&other_int.to_string())
447            }
448            (Key::Int(self_int), Key::String(other_string)) => {
449                self_int.to_string().eq(other_string)
450            }
451        }
452    }
453}
454
455impl Borrow<str> for Key {
456    fn borrow(&self) -> &str {
457        match self {
458            Key::String(str) => str.as_str(),
459            _ => panic!(),
460        }
461    }
462}
463
464impl<Q: ?Sized> Index<&Q> for Value
465where
466    Key: Borrow<Q>,
467    Q: Eq + Hash,
468{
469    type Output = Value;
470
471    fn index(&self, index: &Q) -> &Self::Output {
472        match self {
473            Value::Array(map) => map.get(index).unwrap_or(&Value::Null),
474            _ => &Value::Null,
475        }
476    }
477}
478
479impl Index<Key> for Value {
480    type Output = Value;
481
482    fn index(&self, index: Key) -> &Self::Output {
483        match self {
484            Value::Array(map) => map.get(&index).unwrap_or(&Value::Null),
485            _ => &Value::Null,
486        }
487    }
488}
489
490impl Index<i64> for Value {
491    type Output = Value;
492
493    fn index(&self, index: i64) -> &Self::Output {
494        match self {
495            Value::Array(map) => map.get(&Key::Int(index)).unwrap_or(&Value::Null),
496            _ => &Value::Null,
497        }
498    }
499}
500
501impl Display for Key {
502    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
503        match self {
504            Key::Int(val) => write!(f, "{val}"),
505            Key::String(val) => write!(f, "{val}"),
506        }
507    }
508}
509
510#[test]
511fn test_index() {
512    use indexmap::indexmap;
513    let map = Value::Array(indexmap! {
514        Key::String("key".to_string()) => Value::String("value".to_string()),
515        Key::Int(1) => Value::Bool(true),
516    });
517    assert_eq!(map["key"], "value");
518    assert_eq!(map[1], true);
519    assert_eq!(map[Key::Int(1)], true);
520}
521
522struct ValueVisitor;
523
524impl<'de> Visitor<'de> for ValueVisitor {
525    type Value = Value;
526
527    fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
528        formatter.write_str("any php literal")
529    }
530
531    fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
532    where
533        E: de::Error,
534    {
535        Ok(Value::Bool(v))
536    }
537
538    fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E>
539    where
540        E: de::Error,
541    {
542        Ok(Value::Int(v.into()))
543    }
544
545    fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
546    where
547        E: de::Error,
548    {
549        Ok(Value::Int(v.into()))
550    }
551
552    fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
553    where
554        E: de::Error,
555    {
556        Ok(Value::Int(v.into()))
557    }
558
559    fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
560    where
561        E: de::Error,
562    {
563        Ok(Value::Int(v))
564    }
565
566    fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
567    where
568        E: de::Error,
569    {
570        Ok(Value::Int(v.into()))
571    }
572
573    fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
574    where
575        E: de::Error,
576    {
577        Ok(Value::Int(v.into()))
578    }
579
580    fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
581    where
582        E: de::Error,
583    {
584        Ok(Value::Int(v.into()))
585    }
586
587    fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
588    where
589        E: de::Error,
590    {
591        Ok(Value::Int(v.try_into().map_err(|_| {
592            E::custom(format!("i64 out of range: {v}"))
593        })?))
594    }
595
596    fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
597    where
598        E: de::Error,
599    {
600        Ok(Value::Float(v.into()))
601    }
602
603    fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
604    where
605        E: de::Error,
606    {
607        Ok(Value::Float(v))
608    }
609
610    fn visit_char<E>(self, v: char) -> Result<Self::Value, E>
611    where
612        E: de::Error,
613    {
614        Ok(Value::String(v.to_string()))
615    }
616
617    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
618    where
619        E: de::Error,
620    {
621        Ok(Value::String(v.into()))
622    }
623
624    fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
625    where
626        E: de::Error,
627    {
628        Ok(Value::String(v.into()))
629    }
630
631    fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
632    where
633        E: de::Error,
634    {
635        Ok(Value::String(v))
636    }
637
638    fn visit_unit<E>(self) -> Result<Self::Value, E>
639    where
640        E: de::Error,
641    {
642        Ok(Value::Null)
643    }
644
645    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, <A as SeqAccess<'de>>::Error>
646    where
647        A: SeqAccess<'de>,
648    {
649        let mut result = IndexMap::new();
650        let mut next_key = 0;
651        while let Some(value) = seq.next_element::<Value>()? {
652            let key = Key::Int(next_key);
653            next_key += 1;
654            result.insert(key, value);
655        }
656        Ok(Value::Array(result))
657    }
658
659    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, <A as MapAccess<'de>>::Error>
660    where
661        A: MapAccess<'de>,
662    {
663        let mut result = IndexMap::new();
664        while let Some((key, value)) = map.next_entry()? {
665            result.insert(key, value);
666        }
667        Ok(Value::Array(result))
668    }
669}
670
671impl<'de> Deserialize<'de> for Value {
672    fn deserialize<D>(deserializer: D) -> Result<Value, D::Error>
673    where
674        D: Deserializer<'de>,
675    {
676        deserializer.deserialize_any(ValueVisitor)
677    }
678}
679
680impl Serialize for Value {
681    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
682    where
683        S: Serializer,
684    {
685        match self {
686            Value::Bool(b) => serializer.serialize_bool(*b),
687            Value::Int(i) => serializer.serialize_i64(*i),
688            Value::Float(f) => serializer.serialize_f64(*f),
689            Value::String(s) => serializer.serialize_str(s),
690            Value::Array(a) => {
691                if a.keys()
692                    .enumerate()
693                    .all(|(i, k)| k.as_int() == Some(i as i64))
694                {
695                    let mut seq = serializer.serialize_seq(Some(a.len()))?;
696                    for value in a.values() {
697                        seq.serialize_element(value)?;
698                    }
699                    seq.end()
700                } else {
701                    let mut map = serializer.serialize_map(Some(a.len()))?;
702                    for (key, value) in a {
703                        map.serialize_key(key)?;
704                        map.serialize_value(value)?;
705                    }
706                    map.end()
707                }
708            }
709            Value::Null => serializer.serialize_none(),
710        }
711    }
712}
713
714struct KeyVisitor;
715
716impl<'de> Visitor<'de> for KeyVisitor {
717    type Value = Key;
718
719    fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
720        formatter.write_str("a string, number, bool or null")
721    }
722
723    fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
724    where
725        E: de::Error,
726    {
727        Ok(Key::Int(if v { 1 } else { 0 }))
728    }
729
730    fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E>
731    where
732        E: de::Error,
733    {
734        Ok(Key::Int(v.into()))
735    }
736
737    fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
738    where
739        E: de::Error,
740    {
741        Ok(Key::Int(v.into()))
742    }
743
744    fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
745    where
746        E: de::Error,
747    {
748        Ok(Key::Int(v.into()))
749    }
750
751    fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
752    where
753        E: de::Error,
754    {
755        Ok(Key::Int(v))
756    }
757
758    fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
759    where
760        E: de::Error,
761    {
762        Ok(Key::Int(v.into()))
763    }
764
765    fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
766    where
767        E: de::Error,
768    {
769        Ok(Key::Int(v.into()))
770    }
771
772    fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
773    where
774        E: de::Error,
775    {
776        Ok(Key::Int(v.into()))
777    }
778
779    fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
780    where
781        E: de::Error,
782    {
783        Ok(Key::Int(v.try_into().map_err(|_| {
784            E::custom(format!("i64 out of range: {v}"))
785        })?))
786    }
787
788    fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
789    where
790        E: de::Error,
791    {
792        Ok(Key::Int(v as i64))
793    }
794
795    fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
796    where
797        E: de::Error,
798    {
799        Ok(Key::Int(v as i64))
800    }
801
802    fn visit_char<E>(self, v: char) -> Result<Self::Value, E>
803    where
804        E: de::Error,
805    {
806        Ok(Key::String(v.to_string()))
807    }
808
809    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
810    where
811        E: de::Error,
812    {
813        self.visit_string(v.into())
814    }
815
816    fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
817    where
818        E: de::Error,
819    {
820        self.visit_string(v.into())
821    }
822
823    fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
824    where
825        E: de::Error,
826    {
827        if is_array_key_numeric(&v) {
828            Ok(Key::Int(v.parse().unwrap()))
829        } else {
830            Ok(Key::String(v))
831        }
832    }
833
834    fn visit_unit<E>(self) -> Result<Self::Value, E>
835    where
836        E: de::Error,
837    {
838        Ok(Key::String(String::from("")))
839    }
840}
841
842impl<'de> Deserialize<'de> for Key {
843    fn deserialize<D>(deserializer: D) -> Result<Key, D::Error>
844    where
845        D: Deserializer<'de>,
846    {
847        deserializer.deserialize_any(KeyVisitor)
848    }
849}