Skip to main content

yash_env/system/virtual/
fd_set.rs

1// This file is part of yash, an extended POSIX shell.
2// Copyright (C) 2026 WATANABE Yuki
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17//! File descriptor set for the virtual system
18//!
19//! This module defines the [`FdSet` struct](FdSet), which is an implementation
20//! of the [`FdSet` trait](FdSetTrait) for the
21//! [`VirtualSystem`](super::VirtualSystem). The module also provides iterators
22//! for iterating over the file descriptors in an `FdSet`.
23
24use crate::io::{Fd, RawFd};
25use crate::system::FdSet as FdSetTrait;
26use std::collections::BTreeSet;
27
28/// File descriptor set for the virtual system
29///
30/// This is an implementation of the [`FdSet` trait](FdSetTrait) for the
31/// [`VirtualSystem`](super::VirtualSystem). It represents a set of file
32/// descriptors that can be monitored for events such as readability or
33/// writability in the virtual system. Currently, the `FdSet` struct internally
34/// uses a `BTreeSet` to store the file descriptors, which allows for efficient
35/// insertion, removal, and lookup of file descriptors.
36#[derive(Clone, Debug, Default, Eq, PartialEq)]
37pub struct FdSet(BTreeSet<Fd>);
38
39impl FdSetTrait for FdSet {
40    const MAX_FD: Fd = Fd(RawFd::MAX);
41
42    #[inline(always)]
43    fn insert(&mut self, fd: Fd) {
44        if fd.0 >= 0 {
45            self.0.insert(fd);
46        }
47    }
48
49    #[inline(always)]
50    fn remove(&mut self, fd: Fd) {
51        self.0.remove(&fd);
52    }
53
54    #[inline(always)]
55    fn contains(&self, fd: Fd) -> bool {
56        self.0.contains(&fd)
57    }
58}
59
60impl From<Fd> for FdSet {
61    #[inline(always)]
62    fn from(fd: Fd) -> Self {
63        let mut set = Self::new();
64        set.insert(fd);
65        set
66    }
67}
68
69impl FromIterator<Fd> for FdSet {
70    #[inline(always)]
71    fn from_iter<I: IntoIterator<Item = Fd>>(iter: I) -> Self {
72        Self(FromIterator::from_iter(iter))
73    }
74}
75
76/// Iterator over the file descriptors in an `FdSet`
77///
78/// Use `FdSet::into_iter` to create an iterator from an `FdSet`.
79#[derive(Debug)]
80pub struct IntoIter(std::collections::btree_set::IntoIter<Fd>);
81
82impl Iterator for IntoIter {
83    type Item = Fd;
84
85    #[inline(always)]
86    fn next(&mut self) -> Option<Self::Item> {
87        self.0.next()
88    }
89}
90
91impl IntoIterator for FdSet {
92    type Item = Fd;
93    type IntoIter = IntoIter;
94
95    #[inline(always)]
96    fn into_iter(self) -> Self::IntoIter {
97        IntoIter(self.0.into_iter())
98    }
99}
100
101/// Iterator over the file descriptors in an `FdSet` by reference
102///
103/// Use `FdSet::iter` to create an iterator from a reference to an `FdSet`.
104#[derive(Debug)]
105pub struct Iter<'a>(std::collections::btree_set::Iter<'a, Fd>);
106
107impl<'a> Iterator for Iter<'a> {
108    type Item = &'a Fd;
109
110    #[inline(always)]
111    fn next(&mut self) -> Option<Self::Item> {
112        self.0.next()
113    }
114}
115
116impl<'a> IntoIterator for &'a FdSet {
117    type Item = &'a Fd;
118    type IntoIter = Iter<'a>;
119
120    #[inline(always)]
121    fn into_iter(self) -> Self::IntoIter {
122        Iter(self.0.iter())
123    }
124}
125
126impl Extend<Fd> for FdSet {
127    fn extend<I: IntoIterator<Item = Fd>>(&mut self, iter: I) {
128        self.0.extend(iter);
129    }
130}
131
132impl<'a> Extend<&'a Fd> for FdSet {
133    fn extend<I: IntoIterator<Item = &'a Fd>>(&mut self, iter: I) {
134        self.0.extend(iter);
135    }
136}
137
138impl FdSet {
139    /// Returns the number of file descriptors in the set.
140    #[inline(always)]
141    pub fn len(&self) -> usize {
142        self.0.len()
143    }
144
145    /// Returns whether the set is empty.
146    #[inline(always)]
147    pub fn is_empty(&self) -> bool {
148        self.0.is_empty()
149    }
150
151    /// Returns an iterator over the file descriptors in the set.
152    #[inline(always)]
153    pub fn iter(&self) -> Iter<'_> {
154        self.into_iter()
155    }
156}