1use std::{
6 self,
7 borrow::Borrow,
8 convert::TryFrom,
9 ffi,
10 ops::Deref,
11 os::raw::c_char,
12 str::{FromStr, Utf8Error},
13};
14
15use crate::intercom::{ComError, ComResult};
16use crate::raw::BSTR;
17use crate::type_system::{
18 AutomationTypeSystem, ExternInput, ExternOutput, ExternType, RawTypeSystem,
19};
20
21#[derive(Debug)]
22pub struct FormatError;
23
24#[derive(PartialEq, Eq)]
26pub struct BStr(
27 [u8],
31);
32
33impl std::fmt::Debug for BStr
34{
35 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result
36 {
37 write!(
38 f,
39 "BStr(\"{}\")",
40 String::from_utf16_lossy(unsafe {
41 std::slice::from_raw_parts(self.as_ptr() as *const u16, self.len() as usize / 2)
42 })
43 )
44 }
45}
46
47impl BStr
48{
49 pub unsafe fn from_ptr<'a>(ptr: *const u16) -> &'a BStr
64 {
65 #![allow(clippy::cast_ptr_alignment)]
68 let (len, final_ptr) = match ptr as usize {
69 0 => (0, 1 as *const u8),
70 _ => (*(ptr.offset(-2) as *const u32), ptr as *const u8),
71 };
72
73 let slice = std::slice::from_raw_parts(final_ptr, len as usize);
74 Self::from_slice_unchecked(slice)
75 }
76
77 unsafe fn from_slice_unchecked(slice: &[u8]) -> &BStr
83 {
84 &*(slice as *const [u8] as *const BStr)
85 }
86
87 pub fn as_ptr(&self) -> *const u16
89 {
90 #![allow(clippy::cast_ptr_alignment)]
93
94 let ptr = self.0.as_ptr();
96 if self.0.is_empty() && ptr as usize == 0x1 {
97 std::ptr::null()
98 } else {
99 ptr as *const u16
100 }
101 }
102
103 pub fn len_bytes(&self) -> u32
108 {
109 self.0.len() as u32
113 }
114
115 pub fn len(&self) -> u32
117 {
118 unsafe { os::SysStringLen(self.as_ptr()) }
120 }
121
122 pub fn is_empty(&self) -> bool
123 {
124 self.len_bytes() == 0
125 }
126
127 pub fn as_slice(&self) -> &[u8]
129 {
130 &self.0
131 }
132
133 pub fn to_string(&self) -> Result<String, FormatError>
134 {
135 match self.len_bytes() {
136 x if x % 2 == 0 => String::from_utf16(unsafe {
137 std::slice::from_raw_parts(self.as_ptr() as *const u16, x as usize / 2)
138 })
139 .map_err(|_| FormatError),
140 _ => Err(FormatError),
141 }
142 }
143}
144
145pub struct BString(
168 *mut u16,
170);
171
172impl std::fmt::Debug for BString
173{
174 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result
175 {
176 write!(
177 f,
178 "BStr(\"{}\")",
179 String::from_utf16_lossy(unsafe {
180 std::slice::from_raw_parts(
181 self.as_ptr() as *const u16,
182 self.len_bytes() as usize / 2,
183 )
184 })
185 )
186 }
187}
188
189impl PartialEq for BString
190{
191 fn eq(&self, other: &Self) -> bool
192 {
193 **self == **other
195 }
196}
197
198impl Clone for BString
199{
200 fn clone(&self) -> BString
201 {
202 self.as_ref().to_owned()
203 }
204}
205
206impl BString
207{
208 pub unsafe fn from_ptr(ptr: *mut u16) -> BString
217 {
218 BString(ptr)
219 }
220
221 pub fn from_cstr(s: &ffi::CStr) -> Result<BString, Utf8Error>
223 {
224 Ok(Self::from_str(s.to_str()?).expect("Error type is never type"))
225 }
226
227 pub fn as_mut_ptr(&mut self) -> *mut u16
229 {
230 self.0 as *mut u16
231 }
232
233 pub fn into_ptr(self) -> *mut u16
235 {
236 let ptr = self.0;
237 std::mem::forget(self);
238 ptr as *mut u16
239 }
240}
241
242impl FromStr for BString
243{
244 type Err = std::string::ParseError;
245
246 fn from_str(s: &str) -> Result<BString, Self::Err>
248 {
249 if s.is_empty() {
253 return Ok(BString(std::ptr::null_mut()));
254 }
255
256 unsafe {
257 let chars = s.encode_utf16().collect::<Vec<_>>();
258 let bstr = os::SysAllocStringLen(chars.as_ptr(), chars.len() as u32);
259
260 if bstr.0.is_null() {
263 panic!("Allocating BStr failed.");
264 }
265
266 Ok(BString::from_ptr(bstr.0))
267 }
268 }
269}
270
271impl Deref for BString
272{
273 type Target = BStr;
274 fn deref(&self) -> &BStr
275 {
276 unsafe { BStr::from_ptr(self.0) }
277 }
278}
279
280impl AsRef<BStr> for BStr
283{
284 fn as_ref(&self) -> &BStr
285 {
286 self
287 }
288}
289
290impl AsRef<BStr> for BString
291{
292 fn as_ref(&self) -> &BStr
293 {
294 self
295 }
296}
297
298impl Borrow<BStr> for BString
299{
300 fn borrow(&self) -> &BStr
301 {
302 self
303 }
304}
305
306impl ToOwned for BStr
307{
308 type Owned = BString;
309
310 fn to_owned(&self) -> Self::Owned
311 {
312 unsafe {
313 BString::from_ptr(
314 os::SysAllocStringLen(self.as_ptr(), os::SysStringLen(self.as_ptr())).0,
315 )
316 }
317 }
318}
319
320impl<'a> From<&'a str> for BString
321{
322 fn from(source: &str) -> BString
323 {
324 BString::from_str(source).expect("Error type is never type")
325 }
326}
327
328impl From<String> for BString
329{
330 fn from(source: String) -> BString
331 {
332 BString::from_str(&source).expect("Error type is never type")
333 }
334}
335
336impl Default for BString
337{
338 fn default() -> BString
339 {
340 BString(std::ptr::null_mut())
341 }
342}
343
344impl Drop for BString
345{
346 fn drop(&mut self)
347 {
348 unsafe {
349 os::SysFreeString(self.as_mut_ptr());
350 self.0 = std::ptr::null_mut();
351 }
352 }
353}
354
355pub type CStr = std::ffi::CStr;
356pub type CString = std::ffi::CString;
357
358#[cfg(windows)]
362mod os
363{
364 use crate::raw::BSTR;
365
366 #[link(name = "oleaut32")]
367 extern "system" {
368 #[doc(hidden)]
369 pub fn SysAllocStringLen(psz: *const u16, len: u32) -> BSTR;
370
371 #[doc(hidden)]
372 pub fn SysFreeString(bstr: *mut u16);
373
374 #[doc(hidden)]
375 pub fn SysStringLen(pbstr: *const u16) -> u32;
376 }
377}
378
379#[cfg(not(windows))]
380#[allow(non_snake_case)]
381mod os
382{
383 use crate::raw::BSTR;
384
385 #[doc(hidden)]
386 pub unsafe fn SysAllocStringLen(psz: *const u16, len: u32) -> BSTR
387 {
388 if psz.is_null() {
391 return BSTR(std::ptr::null_mut());
392 }
393
394 let data_length = (len * 2) as usize;
397 let buffer_length: usize = 4 + data_length + 2;
398 let buffer = libc::malloc(buffer_length);
399 if buffer.is_null() {
400 return BSTR(std::ptr::null_mut());
401 }
402
403 let length_u32 = data_length as u32;
405 let length_prefix = &length_u32 as *const _ as *const libc::c_void;
406 libc::memcpy(buffer, length_prefix, 4);
407
408 let src_buffer = psz as *const u8 as *mut libc::c_void;
410 libc::memcpy(buffer.offset(4), src_buffer, data_length as usize);
411
412 let null_terminator: u16 = 0;
413 let null_terminator = &null_terminator as *const _ as *const libc::c_void;
414 libc::memcpy(buffer.offset(4 + data_length as isize), null_terminator, 2);
415
416 let buffer = buffer.offset(4) as *mut u16;
417 BSTR(buffer)
418 }
419
420 #[doc(hidden)]
421 pub unsafe fn SysFreeString(pbstr: *mut u16)
422 {
423 if !pbstr.is_null() {
424 let ptr = pbstr.offset(-2) as *mut libc::c_void;
425 libc::free(ptr);
426 }
427 }
428
429 #[doc(hidden)]
430 pub unsafe fn SysStringLen(pbstr: *const u16) -> u32
431 {
432 #![allow(clippy::cast_ptr_alignment)]
434 if pbstr.is_null() {
435 0
436 } else {
437 *(pbstr.offset(-2) as *const u32) / 2
438 }
439 }
440}
441
442#[derive(Debug, Clone)]
443pub enum IntercomString
444{
445 BString(BString),
446 CString(CString),
447 String(String),
448}
449
450impl From<BString> for IntercomString
451{
452 fn from(source: BString) -> Self
453 {
454 IntercomString::BString(source)
455 }
456}
457
458impl From<String> for IntercomString
459{
460 fn from(source: String) -> Self
461 {
462 IntercomString::String(source)
463 }
464}
465
466impl From<CString> for IntercomString
467{
468 fn from(source: CString) -> Self
469 {
470 IntercomString::CString(source)
471 }
472}
473
474impl TryFrom<IntercomString> for BString
475{
476 type Error = ComError;
477 fn try_from(source: IntercomString) -> Result<BString, ComError>
478 {
479 match source {
480 IntercomString::BString(bstring) => Ok(bstring),
481 IntercomString::CString(cstring) => {
482 BString::from_str(&cstring.into_string().map_err(|_| ComError::E_INVALIDARG)?)
483 .map_err(|_| ComError::E_INVALIDARG)
484 }
485 IntercomString::String(string) => {
486 BString::from_str(&string).map_err(|_| ComError::E_INVALIDARG)
487 }
488 }
489 }
490}
491
492impl TryFrom<IntercomString> for CString
493{
494 type Error = ComError;
495 fn try_from(source: IntercomString) -> Result<CString, ComError>
496 {
497 match source {
498 IntercomString::BString(bstring) => bstring
499 .to_string()
500 .map_err(|_| ComError::E_INVALIDARG)
501 .and_then(|string| CString::new(string).map_err(|_| ComError::E_INVALIDARG)),
502 IntercomString::CString(cstring) => Ok(cstring),
503 IntercomString::String(string) => {
504 CString::new(string).map_err(|_| ComError::E_INVALIDARG)
505 }
506 }
507 }
508}
509
510impl TryFrom<IntercomString> for String
511{
512 type Error = ComError;
513 fn try_from(source: IntercomString) -> Result<String, ComError>
514 {
515 match source {
516 IntercomString::BString(bstring) => {
517 bstring.to_string().map_err(|_| ComError::E_INVALIDARG)
518 }
519 IntercomString::CString(cstring) => {
520 cstring.into_string().map_err(|_| ComError::E_INVALIDARG)
521 }
522 IntercomString::String(string) => Ok(string),
523 }
524 }
525}
526
527impl ExternType<AutomationTypeSystem> for String
529{
530 type ForeignType = BSTR;
531}
532
533unsafe impl ExternInput<AutomationTypeSystem> for String
534{
535 type Lease = BString;
536 unsafe fn into_foreign_parameter(self) -> ComResult<(Self::ForeignType, Self::Lease)>
537 {
538 log::trace!("String::into_foreign_parameter<Automation>");
539 let bstring = BString::from_str(&self).expect("Error type is never type");
540 Ok((BSTR(bstring.as_ptr() as *mut _), bstring))
541 }
542
543 type Owned = Self;
544 unsafe fn from_foreign_parameter(source: Self::ForeignType) -> ComResult<Self::Owned>
545 {
546 log::trace!("String::from_foreign_parameter<Automation>");
547 let bstring = BStr::from_ptr(source.0);
548 bstring.to_string().map_err(|_| ComError::E_INVALIDARG)
549 }
550}
551
552impl ExternType<RawTypeSystem> for String
553{
554 type ForeignType = *mut c_char;
555}
556
557unsafe impl ExternInput<RawTypeSystem> for String
558{
559 type Lease = CString;
560 unsafe fn into_foreign_parameter(self) -> ComResult<(Self::ForeignType, Self::Lease)>
561 {
562 log::trace!("String::into_foreign_parameter<Raw>");
563 let cstring = CString::new(self).map_err(|_| ComError::E_INVALIDARG)?;
564 Ok((cstring.as_ptr() as *mut _, cstring))
565 }
566
567 type Owned = Self;
568 unsafe fn from_foreign_parameter(source: Self::ForeignType) -> ComResult<Self::Owned>
569 {
570 log::trace!("String::from_foreign_parameter<Raw>");
571 let cstring = CStr::from_ptr(source);
572 cstring
573 .to_str()
574 .map_err(|_| ComError::E_INVALIDARG)
575 .map(|s| s.to_string())
576 }
577}
578
579unsafe impl ExternOutput<AutomationTypeSystem> for String
580{
581 fn into_foreign_output(self) -> ComResult<Self::ForeignType>
582 {
583 log::trace!("String::from_foreign_output<Automation>");
584 let bstring = BString::from_str(&self).expect("Error type is never type");
585 Ok(BSTR(bstring.into_ptr()))
586 }
587
588 unsafe fn from_foreign_output(source: Self::ForeignType) -> ComResult<Self>
589 {
590 log::trace!("String::from_foreign_output<Automation>");
591 let bstring = BString::from_ptr(source.0);
592 bstring.to_string().map_err(|_| ComError::E_INVALIDARG)
593 }
594}
595
596unsafe impl ExternOutput<RawTypeSystem> for String
597{
598 fn into_foreign_output(self) -> ComResult<Self::ForeignType>
599 {
600 log::trace!("String::into_foreign_output<Raw>");
601 let cstring = CString::new(self).map_err(|_| ComError::E_INVALIDARG)?;
602 Ok(cstring.into_raw())
603 }
604
605 unsafe fn from_foreign_output(source: Self::ForeignType) -> ComResult<Self>
606 {
607 log::trace!("String::from_foreign_output<Raw>");
608 let cstring = CString::from_raw(source);
609 cstring.into_string().map_err(|_| ComError::E_INVALIDARG)
610 }
611}
612
613impl<'a> ExternType<AutomationTypeSystem> for &'a str
615{
616 type ForeignType = BSTR;
617}
618
619impl<'a> ExternType<RawTypeSystem> for &'a str
620{
621 type ForeignType = *mut c_char;
622}
623
624unsafe impl<'a> ExternInput<AutomationTypeSystem> for &'a str
625{
626 type Lease = BString;
627 unsafe fn into_foreign_parameter(self) -> ComResult<(Self::ForeignType, Self::Lease)>
628 {
629 log::trace!("&str::into_foreign_parameter<Automation>");
630 let bstring = BString::from_str(self).expect("Error type is never type");
631 Ok((BSTR(bstring.as_ptr() as *mut _), bstring))
632 }
633
634 type Owned = String;
635 unsafe fn from_foreign_parameter(source: Self::ForeignType) -> ComResult<Self::Owned>
636 {
637 log::trace!("&str::from_foreign_parameter<Automation>");
638 let bstr = BStr::from_ptr(source.0);
639 bstr.to_string().map_err(|_| ComError::E_INVALIDARG)
640 }
641}
642
643unsafe impl<'a> ExternInput<RawTypeSystem> for &'a str
644{
645 type Lease = CString;
646 unsafe fn into_foreign_parameter(self) -> ComResult<(Self::ForeignType, Self::Lease)>
647 {
648 log::trace!("&str::into_foreign_parameter<Raw>");
649 let cstring = CString::new(self).map_err(|_| ComError::E_INVALIDARG)?;
650 Ok((cstring.as_ptr() as *mut c_char, cstring))
651 }
652
653 type Owned = Self;
654 unsafe fn from_foreign_parameter(source: Self::ForeignType) -> ComResult<Self::Owned>
655 {
656 log::trace!("&str::from_foreign_parameter<Raw>");
657 let cstr = CStr::from_ptr(source);
658 cstr.to_str().map_err(|_| ComError::E_INVALIDARG)
659 }
660}
661
662impl ExternType<AutomationTypeSystem> for BString
664{
665 type ForeignType = BSTR;
666}
667
668impl ExternType<RawTypeSystem> for BString
669{
670 type ForeignType = *mut c_char;
671}
672
673unsafe impl ExternInput<AutomationTypeSystem> for BString
674{
675 type Lease = BString;
676 unsafe fn into_foreign_parameter(self) -> ComResult<(Self::ForeignType, Self::Lease)>
677 {
678 log::trace!("BString::into_foreign_parameter<Automation>");
679 Ok((BSTR(self.as_ptr() as *mut _), self))
680 }
681
682 type Owned = Self;
683 unsafe fn from_foreign_parameter(source: Self::ForeignType) -> ComResult<Self::Owned>
684 {
685 log::trace!("BString::from_foreign_parameter<Automation>");
686 Ok(BStr::from_ptr(source.0).to_owned())
687 }
688}
689
690unsafe impl ExternInput<RawTypeSystem> for BString
691{
692 type Lease = CString;
693 unsafe fn into_foreign_parameter(self) -> ComResult<(Self::ForeignType, Self::Lease)>
694 {
695 log::trace!("BString::into_foreign_parameter<Raw>");
696 self.to_string()
697 .map_err(|_| ComError::E_INVALIDARG)
698 .and_then(|string| CString::new(string).map_err(|_| ComError::E_INVALIDARG))
699 .map(|cstring| (cstring.as_ptr() as *mut _, cstring))
700 }
701
702 type Owned = Self;
703 unsafe fn from_foreign_parameter(source: Self::ForeignType) -> ComResult<Self::Owned>
704 {
705 log::trace!("BString::from_foreign_parameter<Raw>");
706 CStr::from_ptr(source)
707 .to_str()
708 .map(BString::from)
709 .map_err(|_| ComError::E_INVALIDARG)
710 }
711}
712
713unsafe impl ExternOutput<AutomationTypeSystem> for BString
714{
715 fn into_foreign_output(self) -> ComResult<Self::ForeignType>
716 {
717 log::trace!("BString::into_foreign_output<Automation>");
718 Ok(BSTR(self.into_ptr() as *mut _))
719 }
720
721 unsafe fn from_foreign_output(source: Self::ForeignType) -> ComResult<Self>
722 {
723 log::trace!("BString::from_foreign_output<Automation>");
724 Ok(BString::from_ptr(source.0))
725 }
726}
727
728unsafe impl ExternOutput<RawTypeSystem> for BString
729{
730 fn into_foreign_output(self) -> ComResult<Self::ForeignType>
731 {
732 log::trace!("BString::into_foreign_output<Raw>");
733 self.to_string()
734 .map_err(|_| ComError::E_INVALIDARG)
735 .and_then(|string| CString::new(string).map_err(|_| ComError::E_INVALIDARG))
736 .map(|cstring| cstring.into_raw())
737 }
738
739 unsafe fn from_foreign_output(source: Self::ForeignType) -> ComResult<Self>
740 {
741 log::trace!("BString::from_foreign_output<Raw>");
742 CString::from_raw(source)
743 .into_string()
744 .map(BString::from)
745 .map_err(|_| ComError::E_INVALIDARG)
746 }
747}
748
749impl ExternType<AutomationTypeSystem> for CString
751{
752 type ForeignType = BSTR;
753}
754
755impl ExternType<RawTypeSystem> for CString
756{
757 type ForeignType = *mut c_char;
758}
759
760unsafe impl ExternInput<AutomationTypeSystem> for CString
761{
762 type Lease = BString;
763 unsafe fn into_foreign_parameter(self) -> ComResult<(Self::ForeignType, Self::Lease)>
764 {
765 log::trace!("CString::into_foreign_parameter<Automation>");
766 let cstring = self.into_string().map_err(|_| ComError::E_INVALIDARG)?;
767 let bstring = BString::from(cstring);
768 Ok((BSTR(bstring.as_ptr() as *mut _), bstring))
769 }
770
771 type Owned = Self;
772 unsafe fn from_foreign_parameter(source: Self::ForeignType) -> ComResult<Self::Owned>
773 {
774 log::trace!("CString::from_foreign_parameter<Automation>");
775 CString::new(
776 BStr::from_ptr(source.0)
777 .to_string()
778 .map_err(|_| ComError::E_INVALIDARG)?,
779 )
780 .map_err(|_| ComError::E_INVALIDARG)
781 }
782}
783
784unsafe impl ExternInput<RawTypeSystem> for CString
785{
786 type Lease = CString;
787 unsafe fn into_foreign_parameter(self) -> ComResult<(Self::ForeignType, Self::Lease)>
788 {
789 log::trace!("CString::into_foreign_parameter<Raw>");
790 Ok((self.as_ptr() as *mut _, self))
791 }
792
793 type Owned = Self;
794 unsafe fn from_foreign_parameter(source: Self::ForeignType) -> ComResult<Self::Owned>
795 {
796 log::trace!("CString::from_foreign_parameter<Raw>");
797 Ok(CStr::from_ptr(source).to_owned())
798 }
799}
800
801unsafe impl ExternOutput<AutomationTypeSystem> for CString
802{
803 fn into_foreign_output(self) -> ComResult<Self::ForeignType>
804 {
805 log::trace!("CString::into_foreign_output<Automation>");
806 let cstring = self.into_string().map_err(|_| ComError::E_INVALIDARG)?;
807 Ok(BSTR(BString::from(cstring).into_ptr()))
808 }
809
810 unsafe fn from_foreign_output(source: Self::ForeignType) -> ComResult<Self>
811 {
812 log::trace!("CString::from_foreign_output<Automation>");
813 CString::new(
814 BString::from_ptr(source.0)
815 .to_string()
816 .map_err(|_| ComError::E_INVALIDARG)?,
817 )
818 .map_err(|_| ComError::E_INVALIDARG)
819 }
820}
821
822unsafe impl ExternOutput<RawTypeSystem> for CString
823{
824 fn into_foreign_output(self) -> ComResult<Self::ForeignType>
825 {
826 log::trace!("CString::into_foreign_output<Raw>");
827 Ok(self.into_raw())
828 }
829
830 unsafe fn from_foreign_output(source: Self::ForeignType) -> ComResult<Self>
831 {
832 log::trace!("CString::from_foreign_output<Raw>");
833 Ok(CString::from_raw(source))
834 }
835}
836
837impl<'a> ExternType<AutomationTypeSystem> for &'a CStr
839{
840 type ForeignType = BSTR;
841}
842
843impl<'a> ExternType<RawTypeSystem> for &'a CStr
844{
845 type ForeignType = *mut c_char;
846}
847
848unsafe impl<'a> ExternInput<AutomationTypeSystem> for &'a CStr
849{
850 type Lease = BString;
851 unsafe fn into_foreign_parameter(self) -> ComResult<(Self::ForeignType, Self::Lease)>
852 {
853 log::trace!("&CStr::into_foreign_parameter<Automation>");
854 let string = self.to_str().map_err(|_| ComError::E_INVALIDARG)?;
855 let bstring = BString::from(string);
856 Ok((BSTR(bstring.as_ptr() as *mut _), bstring))
857 }
858
859 type Owned = CString;
860 unsafe fn from_foreign_parameter(source: Self::ForeignType) -> ComResult<Self::Owned>
861 {
862 log::trace!("&CStr::from_foreign_parameter<Automation>");
863 let string = BStr::from_ptr(source.0)
864 .to_string()
865 .map_err(|_| ComError::E_INVALIDARG)?;
866 CString::new(string).map_err(|_| ComError::E_INVALIDARG)
867 }
868}
869
870unsafe impl<'a> ExternInput<RawTypeSystem> for &'a CStr
871{
872 type Lease = ();
873 unsafe fn into_foreign_parameter(self) -> ComResult<(Self::ForeignType, Self::Lease)>
874 {
875 log::trace!("&CStr::into_foreign_parameter<Raw>");
876 Ok((self.as_ptr() as *mut _, ()))
877 }
878
879 type Owned = Self;
880 unsafe fn from_foreign_parameter(source: Self::ForeignType) -> ComResult<Self::Owned>
881 {
882 log::trace!("&CStr::from_foreign_parameter<Raw>");
883 Ok(CStr::from_ptr(source))
884 }
885}
886
887impl<'a> ExternType<AutomationTypeSystem> for &'a BStr
889{
890 type ForeignType = BSTR;
891}
892
893impl<'a> ExternType<RawTypeSystem> for &'a BStr
894{
895 type ForeignType = *mut c_char;
896}
897
898unsafe impl<'a> ExternInput<AutomationTypeSystem> for &'a BStr
899{
900 type Lease = ();
901 unsafe fn into_foreign_parameter(self) -> ComResult<(Self::ForeignType, Self::Lease)>
902 {
903 log::trace!("&BStr::into_foreign_parameter<Automation>");
904 Ok((BSTR(self.as_ptr() as *mut _), ()))
905 }
906
907 type Owned = Self;
908 unsafe fn from_foreign_parameter(source: Self::ForeignType) -> ComResult<Self::Owned>
909 {
910 log::trace!("&BStr::from_foreign_parameter<Automation>");
911 Ok(BStr::from_ptr(source.0))
912 }
913}
914
915unsafe impl<'a> ExternInput<RawTypeSystem> for &'a BStr
916{
917 type Lease = CString;
918 unsafe fn into_foreign_parameter(self) -> ComResult<(Self::ForeignType, Self::Lease)>
919 {
920 log::trace!("&BStr::into_foreign_parameter<Raw>");
921 let string = self.to_string().map_err(|_| ComError::E_INVALIDARG)?;
922 let cstring = CString::new(string).map_err(|_| ComError::E_INVALIDARG)?;
923 Ok((cstring.as_ptr() as *mut c_char, cstring))
924 }
925
926 type Owned = BString;
927 unsafe fn from_foreign_parameter(source: Self::ForeignType) -> ComResult<Self::Owned>
928 {
929 log::trace!("&BStr::from_foreign_parameter<Raw>");
930 let string = CStr::from_ptr(source)
931 .to_str()
932 .map_err(|_| ComError::E_INVALIDARG)?;
933 Ok(BString::from(string))
934 }
935}
936
937#[cfg(test)]
938mod test
939{
940 use super::*;
941
942 #[test]
943 fn can_construct_bstring()
944 {
945 let bstrs: Vec<BString> = vec!["foo".into(), "foo".to_string().into()];
946
947 for bstr in bstrs {
948 assert_eq!(bstr.len_bytes(), 6);
949 assert_eq!(bstr.len(), 3);
950
951 let ptr = bstr.as_ptr();
952 unsafe {
953 assert_eq!(*(ptr.offset(-2) as *const u32), 6);
954 assert_eq!(*(ptr.offset(0)), 102u16);
955 assert_eq!(*(ptr.offset(1)), 111u16);
956 assert_eq!(*(ptr.offset(2)), 111u16);
957 assert_eq!(*(ptr.offset(3)), 0);
958 }
959 }
960 }
961
962 #[test]
963 fn can_construct_bstr()
964 {
965 let bstring: BString = "foo".into();
966 let bstr_data = [6u16, 0u16, 102u16, 111u16, 111u16, 0u16];
967
968 let bstrs: Vec<&BStr> = vec![bstring.as_ref(), unsafe {
969 BStr::from_ptr(bstr_data.as_ptr().offset(2))
970 }];
971
972 for bstr in bstrs {
973 assert_eq!(bstr.len_bytes(), 6);
974 assert_eq!(bstr.len(), 3);
975
976 let ptr = bstr.as_ptr();
977 unsafe {
978 assert_eq!(*(ptr.offset(-2) as *const u32), 6);
979 assert_eq!(*(ptr.offset(0)), 102u16);
980 assert_eq!(*(ptr.offset(1)), 111u16);
981 assert_eq!(*(ptr.offset(2)), 111u16);
982 assert_eq!(*(ptr.offset(3)), 0);
983 }
984 }
985 }
986
987 #[test]
988 fn bstr_eq()
989 {
990 let bstr_data = [6u16, 0u16, 102u16, 111u16, 111u16, 0u16];
991 let bstr = unsafe { BStr::from_ptr(bstr_data.as_ptr().offset(2)) };
992
993 let bstring_foo: BString = "foo".into();
994 assert_eq!(bstr, &*bstring_foo);
995
996 let bstring_bar: BString = "bar".into();
997 assert_ne!(bstr, &*bstring_bar);
998 }
999
1000 #[test]
1001 fn bstring_eq()
1002 {
1003 let bstring_foo1: BString = "foo".into();
1004 let bstring_foo2: BString = "foo".into();
1005 assert_eq!(bstring_foo1, bstring_foo2);
1006
1007 let bstring_bar: BString = "bar".into();
1008 assert_ne!(bstring_foo1, bstring_bar);
1009 }
1010}