nixl_sys/utils/
string_list.rs

1// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::*;
17
18/// A safe wrapper around a list of strings from NIXL
19pub struct StringList {
20    inner: NonNull<bindings::nixl_capi_string_list_s>,
21}
22
23impl StringList {
24    pub(crate) fn new(inner: NonNull<bindings::nixl_capi_string_list_s>) -> Self {
25        Self { inner }
26    }
27
28    /// Returns the number of strings in the list
29    pub fn len(&self) -> Result<usize, NixlError> {
30        let mut size = 0;
31        let status = unsafe { nixl_capi_string_list_size(self.inner.as_ptr(), &mut size) };
32
33        match status {
34            0 => Ok(size),
35            -1 => Err(NixlError::InvalidParam),
36            _ => Err(NixlError::BackendError),
37        }
38    }
39
40    /// Returns true if the list contains no strings
41    pub fn is_empty(&self) -> Result<bool, NixlError> {
42        Ok(self.len()? == 0)
43    }
44
45    /// Returns the string at the given index
46    pub fn get(&self, index: usize) -> Result<&str, NixlError> {
47        let mut str_ptr = ptr::null();
48        let status = unsafe { nixl_capi_string_list_get(self.inner.as_ptr(), index, &mut str_ptr) };
49
50        match status {
51            0 => {
52                // SAFETY: If status is 0, str_ptr points to a valid null-terminated string
53                let c_str = unsafe { CStr::from_ptr(str_ptr) };
54                Ok(c_str.to_str().unwrap()) // Safe because NIXL strings are valid UTF-8
55            }
56            -1 => Err(NixlError::InvalidParam),
57            _ => Err(NixlError::BackendError),
58        }
59    }
60
61    /// Returns an iterator over the strings in the list
62    pub fn iter(&self) -> StringListIterator<'_> {
63        StringListIterator {
64            list: self,
65            index: 0,
66            length: self.len().unwrap_or(0),
67        }
68    }
69}
70
71impl Drop for StringList {
72    fn drop(&mut self) {
73        // SAFETY: self.inner is guaranteed to be valid by NonNull
74        unsafe {
75            nixl_capi_destroy_string_list(self.inner.as_ptr());
76        }
77    }
78}
79
80/// An iterator over the strings in a StringList
81pub struct StringListIterator<'a> {
82    list: &'a StringList,
83    index: usize,
84    length: usize,
85}
86
87impl<'a> Iterator for StringListIterator<'a> {
88    type Item = Result<&'a str, NixlError>;
89
90    fn next(&mut self) -> Option<Self::Item> {
91        if self.index >= self.length {
92            None
93        } else {
94            let result = self.list.get(self.index);
95            self.index += 1;
96            Some(result)
97        }
98    }
99
100    fn size_hint(&self) -> (usize, Option<usize>) {
101        let remaining = self.length - self.index;
102        (remaining, Some(remaining))
103    }
104}