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(|_| 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(|_| 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(|_| 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(|_| 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(|_| 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(|_| 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(|_| 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(|_| 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(|_| 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(|_| 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(|_| 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(|_| 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(|_| 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(|_| 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            VecOfFromStringLdapTypeError::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            VecOfFromStringLdapTypeError::PrimitiveValueConversionError(err) => {
389                write!(
390                    f,
391                    "encountered error converting a primitive value from String: {}",
392                    err
393                )
394            }
395        }
396    }
397}
398
399impl<E> std::error::Error for VecOfFromStringLdapTypeError<E> where E: std::error::Error {}
400
401impl<T> FromLdapType for Vec<T>
402where
403    T: FromStringLdapType,
404{
405    type Error = VecOfFromStringLdapTypeError<<T as FromStringLdapType>::Error>;
406
407    fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
408    where
409        Self: Sized,
410    {
411        if !values.binary_values.is_empty() {
412            return Err(
413                VecOfFromStringLdapTypeError::LdapShouldNotReturnBinaryResult {
414                    entry_dn: values.entry_dn,
415                    attribute_name: values.attribute_name,
416                },
417            );
418        }
419        values
420            .string_values
421            .into_iter()
422            .map(|v| <T as FromStringLdapType>::parse(&values.entry_dn, &values.attribute_name, v))
423            .collect::<Result<Vec<T>, <T as FromStringLdapType>::Error>>()
424            .map_err(VecOfFromStringLdapTypeError::PrimitiveValueConversionError)
425    }
426}
427
428/// represents the errors that can occur when decoding an Option of types with a
429/// FromStringLdapType implementation
430#[derive(Debug, Clone)]
431pub enum OptionOfFromStringLdapTypeError<E> {
432    /// since types implementing FromStringLdapType can not handle binary values
433    /// this represents the error when the input contains binary values
434    LdapShouldNotReturnBinaryResult {
435        /// the DN of the entry
436        entry_dn: String,
437        /// the name of the attribute
438        attribute_name: String,
439    },
440    /// since Option types can only hold 0 or 1 results there should not be more
441    /// than one String input value
442    LdapShouldNotReturnMultipleResults {
443        /// the DN of the entry
444        entry_dn: String,
445        /// the name of the attribute
446        attribute_name: String,
447    },
448    /// represents an error converting one of the primitive values
449    PrimitiveValueConversionError(E),
450}
451
452impl<E> std::fmt::Display for OptionOfFromStringLdapTypeError<E>
453where
454    E: std::error::Error,
455{
456    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
457        match self {
458            OptionOfFromStringLdapTypeError::LdapShouldNotReturnBinaryResult {
459                entry_dn,
460                attribute_name,
461            } => {
462                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")
463            }
464            OptionOfFromStringLdapTypeError::LdapShouldNotReturnMultipleResults {
465                entry_dn,
466                attribute_name,
467            } => {
468                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")
469            }
470            OptionOfFromStringLdapTypeError::PrimitiveValueConversionError(err) => {
471                write!(
472                    f,
473                    "encountered error converting a primitive value from String: {}",
474                    err
475                )
476            }
477        }
478    }
479}
480
481impl<E> std::error::Error for OptionOfFromStringLdapTypeError<E> where E: std::error::Error {}
482
483impl<T> FromLdapType for Option<T>
484where
485    T: FromStringLdapType,
486{
487    type Error = OptionOfFromStringLdapTypeError<<T as FromStringLdapType>::Error>;
488
489    fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
490    where
491        Self: Sized,
492    {
493        if !values.binary_values.is_empty() {
494            return Err(
495                OptionOfFromStringLdapTypeError::LdapShouldNotReturnBinaryResult {
496                    entry_dn: values.entry_dn,
497                    attribute_name: values.attribute_name,
498                },
499            );
500        }
501        if values.string_values.len() > 1 {
502            return Err(
503                OptionOfFromStringLdapTypeError::LdapShouldNotReturnMultipleResults {
504                    entry_dn: values.entry_dn,
505                    attribute_name: values.attribute_name,
506                },
507            );
508        }
509        if let Some(value) = values.string_values.first() {
510            Ok(Some(
511                <T as FromStringLdapType>::parse(
512                    &values.entry_dn,
513                    &values.attribute_name,
514                    value.to_owned(),
515                )
516                .map_err(OptionOfFromStringLdapTypeError::PrimitiveValueConversionError)?,
517            ))
518        } else {
519            Ok(None)
520        }
521    }
522}
523
524/// represents the errors that can occur when decoding a required value of
525/// types with a FromStringLdapType implementation
526#[derive(Debug, Clone)]
527pub enum RequiredFromStringLdapTypeError<E> {
528    /// since types implementing FromStringLdapType can not handle binary values
529    /// this represents the error when the input contains binary values
530    LdapShouldNotReturnBinaryResult {
531        /// the DN of the entry
532        entry_dn: String,
533        /// the name of the attribute
534        attribute_name: String,
535    },
536    /// since primitive types can only hold exactly one result there should
537    /// be exactly one String input value
538    LdapShouldReturnExactlyOneResult {
539        /// the DN of the entry
540        entry_dn: String,
541        /// the name of the attribute
542        attribute_name: String,
543        /// number of results
544        count: usize,
545    },
546    /// represents an error converting one of the primitive values
547    PrimitiveValueConversionError(E),
548}
549
550impl<E> std::fmt::Display for RequiredFromStringLdapTypeError<E>
551where
552    E: std::error::Error,
553{
554    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
555        match self {
556            RequiredFromStringLdapTypeError::LdapShouldNotReturnBinaryResult {
557                entry_dn,
558                attribute_name,
559            } => {
560                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")
561            }
562            RequiredFromStringLdapTypeError::LdapShouldReturnExactlyOneResult {
563                entry_dn,
564                attribute_name,
565                count,
566            } => {
567                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")
568            }
569            RequiredFromStringLdapTypeError::PrimitiveValueConversionError(err) => {
570                write!(
571                    f,
572                    "encountered error converting a primitive value from String: {}",
573                    err
574                )
575            }
576        }
577    }
578}
579
580impl<E> std::error::Error for RequiredFromStringLdapTypeError<E> where E: std::error::Error {}
581
582impl<T> FromLdapType for T
583where
584    T: FromStringLdapType,
585{
586    type Error = RequiredFromStringLdapTypeError<<T as FromStringLdapType>::Error>;
587
588    fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
589    where
590        Self: Sized,
591    {
592        if !values.binary_values.is_empty() {
593            return Err(
594                RequiredFromStringLdapTypeError::LdapShouldNotReturnBinaryResult {
595                    entry_dn: values.entry_dn,
596                    attribute_name: values.attribute_name,
597                },
598            );
599        }
600        if values.string_values.len() != 1 {
601            return Err(
602                RequiredFromStringLdapTypeError::LdapShouldReturnExactlyOneResult {
603                    entry_dn: values.entry_dn,
604                    attribute_name: values.attribute_name,
605                    count: values.string_values.len(),
606                },
607            );
608        }
609        if let Some(value) = values.string_values.first() {
610            Ok(<T as FromStringLdapType>::parse(
611                &values.entry_dn,
612                &values.attribute_name,
613                value.to_owned(),
614            )
615            .map_err(RequiredFromStringLdapTypeError::PrimitiveValueConversionError)?)
616        } else {
617            Err(
618                RequiredFromStringLdapTypeError::LdapShouldReturnExactlyOneResult {
619                    entry_dn: values.entry_dn,
620                    attribute_name: values.attribute_name,
621                    count: values.string_values.len(),
622                },
623            )
624        }
625    }
626}
627
628/// a primitive result that can be converted from an Ldap type that is returned
629/// as a `Vec<u8>`
630pub trait FromBinaryLdapType {
631    /// the type of error when the conversion fails
632    type Error;
633
634    /// parse this type from a `Vec<u8>` returned by an LDAP search
635    ///
636    /// # Errors
637    ///
638    /// fails if the type could not be parsed
639    fn parse(entry_dn: &str, attribute_name: &str, value: Vec<u8>) -> Result<Self, Self::Error>
640    where
641        Self: Sized;
642}
643
644/// error that occurs when a conversion encounters a value that it can not
645/// convert
646#[derive(Debug, Clone, PartialEq, Eq)]
647pub struct UnexpectedBinaryValue {
648    /// source entry DN
649    source_entry_dn: String,
650    /// source attribute name
651    source_attribute_name: String,
652    /// name of the type we couldn't convert the value to
653    conversion_target_name: String,
654    /// value that was encountered and could not be converted
655    unexpected_value: Vec<u8>,
656}
657
658impl std::fmt::Display for UnexpectedBinaryValue {
659    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
660        write!(
661            f,
662            "Unexpected value in conversion of {} attribute {} to {}: {:?}",
663            self.source_entry_dn,
664            self.source_attribute_name,
665            self.conversion_target_name,
666            self.unexpected_value,
667        )
668    }
669}
670
671impl std::error::Error for UnexpectedBinaryValue {}
672
673impl FromBinaryLdapType for Vec<u8> {
674    type Error = std::convert::Infallible;
675
676    fn parse(_entry_dn: &str, _attribute_name: &str, value: Vec<u8>) -> Result<Self, Self::Error>
677    where
678        Self: Sized,
679    {
680        Ok(value)
681    }
682}
683
684/// a wrapper newtype to identify types we want to deserialize from Binary LDAP attributes
685/// this avoids conflicts with e.g. `Vec<u8>` deserialized from a multi-valued number attribute
686/// and `Vec<u8>` serialized from a single-valued binary attribute
687#[derive(Debug, Clone)]
688pub struct Binary<T>(pub T);
689
690/// represents the errors that can occur when decoding a Vec of types with a
691/// FromBinaryLdapType implementation
692#[derive(Debug, Clone)]
693pub enum VecOfFromBinaryLdapTypeError<E> {
694    /// since types implementing FromStringLdapType can not handle String values
695    /// this represents the error when the input contains String values
696    LdapShouldNotReturnStringResult {
697        /// the DN of the entry
698        entry_dn: String,
699        /// the attribute name
700        attribute_name: String,
701    },
702    /// represents an error converting one of the primitive values
703    PrimitiveValueConversionError(E),
704}
705
706impl<E> std::fmt::Display for VecOfFromBinaryLdapTypeError<E>
707where
708    E: std::error::Error,
709{
710    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
711        match self {
712            VecOfFromBinaryLdapTypeError::LdapShouldNotReturnStringResult {
713                entry_dn,
714                attribute_name,
715            } => {
716                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")
717            }
718            VecOfFromBinaryLdapTypeError::PrimitiveValueConversionError(err) => {
719                write!(
720                    f,
721                    "encountered error converting a primitive value from binary: {}",
722                    err
723                )
724            }
725        }
726    }
727}
728
729impl<E> std::error::Error for VecOfFromBinaryLdapTypeError<E> where E: std::error::Error {}
730
731impl<T> FromLdapType for Binary<Vec<T>>
732where
733    T: FromBinaryLdapType,
734{
735    type Error = VecOfFromBinaryLdapTypeError<<T as FromBinaryLdapType>::Error>;
736
737    fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
738    where
739        Self: Sized,
740    {
741        if !values.string_values.is_empty() {
742            return Err(
743                VecOfFromBinaryLdapTypeError::LdapShouldNotReturnStringResult {
744                    entry_dn: values.entry_dn,
745                    attribute_name: values.attribute_name,
746                },
747            );
748        }
749        values
750            .binary_values
751            .into_iter()
752            .map(|v| <T as FromBinaryLdapType>::parse(&values.entry_dn, &values.attribute_name, v))
753            .collect::<Result<Vec<T>, <T as FromBinaryLdapType>::Error>>()
754            .map(Binary)
755            .map_err(VecOfFromBinaryLdapTypeError::PrimitiveValueConversionError)
756    }
757}
758
759/// represents the errors that can occur when decoding an Option of types with a
760/// FromBinaryLdapType implementation
761#[derive(Debug, Clone)]
762pub enum OptionOfFromBinaryLdapTypeError<E> {
763    /// since types implementing FromBinaryLdapType can not handle String values
764    /// this represents the error when the input contains String values
765    LdapShouldNotReturnStringResult {
766        /// the DN of the entry
767        entry_dn: String,
768        /// the name of the attribute
769        attribute_name: String,
770    },
771    /// since Option types can only hold 0 or 1 results there should not be more
772    /// than one String input value
773    LdapShouldNotReturnMultipleResults {
774        /// the DN of the entry
775        entry_dn: String,
776        /// the name of the attribute
777        attribute_name: String,
778    },
779    /// represents an error converting one of the primitive values
780    PrimitiveValueConversionError(E),
781}
782
783impl<E> std::fmt::Display for OptionOfFromBinaryLdapTypeError<E>
784where
785    E: std::error::Error,
786{
787    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
788        match self {
789            OptionOfFromBinaryLdapTypeError::LdapShouldNotReturnStringResult {
790                entry_dn,
791                attribute_name,
792            } => {
793                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")
794            }
795            OptionOfFromBinaryLdapTypeError::LdapShouldNotReturnMultipleResults {
796                entry_dn,
797                attribute_name,
798            } => {
799                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")
800            }
801            OptionOfFromBinaryLdapTypeError::PrimitiveValueConversionError(err) => {
802                write!(
803                    f,
804                    "encountered error converting a primitive value from binary: {}",
805                    err
806                )
807            }
808        }
809    }
810}
811
812impl<E> std::error::Error for OptionOfFromBinaryLdapTypeError<E> where E: std::error::Error {}
813
814impl<T> FromLdapType for Binary<Option<T>>
815where
816    T: FromBinaryLdapType,
817{
818    type Error = OptionOfFromBinaryLdapTypeError<<T as FromBinaryLdapType>::Error>;
819
820    fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
821    where
822        Self: Sized,
823    {
824        if !values.string_values.is_empty() {
825            return Err(
826                OptionOfFromBinaryLdapTypeError::LdapShouldNotReturnStringResult {
827                    entry_dn: values.entry_dn,
828                    attribute_name: values.attribute_name,
829                },
830            );
831        }
832        if values.binary_values.len() > 1 {
833            return Err(
834                OptionOfFromBinaryLdapTypeError::LdapShouldNotReturnMultipleResults {
835                    entry_dn: values.entry_dn,
836                    attribute_name: values.attribute_name,
837                },
838            );
839        }
840        if let Some(value) = values.binary_values.first() {
841            Ok(Binary(Some(
842                <T as FromBinaryLdapType>::parse(
843                    &values.entry_dn,
844                    &values.attribute_name,
845                    value.to_owned(),
846                )
847                .map_err(OptionOfFromBinaryLdapTypeError::PrimitiveValueConversionError)?,
848            )))
849        } else {
850            Ok(Binary(None))
851        }
852    }
853}
854
855/// represents the errors that can occur when decoding a required value of
856/// types with a FromBinaryLdapType implementation
857#[derive(Debug, Clone)]
858pub enum RequiredFromBinaryLdapTypeError<E> {
859    /// since types implementing FromBinaryLdapType can not handle String values
860    /// this represents the error when the input contains String values
861    LdapShouldNotReturnStringResult {
862        /// the DN of the entry
863        entry_dn: String,
864        /// the name of the attribute
865        attribute_name: String,
866    },
867    /// since primitive types can only hold exactly one result there should
868    /// be exactly one binaryg input value
869    LdapShouldReturnExactlyOneResult {
870        /// the DN of the entry
871        entry_dn: String,
872        /// the name of the attribute
873        attribute_name: String,
874        /// number of results
875        count: usize,
876    },
877    /// represents an error converting one of the primitive values
878    PrimitiveValueConversionError(E),
879}
880
881impl<E> std::fmt::Display for RequiredFromBinaryLdapTypeError<E>
882where
883    E: std::error::Error,
884{
885    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
886        match self {
887            RequiredFromBinaryLdapTypeError::LdapShouldNotReturnStringResult {
888                entry_dn,
889                attribute_name,
890            } => {
891                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")
892            }
893            RequiredFromBinaryLdapTypeError::LdapShouldReturnExactlyOneResult {
894                entry_dn,
895                attribute_name,
896                count,
897            } => {
898                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")
899            }
900            RequiredFromBinaryLdapTypeError::PrimitiveValueConversionError(err) => {
901                write!(
902                    f,
903                    "encountered error converting a primitive value from binary: {}",
904                    err
905                )
906            }
907        }
908    }
909}
910
911impl<E> std::error::Error for RequiredFromBinaryLdapTypeError<E> where E: std::error::Error {}
912
913impl<T> FromLdapType for Binary<T>
914where
915    T: FromBinaryLdapType,
916{
917    type Error = RequiredFromBinaryLdapTypeError<<T as FromBinaryLdapType>::Error>;
918
919    fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
920    where
921        Self: Sized,
922    {
923        if !values.string_values.is_empty() {
924            return Err(
925                RequiredFromBinaryLdapTypeError::LdapShouldNotReturnStringResult {
926                    entry_dn: values.entry_dn,
927                    attribute_name: values.attribute_name,
928                },
929            );
930        }
931        if values.binary_values.len() != 1 {
932            return Err(
933                RequiredFromBinaryLdapTypeError::LdapShouldReturnExactlyOneResult {
934                    entry_dn: values.entry_dn,
935                    attribute_name: values.attribute_name,
936                    count: values.string_values.len(),
937                },
938            );
939        }
940        if let Some(value) = values.binary_values.first() {
941            Ok(<T as FromBinaryLdapType>::parse(
942                &values.entry_dn,
943                &values.attribute_name,
944                value.to_owned(),
945            )
946            .map(Binary)
947            .map_err(RequiredFromBinaryLdapTypeError::PrimitiveValueConversionError)?)
948        } else {
949            Err(
950                RequiredFromBinaryLdapTypeError::LdapShouldReturnExactlyOneResult {
951                    entry_dn: values.entry_dn,
952                    attribute_name: values.attribute_name,
953                    count: values.string_values.len(),
954                },
955            )
956        }
957    }
958}