ldap_types/
conversion.rs

1//! Types and traits related to the conversion of LDAP types to Rust types
2
3/// represents the representation for a type that could be returned by a search
4/// query, zero, one or multiple Strings and zero, one or
5/// multiple binary values (`Vec<u8>`)
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct LdapAttributeResultValues {
8    /// the DN of the entry we convert
9    pub entry_dn: String,
10    /// the name of the attribute
11    pub attribute_name: String,
12    /// the String result values
13    pub string_values: Vec<String>,
14    /// the binary result values
15    pub binary_values: Vec<Vec<u8>>,
16}
17
18/// adds a method to ldap3::SearchEntry to extract the LdapResultValue
19/// for a given attribute
20#[cfg(feature = "ldap3")]
21pub trait SearchEntryExt {
22    /// extracts the results for a given attribute
23    fn attribute_results(&self, attribute_name: &str) -> LdapAttributeResultValues;
24}
25
26#[cfg(feature = "ldap3")]
27impl SearchEntryExt for ldap3::SearchEntry {
28    fn attribute_results(&self, attribute_name: &str) -> LdapAttributeResultValues {
29        let string_values = self.attrs.get(attribute_name);
30        let binary_values = self.bin_attrs.get(attribute_name);
31        LdapAttributeResultValues {
32            entry_dn: self.dn.to_owned(),
33            attribute_name: attribute_name.to_owned(),
34            string_values: string_values.map_or(Vec::new(), |v| v.to_vec()),
35            binary_values: binary_values.map_or(Vec::new(), |v| v.to_vec()),
36        }
37    }
38}
39
40/// a primitive result that can be converted from an Ldap type that is returned
41/// as a String
42pub trait FromStringLdapType {
43    /// the type of error when the conversion fails
44    type Error;
45
46    /// parse this type from a String returned by an LDAP search
47    ///
48    /// # Errors
49    ///
50    /// fails if the type could not be parsed
51    fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
52    where
53        Self: Sized;
54}
55
56impl FromStringLdapType for String {
57    type Error = std::convert::Infallible;
58
59    fn parse(_entry_dn: &str, _attribute_name: &str, value: String) -> Result<Self, Self::Error>
60    where
61        Self: Sized,
62    {
63        Ok(value)
64    }
65}
66
67/// error that occurs when a conversion encounters a value that it can not
68/// convert
69#[derive(Debug, Clone, PartialEq, Eq)]
70pub struct UnexpectedStringValue {
71    /// source entry DN
72    source_entry_dn: String,
73    /// source attribute name
74    source_attribute_name: String,
75    /// name of the type we couldn't convert the value to
76    conversion_target_name: String,
77    /// value that was encountered and could not be converted
78    unexpected_value: String,
79}
80
81impl std::fmt::Display for UnexpectedStringValue {
82    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83        write!(
84            f,
85            "Unexpected value in conversion of {} attribute {} to {}: {}",
86            self.source_entry_dn,
87            self.source_attribute_name,
88            self.conversion_target_name,
89            self.unexpected_value,
90        )
91    }
92}
93
94impl std::error::Error for UnexpectedStringValue {}
95
96impl FromStringLdapType for bool {
97    type Error = UnexpectedStringValue;
98
99    fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
100    where
101        Self: Sized,
102    {
103        match std::ops::Deref::deref(&value) {
104            "TRUE" => Ok(true),
105            "FALSE" => Ok(false),
106            v => Err(UnexpectedStringValue {
107                source_entry_dn: entry_dn.to_owned(),
108                source_attribute_name: attribute_name.to_owned(),
109                conversion_target_name: "bool".to_string(),
110                unexpected_value: v.to_owned(),
111            }),
112        }
113    }
114}
115
116impl FromStringLdapType for u8 {
117    type Error = UnexpectedStringValue;
118
119    fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
120    where
121        Self: Sized,
122    {
123        <Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
124            source_entry_dn: entry_dn.to_owned(),
125            source_attribute_name: attribute_name.to_owned(),
126            conversion_target_name: "u8".to_string(),
127            unexpected_value: value,
128        })
129    }
130}
131
132impl FromStringLdapType for i8 {
133    type Error = UnexpectedStringValue;
134
135    fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
136    where
137        Self: Sized,
138    {
139        <Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
140            source_entry_dn: entry_dn.to_owned(),
141            source_attribute_name: attribute_name.to_owned(),
142            conversion_target_name: "i8".to_string(),
143            unexpected_value: value,
144        })
145    }
146}
147
148impl FromStringLdapType for u16 {
149    type Error = UnexpectedStringValue;
150
151    fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
152    where
153        Self: Sized,
154    {
155        <Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
156            source_entry_dn: entry_dn.to_owned(),
157            source_attribute_name: attribute_name.to_owned(),
158            conversion_target_name: "u16".to_string(),
159            unexpected_value: value,
160        })
161    }
162}
163
164impl FromStringLdapType for i16 {
165    type Error = UnexpectedStringValue;
166
167    fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
168    where
169        Self: Sized,
170    {
171        <Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
172            source_entry_dn: entry_dn.to_owned(),
173            source_attribute_name: attribute_name.to_owned(),
174            conversion_target_name: "i16".to_string(),
175            unexpected_value: value,
176        })
177    }
178}
179
180impl FromStringLdapType for u32 {
181    type Error = UnexpectedStringValue;
182
183    fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
184    where
185        Self: Sized,
186    {
187        <Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
188            source_entry_dn: entry_dn.to_owned(),
189            source_attribute_name: attribute_name.to_owned(),
190            conversion_target_name: "u32".to_string(),
191            unexpected_value: value,
192        })
193    }
194}
195
196impl FromStringLdapType for i32 {
197    type Error = UnexpectedStringValue;
198
199    fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
200    where
201        Self: Sized,
202    {
203        <Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
204            source_entry_dn: entry_dn.to_owned(),
205            source_attribute_name: attribute_name.to_owned(),
206            conversion_target_name: "i32".to_string(),
207            unexpected_value: value,
208        })
209    }
210}
211
212impl FromStringLdapType for u64 {
213    type Error = UnexpectedStringValue;
214
215    fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
216    where
217        Self: Sized,
218    {
219        <Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
220            source_entry_dn: entry_dn.to_owned(),
221            source_attribute_name: attribute_name.to_owned(),
222            conversion_target_name: "u64".to_string(),
223            unexpected_value: value,
224        })
225    }
226}
227
228impl FromStringLdapType for i64 {
229    type Error = UnexpectedStringValue;
230
231    fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
232    where
233        Self: Sized,
234    {
235        <Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
236            source_entry_dn: entry_dn.to_owned(),
237            source_attribute_name: attribute_name.to_owned(),
238            conversion_target_name: "i64".to_string(),
239            unexpected_value: value,
240        })
241    }
242}
243
244impl FromStringLdapType for u128 {
245    type Error = UnexpectedStringValue;
246
247    fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
248    where
249        Self: Sized,
250    {
251        <Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
252            source_entry_dn: entry_dn.to_owned(),
253            source_attribute_name: attribute_name.to_owned(),
254            conversion_target_name: "u128".to_string(),
255            unexpected_value: value,
256        })
257    }
258}
259
260impl FromStringLdapType for i128 {
261    type Error = UnexpectedStringValue;
262
263    fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
264    where
265        Self: Sized,
266    {
267        <Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
268            source_entry_dn: entry_dn.to_owned(),
269            source_attribute_name: attribute_name.to_owned(),
270            conversion_target_name: "i128".to_string(),
271            unexpected_value: value,
272        })
273    }
274}
275
276impl FromStringLdapType for usize {
277    type Error = UnexpectedStringValue;
278
279    fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
280    where
281        Self: Sized,
282    {
283        <Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
284            source_entry_dn: entry_dn.to_owned(),
285            source_attribute_name: attribute_name.to_owned(),
286            conversion_target_name: "usize".to_string(),
287            unexpected_value: value,
288        })
289    }
290}
291
292impl FromStringLdapType for isize {
293    type Error = UnexpectedStringValue;
294
295    fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
296    where
297        Self: Sized,
298    {
299        <Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
300            source_entry_dn: entry_dn.to_owned(),
301            source_attribute_name: attribute_name.to_owned(),
302            conversion_target_name: "isize".to_string(),
303            unexpected_value: value,
304        })
305    }
306}
307
308#[cfg(feature = "chumsky")]
309impl FromStringLdapType for crate::basic::DistinguishedName {
310    type Error = UnexpectedStringValue;
311
312    fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
313    where
314        Self: Sized,
315    {
316        <Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
317            source_entry_dn: entry_dn.to_owned(),
318            source_attribute_name: attribute_name.to_owned(),
319            conversion_target_name: "DistinguishedName".to_string(),
320            unexpected_value: value,
321        })
322    }
323}
324
325impl FromStringLdapType for oid::ObjectIdentifier {
326    type Error = UnexpectedStringValue;
327
328    fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
329    where
330        Self: Sized,
331    {
332        <Self as TryFrom<&str>>::try_from(&value).map_err(|_err| UnexpectedStringValue {
333            source_entry_dn: entry_dn.to_owned(),
334            source_attribute_name: attribute_name.to_owned(),
335            conversion_target_name: "ObjectIdentifier".to_string(),
336            unexpected_value: value,
337        })
338    }
339}
340
341/// a type that can be parsed from an Ldap type (on the level where
342/// optional/required and single/multi-value matter as opposed to the primitives
343/// above)
344pub trait FromLdapType {
345    /// the type of error when the conversion fails
346    type Error;
347
348    /// parse this type from the LDAP representation returned
349    /// by a search query
350    ///
351    /// # Errors
352    ///
353    /// fails if the type could not be parsed or if the number or type
354    /// (string/binary) does not match what is expected
355    fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
356    where
357        Self: Sized;
358}
359
360/// represents the errors that can occur when decoding a Vec of types with a
361/// FromStringLdapType implementation
362#[derive(Debug, Clone)]
363pub enum VecOfFromStringLdapTypeError<E> {
364    /// since types implementing FromStringLdapType can not handle binary values
365    /// this represents the error when the input contains binary values
366    LdapShouldNotReturnBinaryResult {
367        /// the DN of the entry
368        entry_dn: String,
369        /// the attribute name
370        attribute_name: String,
371    },
372    /// represents an error converting one of the primitive values
373    PrimitiveValueConversionError(E),
374}
375
376impl<E> std::fmt::Display for VecOfFromStringLdapTypeError<E>
377where
378    E: std::error::Error,
379{
380    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
381        match self {
382            Self::LdapShouldNotReturnBinaryResult {
383                entry_dn,
384                attribute_name,
385            } => {
386                write!(f, "encountered binary values in input for {entry_dn} attribute {attribute_name} when converting a Vec of a type that only supports String inputs")
387            }
388            Self::PrimitiveValueConversionError(err) => {
389                write!(
390                    f,
391                    "encountered error converting a primitive value from String: {err}",
392                )
393            }
394        }
395    }
396}
397
398impl<E> std::error::Error for VecOfFromStringLdapTypeError<E> where E: std::error::Error {}
399
400impl<T> FromLdapType for Vec<T>
401where
402    T: FromStringLdapType,
403{
404    type Error = VecOfFromStringLdapTypeError<<T as FromStringLdapType>::Error>;
405
406    fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
407    where
408        Self: Sized,
409    {
410        if !values.binary_values.is_empty() {
411            return Err(
412                VecOfFromStringLdapTypeError::LdapShouldNotReturnBinaryResult {
413                    entry_dn: values.entry_dn,
414                    attribute_name: values.attribute_name,
415                },
416            );
417        }
418        values
419            .string_values
420            .into_iter()
421            .map(|v| <T as FromStringLdapType>::parse(&values.entry_dn, &values.attribute_name, v))
422            .collect::<Result<Self, <T as FromStringLdapType>::Error>>()
423            .map_err(VecOfFromStringLdapTypeError::PrimitiveValueConversionError)
424    }
425}
426
427/// represents the errors that can occur when decoding an Option of types with a
428/// FromStringLdapType implementation
429#[derive(Debug, Clone)]
430pub enum OptionOfFromStringLdapTypeError<E> {
431    /// since types implementing FromStringLdapType can not handle binary values
432    /// this represents the error when the input contains binary values
433    LdapShouldNotReturnBinaryResult {
434        /// the DN of the entry
435        entry_dn: String,
436        /// the name of the attribute
437        attribute_name: String,
438    },
439    /// since Option types can only hold 0 or 1 results there should not be more
440    /// than one String input value
441    LdapShouldNotReturnMultipleResults {
442        /// the DN of the entry
443        entry_dn: String,
444        /// the name of the attribute
445        attribute_name: String,
446    },
447    /// represents an error converting one of the primitive values
448    PrimitiveValueConversionError(E),
449}
450
451impl<E> std::fmt::Display for OptionOfFromStringLdapTypeError<E>
452where
453    E: std::error::Error,
454{
455    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
456        match self {
457            Self::LdapShouldNotReturnBinaryResult {
458                entry_dn,
459                attribute_name,
460            } => {
461                write!(f, "encountered binary values in input for {entry_dn} attribute {attribute_name} when converting an Option of a type that only supports String inputs")
462            }
463            Self::LdapShouldNotReturnMultipleResults {
464                entry_dn,
465                attribute_name,
466            } => {
467                write!(f, "encountered multiple string values in input for {entry_dn} attribute {attribute_name} when converting an Option of a type that only supports String inputs")
468            }
469            Self::PrimitiveValueConversionError(err) => {
470                write!(
471                    f,
472                    "encountered error converting a primitive value from String: {err}",
473                )
474            }
475        }
476    }
477}
478
479impl<E> std::error::Error for OptionOfFromStringLdapTypeError<E> where E: std::error::Error {}
480
481impl<T> FromLdapType for Option<T>
482where
483    T: FromStringLdapType,
484{
485    type Error = OptionOfFromStringLdapTypeError<<T as FromStringLdapType>::Error>;
486
487    fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
488    where
489        Self: Sized,
490    {
491        if !values.binary_values.is_empty() {
492            return Err(
493                OptionOfFromStringLdapTypeError::LdapShouldNotReturnBinaryResult {
494                    entry_dn: values.entry_dn,
495                    attribute_name: values.attribute_name,
496                },
497            );
498        }
499        if values.string_values.len() > 1 {
500            return Err(
501                OptionOfFromStringLdapTypeError::LdapShouldNotReturnMultipleResults {
502                    entry_dn: values.entry_dn,
503                    attribute_name: values.attribute_name,
504                },
505            );
506        }
507        if let Some(value) = values.string_values.first() {
508            Ok(Some(
509                <T as FromStringLdapType>::parse(
510                    &values.entry_dn,
511                    &values.attribute_name,
512                    value.to_owned(),
513                )
514                .map_err(OptionOfFromStringLdapTypeError::PrimitiveValueConversionError)?,
515            ))
516        } else {
517            Ok(None)
518        }
519    }
520}
521
522/// represents the errors that can occur when decoding a required value of
523/// types with a FromStringLdapType implementation
524#[derive(Debug, Clone)]
525pub enum RequiredFromStringLdapTypeError<E> {
526    /// since types implementing FromStringLdapType can not handle binary values
527    /// this represents the error when the input contains binary values
528    LdapShouldNotReturnBinaryResult {
529        /// the DN of the entry
530        entry_dn: String,
531        /// the name of the attribute
532        attribute_name: String,
533    },
534    /// since primitive types can only hold exactly one result there should
535    /// be exactly one String input value
536    LdapShouldReturnExactlyOneResult {
537        /// the DN of the entry
538        entry_dn: String,
539        /// the name of the attribute
540        attribute_name: String,
541        /// number of results
542        count: usize,
543    },
544    /// represents an error converting one of the primitive values
545    PrimitiveValueConversionError(E),
546}
547
548impl<E> std::fmt::Display for RequiredFromStringLdapTypeError<E>
549where
550    E: std::error::Error,
551{
552    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
553        match self {
554            Self::LdapShouldNotReturnBinaryResult {
555                entry_dn,
556                attribute_name,
557            } => {
558                write!(f, "encountered binary values in input for {entry_dn} attribute {attribute_name} when converting a required value of a type that only supports String inputs")
559            }
560            Self::LdapShouldReturnExactlyOneResult {
561                entry_dn,
562                attribute_name,
563                count,
564            } => {
565                write!(f, "encountered {count} string values (expected exactly one) in input for {entry_dn} attribute {attribute_name} when converting a required value of a type that only supports String inputs")
566            }
567            Self::PrimitiveValueConversionError(err) => {
568                write!(
569                    f,
570                    "encountered error converting a primitive value from String: {err}",
571                )
572            }
573        }
574    }
575}
576
577impl<E> std::error::Error for RequiredFromStringLdapTypeError<E> where E: std::error::Error {}
578
579impl<T> FromLdapType for T
580where
581    T: FromStringLdapType,
582{
583    type Error = RequiredFromStringLdapTypeError<<T as FromStringLdapType>::Error>;
584
585    fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
586    where
587        Self: Sized,
588    {
589        if !values.binary_values.is_empty() {
590            return Err(
591                RequiredFromStringLdapTypeError::LdapShouldNotReturnBinaryResult {
592                    entry_dn: values.entry_dn,
593                    attribute_name: values.attribute_name,
594                },
595            );
596        }
597        if values.string_values.len() != 1 {
598            return Err(
599                RequiredFromStringLdapTypeError::LdapShouldReturnExactlyOneResult {
600                    entry_dn: values.entry_dn,
601                    attribute_name: values.attribute_name,
602                    count: values.string_values.len(),
603                },
604            );
605        }
606        if let Some(value) = values.string_values.first() {
607            Ok(<T as FromStringLdapType>::parse(
608                &values.entry_dn,
609                &values.attribute_name,
610                value.to_owned(),
611            )
612            .map_err(RequiredFromStringLdapTypeError::PrimitiveValueConversionError)?)
613        } else {
614            Err(
615                RequiredFromStringLdapTypeError::LdapShouldReturnExactlyOneResult {
616                    entry_dn: values.entry_dn,
617                    attribute_name: values.attribute_name,
618                    count: values.string_values.len(),
619                },
620            )
621        }
622    }
623}
624
625/// a primitive result that can be converted from an Ldap type that is returned
626/// as a `Vec<u8>`
627pub trait FromBinaryLdapType {
628    /// the type of error when the conversion fails
629    type Error;
630
631    /// parse this type from a `Vec<u8>` returned by an LDAP search
632    ///
633    /// # Errors
634    ///
635    /// fails if the type could not be parsed
636    fn parse(entry_dn: &str, attribute_name: &str, value: Vec<u8>) -> Result<Self, Self::Error>
637    where
638        Self: Sized;
639}
640
641/// error that occurs when a conversion encounters a value that it can not
642/// convert
643#[derive(Debug, Clone, PartialEq, Eq)]
644pub struct UnexpectedBinaryValue {
645    /// source entry DN
646    source_entry_dn: String,
647    /// source attribute name
648    source_attribute_name: String,
649    /// name of the type we couldn't convert the value to
650    conversion_target_name: String,
651    /// value that was encountered and could not be converted
652    unexpected_value: Vec<u8>,
653}
654
655impl std::fmt::Display for UnexpectedBinaryValue {
656    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
657        write!(
658            f,
659            "Unexpected value in conversion of {} attribute {} to {}: {:?}",
660            self.source_entry_dn,
661            self.source_attribute_name,
662            self.conversion_target_name,
663            self.unexpected_value,
664        )
665    }
666}
667
668impl std::error::Error for UnexpectedBinaryValue {}
669
670impl FromBinaryLdapType for Vec<u8> {
671    type Error = std::convert::Infallible;
672
673    fn parse(_entry_dn: &str, _attribute_name: &str, value: Vec<u8>) -> Result<Self, Self::Error>
674    where
675        Self: Sized,
676    {
677        Ok(value)
678    }
679}
680
681/// a wrapper newtype to identify types we want to deserialize from Binary LDAP attributes
682/// this avoids conflicts with e.g. `Vec<u8>` deserialized from a multi-valued number attribute
683/// and `Vec<u8>` serialized from a single-valued binary attribute
684#[derive(Debug, Clone)]
685pub struct Binary<T>(pub T);
686
687/// represents the errors that can occur when decoding a Vec of types with a
688/// FromBinaryLdapType implementation
689#[derive(Debug, Clone)]
690pub enum VecOfFromBinaryLdapTypeError<E> {
691    /// since types implementing FromStringLdapType can not handle String values
692    /// this represents the error when the input contains String values
693    LdapShouldNotReturnStringResult {
694        /// the DN of the entry
695        entry_dn: String,
696        /// the attribute name
697        attribute_name: String,
698    },
699    /// represents an error converting one of the primitive values
700    PrimitiveValueConversionError(E),
701}
702
703impl<E> std::fmt::Display for VecOfFromBinaryLdapTypeError<E>
704where
705    E: std::error::Error,
706{
707    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
708        match self {
709            Self::LdapShouldNotReturnStringResult {
710                entry_dn,
711                attribute_name,
712            } => {
713                write!(f, "encountered String values in input for {entry_dn} attribute {attribute_name} when converting a Vec of a type that only supports binary inputs")
714            }
715            Self::PrimitiveValueConversionError(err) => {
716                write!(
717                    f,
718                    "encountered error converting a primitive value from binary: {err}",
719                )
720            }
721        }
722    }
723}
724
725impl<E> std::error::Error for VecOfFromBinaryLdapTypeError<E> where E: std::error::Error {}
726
727impl<T> FromLdapType for Binary<Vec<T>>
728where
729    T: FromBinaryLdapType,
730{
731    type Error = VecOfFromBinaryLdapTypeError<<T as FromBinaryLdapType>::Error>;
732
733    fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
734    where
735        Self: Sized,
736    {
737        if !values.string_values.is_empty() {
738            return Err(
739                VecOfFromBinaryLdapTypeError::LdapShouldNotReturnStringResult {
740                    entry_dn: values.entry_dn,
741                    attribute_name: values.attribute_name,
742                },
743            );
744        }
745        values
746            .binary_values
747            .into_iter()
748            .map(|v| <T as FromBinaryLdapType>::parse(&values.entry_dn, &values.attribute_name, v))
749            .collect::<Result<Vec<T>, <T as FromBinaryLdapType>::Error>>()
750            .map(Binary)
751            .map_err(VecOfFromBinaryLdapTypeError::PrimitiveValueConversionError)
752    }
753}
754
755/// represents the errors that can occur when decoding an Option of types with a
756/// FromBinaryLdapType implementation
757#[derive(Debug, Clone)]
758pub enum OptionOfFromBinaryLdapTypeError<E> {
759    /// since types implementing FromBinaryLdapType can not handle String values
760    /// this represents the error when the input contains String values
761    LdapShouldNotReturnStringResult {
762        /// the DN of the entry
763        entry_dn: String,
764        /// the name of the attribute
765        attribute_name: String,
766    },
767    /// since Option types can only hold 0 or 1 results there should not be more
768    /// than one String input value
769    LdapShouldNotReturnMultipleResults {
770        /// the DN of the entry
771        entry_dn: String,
772        /// the name of the attribute
773        attribute_name: String,
774    },
775    /// represents an error converting one of the primitive values
776    PrimitiveValueConversionError(E),
777}
778
779impl<E> std::fmt::Display for OptionOfFromBinaryLdapTypeError<E>
780where
781    E: std::error::Error,
782{
783    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
784        match self {
785            Self::LdapShouldNotReturnStringResult {
786                entry_dn,
787                attribute_name,
788            } => {
789                write!(f, "encountered String values in input for {entry_dn} attribute {attribute_name} when converting an Option of a type that only supports binary inputs")
790            }
791            Self::LdapShouldNotReturnMultipleResults {
792                entry_dn,
793                attribute_name,
794            } => {
795                write!(f, "encountered multiple binary values in input for {entry_dn} attribute {attribute_name} when converting an Option of a type that only supports binary inputs")
796            }
797            Self::PrimitiveValueConversionError(err) => {
798                write!(
799                    f,
800                    "encountered error converting a primitive value from binary: {err}",
801                )
802            }
803        }
804    }
805}
806
807impl<E> std::error::Error for OptionOfFromBinaryLdapTypeError<E> where E: std::error::Error {}
808
809impl<T> FromLdapType for Binary<Option<T>>
810where
811    T: FromBinaryLdapType,
812{
813    type Error = OptionOfFromBinaryLdapTypeError<<T as FromBinaryLdapType>::Error>;
814
815    fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
816    where
817        Self: Sized,
818    {
819        if !values.string_values.is_empty() {
820            return Err(
821                OptionOfFromBinaryLdapTypeError::LdapShouldNotReturnStringResult {
822                    entry_dn: values.entry_dn,
823                    attribute_name: values.attribute_name,
824                },
825            );
826        }
827        if values.binary_values.len() > 1 {
828            return Err(
829                OptionOfFromBinaryLdapTypeError::LdapShouldNotReturnMultipleResults {
830                    entry_dn: values.entry_dn,
831                    attribute_name: values.attribute_name,
832                },
833            );
834        }
835        if let Some(value) = values.binary_values.first() {
836            Ok(Self(Some(
837                <T as FromBinaryLdapType>::parse(
838                    &values.entry_dn,
839                    &values.attribute_name,
840                    value.to_owned(),
841                )
842                .map_err(OptionOfFromBinaryLdapTypeError::PrimitiveValueConversionError)?,
843            )))
844        } else {
845            Ok(Self(None))
846        }
847    }
848}
849
850/// represents the errors that can occur when decoding a required value of
851/// types with a FromBinaryLdapType implementation
852#[derive(Debug, Clone)]
853pub enum RequiredFromBinaryLdapTypeError<E> {
854    /// since types implementing FromBinaryLdapType can not handle String values
855    /// this represents the error when the input contains String values
856    LdapShouldNotReturnStringResult {
857        /// the DN of the entry
858        entry_dn: String,
859        /// the name of the attribute
860        attribute_name: String,
861    },
862    /// since primitive types can only hold exactly one result there should
863    /// be exactly one binaryg input value
864    LdapShouldReturnExactlyOneResult {
865        /// the DN of the entry
866        entry_dn: String,
867        /// the name of the attribute
868        attribute_name: String,
869        /// number of results
870        count: usize,
871    },
872    /// represents an error converting one of the primitive values
873    PrimitiveValueConversionError(E),
874}
875
876impl<E> std::fmt::Display for RequiredFromBinaryLdapTypeError<E>
877where
878    E: std::error::Error,
879{
880    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
881        match self {
882            Self::LdapShouldNotReturnStringResult {
883                entry_dn,
884                attribute_name,
885            } => {
886                write!(f, "encountered String values in input for {entry_dn} attribute {attribute_name} when converting a required value of a type that only supports binary inputs")
887            }
888            Self::LdapShouldReturnExactlyOneResult {
889                entry_dn,
890                attribute_name,
891                count,
892            } => {
893                write!(f, "encountered {count} binary values (expected exactly one) in input for {entry_dn} attribute {attribute_name} when converting a required value of a type that only supports binary inputs")
894            }
895            Self::PrimitiveValueConversionError(err) => {
896                write!(
897                    f,
898                    "encountered error converting a primitive value from binary: {err}",
899                )
900            }
901        }
902    }
903}
904
905impl<E> std::error::Error for RequiredFromBinaryLdapTypeError<E> where E: std::error::Error {}
906
907impl<T> FromLdapType for Binary<T>
908where
909    T: FromBinaryLdapType,
910{
911    type Error = RequiredFromBinaryLdapTypeError<<T as FromBinaryLdapType>::Error>;
912
913    fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
914    where
915        Self: Sized,
916    {
917        if !values.string_values.is_empty() {
918            return Err(
919                RequiredFromBinaryLdapTypeError::LdapShouldNotReturnStringResult {
920                    entry_dn: values.entry_dn,
921                    attribute_name: values.attribute_name,
922                },
923            );
924        }
925        if values.binary_values.len() != 1 {
926            return Err(
927                RequiredFromBinaryLdapTypeError::LdapShouldReturnExactlyOneResult {
928                    entry_dn: values.entry_dn,
929                    attribute_name: values.attribute_name,
930                    count: values.string_values.len(),
931                },
932            );
933        }
934        if let Some(value) = values.binary_values.first() {
935            Ok(<T as FromBinaryLdapType>::parse(
936                &values.entry_dn,
937                &values.attribute_name,
938                value.to_owned(),
939            )
940            .map(Binary)
941            .map_err(RequiredFromBinaryLdapTypeError::PrimitiveValueConversionError)?)
942        } else {
943            Err(
944                RequiredFromBinaryLdapTypeError::LdapShouldReturnExactlyOneResult {
945                    entry_dn: values.entry_dn,
946                    attribute_name: values.attribute_name,
947                    count: values.string_values.len(),
948                },
949            )
950        }
951    }
952}