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 std::marker::PhantomData;
7
8use crate::{
9    PCWSTR, WString,
10    iter::{FabricIter, FabricListAccessor},
11};
12use mssf_com::FabricCommon::{
13    IFabricStringListResult, IFabricStringResult, IFabricStringResult_Impl,
14};
15use windows_core::implement;
16
17// Basic implementation of fabric string result
18// usually used as string return value to fabric runtime.
19#[derive(Debug)]
20#[implement(IFabricStringResult)]
21pub struct StringResult {
22    data: WString,
23}
24
25// Recommend to use WStringWrap to construct this and convert to
26// IFabricStringResult.
27impl StringResult {
28    pub fn new(data: WString) -> StringResult {
29        StringResult { data }
30    }
31}
32
33impl IFabricStringResult_Impl for StringResult_Impl {
34    fn get_String(&self) -> crate::PCWSTR {
35        // This is some hack to get the raw pointer out.
36        crate::PCWSTR::from_raw(self.data.as_ptr())
37    }
38}
39
40// TODO: deprecate
41// If nullptr returns empty string.
42// requires the PCWSTR points to a valid buffer with null terminatior
43fn safe_pwstr_to_wstring(raw: PCWSTR) -> WString {
44    WString::from(&raw)
45}
46
47// TODO: deprecate
48// Convert helper for WString and PCWSTR and IFabricStringResult
49pub struct WStringWrap {
50    h: WString,
51}
52
53impl WStringWrap {
54    pub fn into_wstring(self) -> WString {
55        self.h
56    }
57}
58
59impl From<WString> for WStringWrap {
60    fn from(value: WString) -> Self {
61        Self { h: value }
62    }
63}
64
65impl From<PCWSTR> for WStringWrap {
66    fn from(value: PCWSTR) -> Self {
67        let h = safe_pwstr_to_wstring(value);
68        Self { h }
69    }
70}
71
72impl From<WStringWrap> for WString {
73    fn from(val: WStringWrap) -> Self {
74        val.h
75    }
76}
77
78impl From<&IFabricStringResult> for WStringWrap {
79    fn from(value: &IFabricStringResult) -> Self {
80        let content = unsafe { value.get_String() };
81        let h = safe_pwstr_to_wstring(content);
82        Self { h }
83    }
84}
85
86impl From<WStringWrap> for IFabricStringResult {
87    fn from(value: WStringWrap) -> Self {
88        StringResult::new(value.h).into()
89    }
90}
91
92// note that wstring must be valid for pcwstr lifetime
93pub fn get_pcwstr_from_opt(opt: &Option<WString>) -> PCWSTR {
94    match opt {
95        Some(x) => PCWSTR(x.as_ptr()),
96        None => PCWSTR::null(),
97    }
98}
99
100// IFabricStringListResult
101
102pub struct WStringList {
103    data: Vec<WString>,
104}
105
106impl WStringList {
107    pub fn into_vec(self) -> Vec<WString> {
108        self.data
109    }
110}
111
112impl From<&IFabricStringListResult> for WStringList {
113    fn from(value: &IFabricStringListResult) -> Self {
114        // cpp code should not error if the parameters are not null.
115        let mut itemcount = 0_u32;
116        let first_str = unsafe {
117            value
118                .GetStrings(std::ptr::addr_of_mut!(itemcount))
119                .expect("cannot get strings")
120        };
121        let l = FabricStringListAccessor {
122            itemcount,
123            first_str,
124            phantom: PhantomData,
125        };
126        let itr = FabricStringListAccessorIter::new(&l, &l);
127        let data = itr.collect::<Vec<_>>();
128        Self { data }
129    }
130}
131
132pub(crate) struct FabricStringListAccessor<'a> {
133    pub(crate) itemcount: u32,
134    pub(crate) first_str: *mut PCWSTR,
135    pub(crate) phantom: PhantomData<&'a IFabricStringListResult>,
136}
137
138impl FabricListAccessor<PCWSTR> for FabricStringListAccessor<'_> {
139    fn get_count(&self) -> u32 {
140        self.itemcount
141    }
142
143    fn get_first_item(&self) -> *const PCWSTR {
144        self.first_str
145    }
146}
147
148pub(crate) type FabricStringListAccessorIter<'a> =
149    FabricIter<'a, PCWSTR, WString, FabricStringListAccessor<'a>>;
150
151#[cfg(test)]
152mod test {
153    use crate::strings::WStringWrap;
154
155    use super::StringResult;
156    use crate::WString;
157    use mssf_com::FabricCommon::IFabricStringResult;
158
159    #[test]
160    fn test_str_addr() {
161        // Test the addr returned to SF is right.
162        let addr = "1.2.3.4:1234";
163
164        // Check wstring len.
165        let haddr = WString::from(addr);
166        let haddr_slice = haddr.as_wide();
167        assert_eq!(haddr_slice.len(), 12);
168
169        // check StringResult len.
170        let com_addr: IFabricStringResult = StringResult::new(haddr.clone()).into();
171        let raw = unsafe { com_addr.get_String() };
172        let slice = unsafe { raw.as_wide() };
173        assert_eq!(slice.len(), 12);
174
175        // check StringResult conversion is right
176        let haddr2: WString = WStringWrap::from(&com_addr).into();
177        assert_eq!(haddr, haddr2);
178    }
179}