1#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct LdapAttributeResultValues {
8 pub entry_dn: String,
10 pub attribute_name: String,
12 pub string_values: Vec<String>,
14 pub binary_values: Vec<Vec<u8>>,
16}
17
18#[cfg(feature = "ldap3")]
21pub trait SearchEntryExt {
22 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
40pub trait FromStringLdapType {
43 type Error;
45
46 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#[derive(Debug, Clone, PartialEq, Eq)]
70pub struct UnexpectedStringValue {
71 source_entry_dn: String,
73 source_attribute_name: String,
75 conversion_target_name: String,
77 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
341pub trait FromLdapType {
345 type Error;
347
348 fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
356 where
357 Self: Sized;
358}
359
360#[derive(Debug, Clone)]
363pub enum VecOfFromStringLdapTypeError<E> {
364 LdapShouldNotReturnBinaryResult {
367 entry_dn: String,
369 attribute_name: String,
371 },
372 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#[derive(Debug, Clone)]
430pub enum OptionOfFromStringLdapTypeError<E> {
431 LdapShouldNotReturnBinaryResult {
434 entry_dn: String,
436 attribute_name: String,
438 },
439 LdapShouldNotReturnMultipleResults {
442 entry_dn: String,
444 attribute_name: String,
446 },
447 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#[derive(Debug, Clone)]
525pub enum RequiredFromStringLdapTypeError<E> {
526 LdapShouldNotReturnBinaryResult {
529 entry_dn: String,
531 attribute_name: String,
533 },
534 LdapShouldReturnExactlyOneResult {
537 entry_dn: String,
539 attribute_name: String,
541 count: usize,
543 },
544 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
625pub trait FromBinaryLdapType {
628 type Error;
630
631 fn parse(entry_dn: &str, attribute_name: &str, value: Vec<u8>) -> Result<Self, Self::Error>
637 where
638 Self: Sized;
639}
640
641#[derive(Debug, Clone, PartialEq, Eq)]
644pub struct UnexpectedBinaryValue {
645 source_entry_dn: String,
647 source_attribute_name: String,
649 conversion_target_name: String,
651 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#[derive(Debug, Clone)]
685pub struct Binary<T>(pub T);
686
687#[derive(Debug, Clone)]
690pub enum VecOfFromBinaryLdapTypeError<E> {
691 LdapShouldNotReturnStringResult {
694 entry_dn: String,
696 attribute_name: String,
698 },
699 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#[derive(Debug, Clone)]
758pub enum OptionOfFromBinaryLdapTypeError<E> {
759 LdapShouldNotReturnStringResult {
762 entry_dn: String,
764 attribute_name: String,
766 },
767 LdapShouldNotReturnMultipleResults {
770 entry_dn: String,
772 attribute_name: String,
774 },
775 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#[derive(Debug, Clone)]
853pub enum RequiredFromBinaryLdapTypeError<E> {
854 LdapShouldNotReturnStringResult {
857 entry_dn: String,
859 attribute_name: String,
861 },
862 LdapShouldReturnExactlyOneResult {
865 entry_dn: String,
867 attribute_name: String,
869 count: usize,
871 },
872 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}