Skip to main content

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