mssf_core/
strings.rs

1// ------------------------------------------------------------
2// Copyright (c) Microsoft Corporation.  All rights reserved.
3// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
4// ------------------------------------------------------------
5
6use crate::{WString, PCWSTR};
7use mssf_com::FabricCommon::{IFabricStringResult, IFabricStringResult_Impl};
8use windows_core::implement;
9
10// Basic implementation of fabric string result
11// usually used as string return value to fabric runtime.
12#[derive(Debug)]
13#[implement(IFabricStringResult)]
14pub struct StringResult {
15    data: WString,
16}
17
18// Recommend to use WStringWrap to construct this and convert to
19// IFabricStringResult.
20impl StringResult {
21    pub fn new(data: WString) -> StringResult {
22        StringResult { data }
23    }
24}
25
26impl IFabricStringResult_Impl for StringResult_Impl {
27    fn get_String(&self) -> crate::PCWSTR {
28        // This is some hack to get the raw pointer out.
29        crate::PCWSTR::from_raw(self.data.as_ptr())
30    }
31}
32
33// If nullptr returns empty string.
34// requires the PCWSTR points to a valid buffer with null terminatior
35fn safe_pwstr_to_wstring(raw: PCWSTR) -> WString {
36    if raw.is_null() {
37        return WString::new();
38    }
39    WString::from_wide(unsafe { raw.as_wide() })
40}
41
42// Convert helper for WString and PCWSTR and IFabricStringResult
43pub struct WStringWrap {
44    h: WString,
45}
46
47impl WStringWrap {
48    pub fn into_wstring(self) -> WString {
49        self.h
50    }
51}
52
53impl From<WString> for WStringWrap {
54    fn from(value: WString) -> Self {
55        Self { h: value }
56    }
57}
58
59impl From<PCWSTR> for WStringWrap {
60    fn from(value: PCWSTR) -> Self {
61        let h = safe_pwstr_to_wstring(value);
62        Self { h }
63    }
64}
65
66impl From<WStringWrap> for WString {
67    fn from(val: WStringWrap) -> Self {
68        val.h
69    }
70}
71
72impl From<&IFabricStringResult> for WStringWrap {
73    fn from(value: &IFabricStringResult) -> Self {
74        let content = unsafe { value.get_String() };
75        let h = safe_pwstr_to_wstring(content);
76        Self { h }
77    }
78}
79
80impl From<WStringWrap> for IFabricStringResult {
81    fn from(value: WStringWrap) -> Self {
82        StringResult::new(value.h).into()
83    }
84}
85
86// note that wstring must be valid for pcwstr lifetime
87pub fn get_pcwstr_from_opt(opt: &Option<WString>) -> PCWSTR {
88    match opt {
89        Some(x) => PCWSTR(x.as_ptr()),
90        None => PCWSTR::null(),
91    }
92}
93
94#[cfg(test)]
95mod test {
96    use crate::strings::WStringWrap;
97
98    use super::StringResult;
99    use crate::WString;
100    use mssf_com::FabricCommon::IFabricStringResult;
101
102    #[test]
103    fn test_str_addr() {
104        // Test the addr returned to SF is right.
105        let addr = "1.2.3.4:1234";
106
107        // Check wstring len.
108        let haddr = WString::from(addr);
109        let haddr_slice = haddr.as_wide();
110        assert_eq!(haddr_slice.len(), 12);
111
112        // check StringResult len.
113        let com_addr: IFabricStringResult = StringResult::new(haddr.clone()).into();
114        let raw = unsafe { com_addr.get_String() };
115        let slice = unsafe { raw.as_wide() };
116        assert_eq!(slice.len(), 12);
117
118        // check StringResult conversion is right
119        let haddr2: WString = WStringWrap::from(&com_addr).into();
120        assert_eq!(haddr, haddr2);
121    }
122}