diff --git a/services/libs/jinux-std/src/fs/procfs/template/dir.rs b/services/libs/jinux-std/src/fs/procfs/template/dir.rs index 0442e16a2..8659574f3 100644 --- a/services/libs/jinux-std/src/fs/procfs/template/dir.rs +++ b/services/libs/jinux-std/src/fs/procfs/template/dir.rs @@ -2,9 +2,10 @@ use alloc::string::String; use core::any::Any; use core::time::Duration; use jinux_frame::vm::VmFrame; +use jinux_util::slot_vec::SlotVec; use crate::fs::utils::{ - DirEntryVec, DirentVisitor, FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata, + DirentVisitor, FileSystem, Inode, InodeMode, InodeType, IoctlCmd, Metadata, }; use crate::prelude::*; @@ -14,7 +15,7 @@ pub struct ProcDir { inner: D, this: Weak>, parent: Option>, - cached_children: RwLock)>>, + cached_children: RwLock)>>, info: ProcInodeInfo, } @@ -38,7 +39,7 @@ impl ProcDir { inner: dir, this: weak_self.clone(), parent, - cached_children: RwLock::new(DirEntryVec::new()), + cached_children: RwLock::new(SlotVec::new()), info, }) } @@ -51,7 +52,7 @@ impl ProcDir { self.parent.as_ref().and_then(|p| p.upgrade()) } - pub fn cached_children(&self) -> &RwLock)>> { + pub fn cached_children(&self) -> &RwLock)>> { &self.cached_children } } @@ -127,7 +128,7 @@ impl Inode for ProcDir { self.inner.populate_children(self.this.clone()); let cached_children = self.cached_children.read(); for (idx, (name, child)) in cached_children - .idxes_and_entries() + .idxes_and_items() .map(|(idx, (name, child))| (idx + 2, (name, child))) { if idx < *offset { diff --git a/services/libs/jinux-std/src/fs/ramfs/fs.rs b/services/libs/jinux-std/src/fs/ramfs/fs.rs index 0b375b9dd..03817be15 100644 --- a/services/libs/jinux-std/src/fs/ramfs/fs.rs +++ b/services/libs/jinux-std/src/fs/ramfs/fs.rs @@ -5,12 +5,12 @@ use core::any::Any; use core::sync::atomic::{AtomicUsize, Ordering}; use core::time::Duration; use jinux_frame::vm::VmFrame; +use jinux_util::slot_vec::SlotVec; use spin::{RwLock, RwLockWriteGuard}; use super::*; use crate::fs::utils::{ - DirEntryVec, DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoctlCmd, - Metadata, SuperBlock, + DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoctlCmd, Metadata, SuperBlock, }; pub struct RamFS { @@ -164,7 +164,7 @@ impl Inner { } struct DirEntry { - children: DirEntryVec<(Str256, Arc)>, + children: SlotVec<(Str256, Arc)>, this: Weak, parent: Weak, } @@ -172,7 +172,7 @@ struct DirEntry { impl DirEntry { fn new() -> Self { Self { - children: DirEntryVec::new(), + children: SlotVec::new(), this: Weak::default(), parent: Weak::default(), } @@ -205,13 +205,13 @@ impl DirEntry { Some((1, self.parent.upgrade().unwrap())) } else { self.children - .idxes_and_entries() + .idxes_and_items() .find(|(_, (child, _))| child == &Str256::from(name)) .map(|(idx, (_, inode))| (idx + 2, inode.clone())) } } - fn append_entry(&mut self, name: &str, inode: Arc) { + fn append_entry(&mut self, name: &str, inode: Arc) -> usize { self.children.put((Str256::from(name), inode)) } @@ -255,7 +255,7 @@ impl DirEntry { // Read the normal child entries. for (offset, (name, child)) in self .children - .idxes_and_entries() + .idxes_and_items() .map(|(offset, (name, child))| (offset + 2, (name, child))) { if offset < *idx { diff --git a/services/libs/jinux-std/src/fs/utils/direntry_vec.rs b/services/libs/jinux-std/src/fs/utils/direntry_vec.rs index 8e55e1c4d..b58fea932 100644 --- a/services/libs/jinux-std/src/fs/utils/direntry_vec.rs +++ b/services/libs/jinux-std/src/fs/utils/direntry_vec.rs @@ -1,87 +1,7 @@ use super::Inode; use crate::prelude::*; -/// DirEntryVec is used to store the entries of a directory. -/// It can guarantee that the index of one dir entry remains unchanged during -/// adding or deleting other dir entries of it. -pub struct DirEntryVec { - // The slots to store dir entries. - slots: Vec>, - // The number of occupied slots. - // The i-th slot is occupied if `self.slots[i].is_some()`. - num_occupied: usize, -} - -impl DirEntryVec { - /// New an empty vec. - pub fn new() -> Self { - Self { - slots: Vec::new(), - num_occupied: 0, - } - } - - /// Returns `true` if the vec contains no entries. - pub fn is_empty(&self) -> bool { - self.num_occupied == 0 - } - - /// Put a dir entry into the vec. - /// it may be put into an existing empty slot or the back of the vec. - pub fn put(&mut self, entry: T) { - if self.num_occupied == self.slots.len() { - self.slots.push(Some(entry)); - } else { - let idx = self.slots.iter().position(|x| x.is_none()).unwrap(); - self.slots[idx] = Some(entry); - } - self.num_occupied += 1; - } - - /// Removes and returns the entry at position `idx`. - /// Returns `None` if `idx` is out of bounds or the entry has been removed. - pub fn remove(&mut self, idx: usize) -> Option { - if idx >= self.slots.len() { - return None; - } - let mut del_entry = None; - core::mem::swap(&mut del_entry, &mut self.slots[idx]); - if del_entry.is_some() { - debug_assert!(self.num_occupied > 0); - self.num_occupied -= 1; - } - del_entry - } - - /// Put and returns the entry at position `idx`. - /// Returns `None` if `idx` is out of bounds or the entry has been removed. - pub fn put_at(&mut self, idx: usize, entry: T) -> Option { - if idx >= self.slots.len() { - return None; - } - let mut sub_entry = Some(entry); - core::mem::swap(&mut sub_entry, &mut self.slots[idx]); - if sub_entry.is_none() { - self.num_occupied += 1; - } - sub_entry - } - - /// Creates an iterator which gives both of the index and the dir entry. - /// The index may not be continuous. - pub fn idxes_and_entries(&self) -> impl Iterator { - self.slots - .iter() - .enumerate() - .filter(|(_, x)| x.is_some()) - .map(|(idx, x)| (idx, x.as_ref().unwrap())) - } - - /// Creates an iterator which gives the dir entry. - pub fn iter(&self) -> impl Iterator { - self.slots.iter().filter_map(|x| x.as_ref()) - } -} +use jinux_util::slot_vec::SlotVec; pub trait DirEntryVecExt { /// If the entry is not found by `name`, use `f` to get the inode, then put the entry into vec. @@ -92,7 +12,7 @@ pub trait DirEntryVecExt { fn remove_entry_by_name(&mut self, name: &str) -> Option<(String, Arc)>; } -impl DirEntryVecExt for DirEntryVec<(String, Arc)> { +impl DirEntryVecExt for SlotVec<(String, Arc)> { fn put_entry_if_not_found(&mut self, name: &str, f: impl Fn() -> Arc) { if self .iter() @@ -106,7 +26,7 @@ impl DirEntryVecExt for DirEntryVec<(String, Arc)> { fn remove_entry_by_name(&mut self, name: &str) -> Option<(String, Arc)> { let idx = self - .idxes_and_entries() + .idxes_and_items() .find(|(_, (child_name, _))| child_name == name) .map(|(idx, _)| idx); if let Some(idx) = idx { diff --git a/services/libs/jinux-std/src/fs/utils/mod.rs b/services/libs/jinux-std/src/fs/utils/mod.rs index b978ec323..dce7915d4 100644 --- a/services/libs/jinux-std/src/fs/utils/mod.rs +++ b/services/libs/jinux-std/src/fs/utils/mod.rs @@ -5,7 +5,7 @@ pub use channel::{Channel, Consumer, Producer}; pub use creation_flags::CreationFlags; pub use dentry_cache::Dentry; pub use dirent_visitor::DirentVisitor; -pub use direntry_vec::{DirEntryVec, DirEntryVecExt}; +pub use direntry_vec::DirEntryVecExt; pub use fcntl::FcntlCmd; pub use file_creation_mask::FileCreationMask; pub use fs::{FileSystem, FsFlags, SuperBlock}; diff --git a/services/libs/jinux-util/src/lib.rs b/services/libs/jinux-util/src/lib.rs index 92e184141..7e5eac35d 100644 --- a/services/libs/jinux-util/src/lib.rs +++ b/services/libs/jinux-util/src/lib.rs @@ -2,5 +2,8 @@ #![no_std] #![forbid(unsafe_code)] +extern crate alloc; + pub mod frame_ptr; +pub mod slot_vec; pub mod union_read_ptr; diff --git a/services/libs/jinux-util/src/slot_vec.rs b/services/libs/jinux-util/src/slot_vec.rs new file mode 100644 index 000000000..5c3e9faef --- /dev/null +++ b/services/libs/jinux-util/src/slot_vec.rs @@ -0,0 +1,119 @@ +use alloc::vec::Vec; + +/// SlotVec is the variant of Vector. +/// It guarantees that the index of one item remains unchanged during adding +/// or deleting other items of the vector. +pub struct SlotVec { + // The slots to store items. + slots: Vec>, + // The number of occupied slots. + // The i-th slot is occupied if `self.slots[i].is_some()`. + num_occupied: usize, +} + +impl SlotVec { + /// New an empty vector. + pub fn new() -> Self { + Self { + slots: Vec::new(), + num_occupied: 0, + } + } + + /// Return `true` if the vector contains no items. + pub fn is_empty(&self) -> bool { + self.num_occupied == 0 + } + + /// Return the number of items. + pub fn len(&self) -> usize { + self.num_occupied + } + + /// Return the number of slots. + pub fn slots_len(&self) -> usize { + self.slots.len() + } + + /// Get the item at position `idx`. + /// + /// Return `None` if `idx` is out of bounds or the item is not exist. + pub fn get(&self, idx: usize) -> Option<&T> { + if idx >= self.slots.len() { + return None; + } + self.slots[idx].as_ref() + } + + /// Put an item into the vector. + /// It may be put into any existing empty slots or the back of the vector. + /// + /// Return the index of the inserted item. + pub fn put(&mut self, entry: T) -> usize { + let idx = if self.num_occupied == self.slots.len() { + self.slots.push(Some(entry)); + self.slots.len() - 1 + } else { + let idx = self.slots.iter().position(|x| x.is_none()).unwrap(); + self.slots[idx] = Some(entry); + idx + }; + self.num_occupied += 1; + idx + } + + /// Put and return the item at position `idx`. + /// + /// Return `None` if the item is not exist. + pub fn put_at(&mut self, idx: usize, item: T) -> Option { + if idx >= self.slots.len() { + self.slots.resize_with(idx + 1, Default::default); + } + let mut sub_item = Some(item); + core::mem::swap(&mut sub_item, &mut self.slots[idx]); + if sub_item.is_none() { + self.num_occupied += 1; + } + sub_item + } + + /// Remove and return the item at position `idx`. + /// + /// Return `None` if `idx` is out of bounds or the item has been removed. + pub fn remove(&mut self, idx: usize) -> Option { + if idx >= self.slots.len() { + return None; + } + let mut del_item = None; + core::mem::swap(&mut del_item, &mut self.slots[idx]); + if del_item.is_some() { + debug_assert!(self.num_occupied > 0); + self.num_occupied -= 1; + } + del_item + } + + /// Create an iterator which gives both of the index and the item. + /// The index may not be continuous. + pub fn idxes_and_items(&self) -> impl Iterator { + self.slots + .iter() + .enumerate() + .filter(|(_, x)| x.is_some()) + .map(|(idx, x)| (idx, x.as_ref().unwrap())) + } + + /// Create an iterator which just gives the item. + pub fn iter(&self) -> impl Iterator { + self.slots.iter().filter_map(|x| x.as_ref()) + } +} + +impl Clone for SlotVec { + fn clone(&self) -> Self { + Self { + slots: self.slots.clone(), + num_occupied: self.num_occupied.clone(), + } + } +}