intercom/
strings.rs

1//!
2//! Intercom string representations.
3//!
4
5use 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/// Represents a borrowed BSTR string.
25#[derive(PartialEq, Eq)]
26pub struct BStr(
27    // Invariant 1: .0.as_ptr() must be a valid BSTR pointer _or_ 0x1 if len == 0.
28    //              This includes having u32 alignment.
29    // Invariant 2: .0.len() must fit to u32.
30    [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    /// Unsafely creates a `BStr` from a BSTR pointer.
50    ///
51    /// This function will cast the pointer into a `BStr`. The provied pointer
52    /// **must** be a valid BSTR pointer and must be valid while the BStr is
53    /// alive. The BStr must also not be moved.
54    ///
55    /// # Safety
56    ///
57    /// The parameter must be a valid BSTR pointer. This includes both the
58    /// memory layout and allocation using BSTR-compatible allocation
59    /// functions.
60    ///
61    /// In addition to this the pointer must be kept alive while the returned
62    /// reference is in use.
63    pub unsafe fn from_ptr<'a>(ptr: *const u16) -> &'a BStr
64    {
65        // The BStr invariant 1 states the ptr must be valid BSTR pointer,
66        // which is u32-aligned.
67        #![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    /// Unsafely creates a `BStr` from a slice.
78    ///
79    /// This function will cast the slice into a `BStr`. The slice **must**
80    /// be a slice constructed from a valid BSTR pointer. Specifically the slice
81    /// as_ptr() must result in a valid BSTR pointer.
82    unsafe fn from_slice_unchecked(slice: &[u8]) -> &BStr
83    {
84        &*(slice as *const [u8] as *const BStr)
85    }
86
87    /// Returns the pointer as a 16-bit wide character pointer.
88    pub fn as_ptr(&self) -> *const u16
89    {
90        // The BStr invariant 1 states the ptr must be valid BSTR pointer,
91        // which is u32-aligned.
92        #![allow(clippy::cast_ptr_alignment)]
93
94        // 0x1 is a marker pointer
95        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    /// Returns the string length in bytes.
104    ///
105    /// Does not include the length prefix or the terminating zero. However
106    /// any zero bytes in the middle of the string are included.
107    pub fn len_bytes(&self) -> u32
108    {
109        // The len() on the slice is stored separately and can be used even
110        // if the buffer itself points to an invalid value as is the case with
111        // some 0-length BSTRs.
112        self.0.len() as u32
113    }
114
115    /// Returns the string length in characters.
116    pub fn len(&self) -> u32
117    {
118        // As long as the BStr is valie this is safe.
119        unsafe { os::SysStringLen(self.as_ptr()) }
120    }
121
122    pub fn is_empty(&self) -> bool
123    {
124        self.len_bytes() == 0
125    }
126
127    /// Gets the BStr as a slice of 16-bit characters.
128    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
145/// An owned BSTR string Rust type.
146///
147/// Used for passing strings with their ownership through the COM interfaces.
148///
149/// # `BSTR` details
150///
151/// The `BSTR` is both a length prefixed and zero terminated string with UTF-16
152/// encoding. It is the string type widely used with Microsoft COM for
153/// interoperability purposes.
154///
155/// What makes the `BSTR` exotic is that the `*mut u16` pointer references the
156/// start of the string data. The length prefix is located _before_ the pointed
157/// value.
158///
159/// It is important to note that when COM servers return `BSTR` strings, they
160/// pass ownership of the string to the COM client. After this the COM client
161/// is responsible for de-allocating the memory. Because of this it is
162/// important that the memory allocation for `BSTR` values is well defined.
163///
164/// On Windows this means allocating the strings using `SysAllocString` or
165/// `SysAllocStringLen` methods and freeing them with `SysFreeString` by
166/// default.
167pub struct BString(
168    // The pointer must be 32-bit aligned.
169    *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        // Deref into &BStr and compare those.
194        **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    /// # Safety
209    ///
210    /// The parameter must be a valid BSTR pointer. This includes both the
211    /// memory layout and allocation using BSTR-compatible allocation
212    /// functions.
213    ///
214    /// In addition the pointer ownership moves to the BString and the pointer
215    /// must not be freed outside of BString drop.
216    pub unsafe fn from_ptr(ptr: *mut u16) -> BString
217    {
218        BString(ptr)
219    }
220
221    /// Converts a C-string into a `BString`.
222    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    /// Returns the pointer as a 16-bit wide character pointer.
228    pub fn as_mut_ptr(&mut self) -> *mut u16
229    {
230        self.0 as *mut u16
231    }
232
233    /// Converts the `BString` into a raw pointer.
234    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    /// Converts a Rust string into a `BString`.
247    fn from_str(s: &str) -> Result<BString, Self::Err>
248    {
249        // Avoid unnecessary allocations when the string is empty.
250        // Null and empty BSTRs should be treated as equal.
251        // See https://blogs.msdn.microsoft.com/ericlippert/2003/09/12/erics-complete-guide-to-bstr-semantics/
252        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            // Memory issues are traditionally fatal in Rust and do not cause
261            // Err-results.
262            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
280// AsRef/Borrow/ToOwned implementations.
281
282impl 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//////////////////////////////////////////
359// OS specific string allocation.
360
361#[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        // Match the SysAllocStringLen implementation on Windows when
389        // psz is null.
390        if psz.is_null() {
391            return BSTR(std::ptr::null_mut());
392        }
393
394        // Length prefix + data length + null-terminator.
395        // The length of BSTR is expressed as bytes in the prefix.
396        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        // Set the length prefix.
404        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        // The actual data.
409        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        // The BSTR pointers should be u32-aligned.
433        #![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
527// String
528impl 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
613// &str
614impl<'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
662// BString
663impl 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
749// CString
750impl 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
837// &CStr
838impl<'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
887// &BStr
888impl<'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}