Merge branch 'master' into maybe-sync-signal
This commit is contained in:
commit
f646f68b60
3 files changed
+405
-80
No files matched your search
@@ -83,6 +83,7 @@ dioxus-html = { workspace = true, features = ["hot-reload-context"] }
|
|||||||
dioxus-core = { workspace = true, features = ["serialize"] }
|
dioxus-core = { workspace = true, features = ["serialize"] }
|
||||||
dioxus-hot-reload = { workspace = true }
|
dioxus-hot-reload = { workspace = true }
|
||||||
interprocess-docfix = { version = "1.2.2" }
|
interprocess-docfix = { version = "1.2.2" }
|
||||||
|
gitignore = "1.0.8"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
|||||||
@@ -27,15 +27,17 @@ pub struct Autoformat {
|
|||||||
impl Autoformat {
|
impl Autoformat {
|
||||||
// Todo: autoformat the entire crate
|
// Todo: autoformat the entire crate
|
||||||
pub async fn autoformat(self) -> Result<()> {
|
pub async fn autoformat(self) -> Result<()> {
|
||||||
|
let Autoformat { check, raw, file } = self;
|
||||||
|
|
||||||
// Default to formatting the project
|
// Default to formatting the project
|
||||||
if self.raw.is_none() && self.file.is_none() {
|
if raw.is_none() && file.is_none() {
|
||||||
if let Err(e) = autoformat_project(self.check).await {
|
if let Err(e) = autoformat_project(check).await {
|
||||||
eprintln!("error formatting project: {}", e);
|
eprintln!("error formatting project: {}", e);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(raw) = self.raw {
|
if let Some(raw) = raw {
|
||||||
let indent = indentation_for(".")?;
|
let indent = indentation_for(".")?;
|
||||||
if let Some(inner) = dioxus_autofmt::fmt_block(&raw, 0, indent) {
|
if let Some(inner) = dioxus_autofmt::fmt_block(&raw, 0, indent) {
|
||||||
println!("{}", inner);
|
println!("{}", inner);
|
||||||
@@ -47,47 +49,90 @@ impl Autoformat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Format single file
|
// Format single file
|
||||||
if let Some(file) = self.file {
|
if let Some(file) = file {
|
||||||
let file_content;
|
refactor_file(file)?;
|
||||||
let indent;
|
|
||||||
if file == "-" {
|
|
||||||
indent = indentation_for(".")?;
|
|
||||||
let mut contents = String::new();
|
|
||||||
std::io::stdin().read_to_string(&mut contents)?;
|
|
||||||
file_content = Ok(contents);
|
|
||||||
} else {
|
|
||||||
indent = indentation_for(".")?;
|
|
||||||
file_content = fs::read_to_string(&file);
|
|
||||||
};
|
|
||||||
|
|
||||||
match file_content {
|
|
||||||
Ok(s) => {
|
|
||||||
let edits = dioxus_autofmt::fmt_file(&s, indent);
|
|
||||||
let out = dioxus_autofmt::apply_formats(&s, edits);
|
|
||||||
if file == "-" {
|
|
||||||
print!("{}", out);
|
|
||||||
} else {
|
|
||||||
match fs::write(&file, out) {
|
|
||||||
Ok(_) => {
|
|
||||||
println!("formatted {}", file);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("failed to write formatted content to file: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("failed to open file: {}", e);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn refactor_file(file: String) -> Result<(), Error> {
|
||||||
|
let indent = indentation_for(".")?;
|
||||||
|
let file_content = if file == "-" {
|
||||||
|
let mut contents = String::new();
|
||||||
|
std::io::stdin().read_to_string(&mut contents)?;
|
||||||
|
Ok(contents)
|
||||||
|
} else {
|
||||||
|
fs::read_to_string(&file)
|
||||||
|
};
|
||||||
|
let Ok(s) = file_content else {
|
||||||
|
eprintln!("failed to open file: {}", file_content.unwrap_err());
|
||||||
|
exit(1);
|
||||||
|
};
|
||||||
|
let edits = dioxus_autofmt::fmt_file(&s, indent);
|
||||||
|
let out = dioxus_autofmt::apply_formats(&s, edits);
|
||||||
|
|
||||||
|
if file == "-" {
|
||||||
|
print!("{}", out);
|
||||||
|
} else if let Err(e) = fs::write(&file, out) {
|
||||||
|
eprintln!("failed to write formatted content to file: {e}",);
|
||||||
|
} else {
|
||||||
|
println!("formatted {}", file);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_project_files(config: &CrateConfig) -> Vec<PathBuf> {
|
||||||
|
let mut files = vec![];
|
||||||
|
|
||||||
|
let gitignore_path = config.crate_dir.join(".gitignore");
|
||||||
|
if gitignore_path.is_file() {
|
||||||
|
let gitigno = gitignore::File::new(gitignore_path.as_path()).unwrap();
|
||||||
|
if let Ok(git_files) = gitigno.included_files() {
|
||||||
|
let git_files = git_files
|
||||||
|
.into_iter()
|
||||||
|
.filter(|f| f.ends_with(".rs") && !is_target_dir(f));
|
||||||
|
files.extend(git_files)
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
collect_rs_files(&config.crate_dir, &mut files);
|
||||||
|
}
|
||||||
|
|
||||||
|
files
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_target_dir(file: &Path) -> bool {
|
||||||
|
let stripped = if let Ok(cwd) = std::env::current_dir() {
|
||||||
|
file.strip_prefix(cwd).unwrap_or(file)
|
||||||
|
} else {
|
||||||
|
file
|
||||||
|
};
|
||||||
|
if let Some(first) = stripped.components().next() {
|
||||||
|
first.as_os_str() == "target"
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn format_file(
|
||||||
|
path: impl AsRef<Path>,
|
||||||
|
indent: IndentOptions,
|
||||||
|
) -> Result<usize, tokio::io::Error> {
|
||||||
|
let contents = tokio::fs::read_to_string(&path).await?;
|
||||||
|
|
||||||
|
let edits = dioxus_autofmt::fmt_file(&contents, indent);
|
||||||
|
let len = edits.len();
|
||||||
|
|
||||||
|
if !edits.is_empty() {
|
||||||
|
let out = dioxus_autofmt::apply_formats(&contents, edits);
|
||||||
|
tokio::fs::write(path, out).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(len)
|
||||||
|
}
|
||||||
|
|
||||||
/// Read every .rs file accessible when considering the .gitignore and try to format it
|
/// Read every .rs file accessible when considering the .gitignore and try to format it
|
||||||
///
|
///
|
||||||
/// Runs using Tokio for multithreading, so it should be really really fast
|
/// Runs using Tokio for multithreading, so it should be really really fast
|
||||||
@@ -96,8 +141,13 @@ impl Autoformat {
|
|||||||
async fn autoformat_project(check: bool) -> Result<()> {
|
async fn autoformat_project(check: bool) -> Result<()> {
|
||||||
let crate_config = crate::CrateConfig::new(None)?;
|
let crate_config = crate::CrateConfig::new(None)?;
|
||||||
|
|
||||||
let mut files_to_format = vec![];
|
let files_to_format = get_project_files(&crate_config);
|
||||||
collect_rs_files(&crate_config.crate_dir, &mut files_to_format);
|
|
||||||
|
if files_to_format.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let indent = indentation_for(&files_to_format[0])?;
|
||||||
|
|
||||||
if files_to_format.is_empty() {
|
if files_to_format.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -107,38 +157,17 @@ async fn autoformat_project(check: bool) -> Result<()> {
|
|||||||
|
|
||||||
let counts = files_to_format
|
let counts = files_to_format
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|file| {
|
|
||||||
if file.components().any(|f| f.as_os_str() == "target") {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
})
|
|
||||||
.map(|path| async {
|
.map(|path| async {
|
||||||
let _path = path.clone();
|
let path_clone = path.clone();
|
||||||
let _indent = indent.clone();
|
let res = tokio::spawn(format_file(path, indent.clone())).await;
|
||||||
let res = tokio::spawn(async move {
|
|
||||||
let contents = tokio::fs::read_to_string(&path).await?;
|
|
||||||
|
|
||||||
let edits = dioxus_autofmt::fmt_file(&contents, _indent.clone());
|
|
||||||
let len = edits.len();
|
|
||||||
|
|
||||||
if !edits.is_empty() {
|
|
||||||
let out = dioxus_autofmt::apply_formats(&contents, edits);
|
|
||||||
tokio::fs::write(&path, out).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(len) as Result<usize, tokio::io::Error>
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("error formatting file: {}\n{err}", _path.display());
|
eprintln!("error formatting file: {}\n{err}", path_clone.display());
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Ok(Err(err)) => {
|
Ok(Err(err)) => {
|
||||||
eprintln!("error formatting file: {}\n{err}", _path.display());
|
eprintln!("error formatting file: {}\n{err}", path_clone.display());
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Ok(Ok(res)) => Some(res),
|
Ok(Ok(res)) => Some(res),
|
||||||
@@ -148,13 +177,7 @@ async fn autoformat_project(check: bool) -> Result<()> {
|
|||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let files_formatted: usize = counts
|
let files_formatted: usize = counts.into_iter().flatten().sum();
|
||||||
.into_iter()
|
|
||||||
.map(|f| match f {
|
|
||||||
Some(res) => res,
|
|
||||||
_ => 0,
|
|
||||||
})
|
|
||||||
.sum();
|
|
||||||
|
|
||||||
if files_formatted > 0 && check {
|
if files_formatted > 0 && check {
|
||||||
eprintln!("{} files needed formatting", files_formatted);
|
eprintln!("{} files needed formatting", files_formatted);
|
||||||
@@ -207,26 +230,24 @@ fn indentation_for(file_or_dir: impl AsRef<Path>) -> Result<IndentOptions> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_rs_files(folder: &Path, files: &mut Vec<PathBuf>) {
|
fn collect_rs_files(folder: &impl AsRef<Path>, files: &mut Vec<PathBuf>) {
|
||||||
let Ok(folder) = folder.read_dir() else {
|
if is_target_dir(folder.as_ref()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let Ok(folder) = folder.as_ref().read_dir() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// load the gitignore
|
// load the gitignore
|
||||||
|
|
||||||
for entry in folder {
|
for entry in folder {
|
||||||
let Ok(entry) = entry else {
|
let Ok(entry) = entry else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
|
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
collect_rs_files(&path, files);
|
collect_rs_files(&path, files);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ext) = path.extension() {
|
if let Some(ext) = path.extension() {
|
||||||
if ext == "rs" {
|
if ext == "rs" && !is_target_dir(&path) {
|
||||||
files.push(path);
|
files.push(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -485,6 +485,309 @@ impl<S> MemoryLocation<S> {
|
|||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn try_borrow<T: Any>(
|
||||||
|
&self,
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
|
created_at: &'static std::panic::Location<'static>,
|
||||||
|
) -> Result<GenerationalRef<T>, BorrowError> {
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
self.0
|
||||||
|
.borrowed_at
|
||||||
|
.borrow_mut()
|
||||||
|
.push(std::panic::Location::caller());
|
||||||
|
match self.0.data.try_borrow() {
|
||||||
|
Ok(borrow) => match Ref::filter_map(borrow, |any| any.as_ref()?.downcast_ref::<T>()) {
|
||||||
|
Ok(reference) => Ok(GenerationalRef {
|
||||||
|
inner: reference,
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
borrow: GenerationalRefBorrowInfo {
|
||||||
|
borrowed_at: std::panic::Location::caller(),
|
||||||
|
borrowed_from: self.0,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Err(_) => Err(BorrowError::Dropped(ValueDroppedError {
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
|
created_at,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
Err(_) => Err(BorrowError::AlreadyBorrowedMut(AlreadyBorrowedMutError {
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
borrowed_mut_at: self.0.borrowed_mut_at.get().unwrap(),
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn try_borrow_mut<T: Any>(
|
||||||
|
&self,
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
|
created_at: &'static std::panic::Location<'static>,
|
||||||
|
) -> Result<GenerationalRefMut<T>, BorrowMutError> {
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
{
|
||||||
|
self.0
|
||||||
|
.borrowed_mut_at
|
||||||
|
.set(Some(std::panic::Location::caller()));
|
||||||
|
}
|
||||||
|
match self.0.data.try_borrow_mut() {
|
||||||
|
Ok(borrow_mut) => {
|
||||||
|
match RefMut::filter_map(borrow_mut, |any| any.as_mut()?.downcast_mut::<T>()) {
|
||||||
|
Ok(reference) => Ok(GenerationalRefMut {
|
||||||
|
inner: reference,
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
borrow: GenerationalRefMutBorrowInfo {
|
||||||
|
borrowed_from: self.0,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Err(_) => Err(BorrowMutError::Dropped(ValueDroppedError {
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
|
created_at,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => Err(BorrowMutError::AlreadyBorrowed(AlreadyBorrowedError {
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
borrowed_at: self.0.borrowed_at.borrow().clone(),
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
/// An error that can occur when trying to borrow a value.
|
||||||
|
pub enum BorrowError {
|
||||||
|
/// The value was dropped.
|
||||||
|
Dropped(ValueDroppedError),
|
||||||
|
/// The value was already borrowed mutably.
|
||||||
|
AlreadyBorrowedMut(AlreadyBorrowedMutError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for BorrowError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
BorrowError::Dropped(error) => Display::fmt(error, f),
|
||||||
|
BorrowError::AlreadyBorrowedMut(error) => Display::fmt(error, f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for BorrowError {}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
/// An error that can occur when trying to borrow a value mutably.
|
||||||
|
pub enum BorrowMutError {
|
||||||
|
/// The value was dropped.
|
||||||
|
Dropped(ValueDroppedError),
|
||||||
|
/// The value was already borrowed.
|
||||||
|
AlreadyBorrowed(AlreadyBorrowedError),
|
||||||
|
/// The value was already borrowed mutably.
|
||||||
|
AlreadyBorrowedMut(AlreadyBorrowedMutError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for BorrowMutError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
BorrowMutError::Dropped(error) => Display::fmt(error, f),
|
||||||
|
BorrowMutError::AlreadyBorrowedMut(error) => Display::fmt(error, f),
|
||||||
|
BorrowMutError::AlreadyBorrowed(error) => Display::fmt(error, f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for BorrowMutError {}
|
||||||
|
|
||||||
|
/// An error that can occur when trying to use a value that has been dropped.
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct ValueDroppedError {
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
|
created_at: &'static std::panic::Location<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ValueDroppedError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str("Failed to borrow because the value was dropped.")?;
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_ownership"))]
|
||||||
|
f.write_fmt(format_args!("created_at: {}", self.created_at))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for ValueDroppedError {}
|
||||||
|
|
||||||
|
/// An error that can occur when trying to borrow a value that has already been borrowed mutably.
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct AlreadyBorrowedMutError {
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
borrowed_mut_at: &'static std::panic::Location<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for AlreadyBorrowedMutError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str("Failed to borrow because the value was already borrowed mutably.")?;
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
f.write_fmt(format_args!("borrowed_mut_at: {}", self.borrowed_mut_at))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for AlreadyBorrowedMutError {}
|
||||||
|
|
||||||
|
/// An error that can occur when trying to borrow a value mutably that has already been borrowed immutably.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct AlreadyBorrowedError {
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
borrowed_at: Vec<&'static std::panic::Location<'static>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for AlreadyBorrowedError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str("Failed to borrow mutably because the value was already borrowed immutably.")?;
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
f.write_str("borrowed_at:")?;
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
for location in self.borrowed_at.iter() {
|
||||||
|
f.write_fmt(format_args!("\t{}", location))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for AlreadyBorrowedError {}
|
||||||
|
|
||||||
|
/// A reference to a value in a generational box.
|
||||||
|
pub struct GenerationalRef<T: 'static> {
|
||||||
|
inner: Ref<'static, T>,
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
borrow: GenerationalRefBorrowInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> GenerationalRef<T> {
|
||||||
|
/// Map one ref type to another.
|
||||||
|
pub fn map<U, F>(orig: GenerationalRef<T>, f: F) -> GenerationalRef<U>
|
||||||
|
where
|
||||||
|
F: FnOnce(&T) -> &U,
|
||||||
|
{
|
||||||
|
GenerationalRef {
|
||||||
|
inner: Ref::map(orig.inner, f),
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
borrow: GenerationalRefBorrowInfo {
|
||||||
|
borrowed_at: orig.borrow.borrowed_at,
|
||||||
|
borrowed_from: orig.borrow.borrowed_from,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Filter one ref type to another.
|
||||||
|
pub fn filter_map<U, F>(orig: GenerationalRef<T>, f: F) -> Option<GenerationalRef<U>>
|
||||||
|
where
|
||||||
|
F: FnOnce(&T) -> Option<&U>,
|
||||||
|
{
|
||||||
|
let Self {
|
||||||
|
inner,
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
borrow,
|
||||||
|
} = orig;
|
||||||
|
Ref::filter_map(inner, f).ok().map(|inner| GenerationalRef {
|
||||||
|
inner,
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
borrow: GenerationalRefBorrowInfo {
|
||||||
|
borrowed_at: borrow.borrowed_at,
|
||||||
|
borrowed_from: borrow.borrowed_from,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> Deref for GenerationalRef<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.inner.deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
struct GenerationalRefBorrowInfo {
|
||||||
|
borrowed_at: &'static std::panic::Location<'static>,
|
||||||
|
borrowed_from: &'static MemoryLocationInner,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
impl Drop for GenerationalRefBorrowInfo {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.borrowed_from
|
||||||
|
.borrowed_at
|
||||||
|
.borrow_mut()
|
||||||
|
.retain(|location| std::ptr::eq(*location, self.borrowed_at as *const _));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A mutable reference to a value in a generational box.
|
||||||
|
pub struct GenerationalRefMut<T: 'static> {
|
||||||
|
inner: RefMut<'static, T>,
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
borrow: GenerationalRefMutBorrowInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> GenerationalRefMut<T> {
|
||||||
|
/// Map one ref type to another.
|
||||||
|
pub fn map<U, F>(orig: GenerationalRefMut<T>, f: F) -> GenerationalRefMut<U>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut T) -> &mut U,
|
||||||
|
{
|
||||||
|
GenerationalRefMut {
|
||||||
|
inner: RefMut::map(orig.inner, f),
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
borrow: orig.borrow,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Filter one ref type to another.
|
||||||
|
pub fn filter_map<U, F>(orig: GenerationalRefMut<T>, f: F) -> Option<GenerationalRefMut<U>>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut T) -> Option<&mut U>,
|
||||||
|
{
|
||||||
|
let Self {
|
||||||
|
inner,
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
borrow,
|
||||||
|
} = orig;
|
||||||
|
RefMut::filter_map(inner, f)
|
||||||
|
.ok()
|
||||||
|
.map(|inner| GenerationalRefMut {
|
||||||
|
inner,
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
borrow,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> Deref for GenerationalRefMut<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.inner.deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> DerefMut for GenerationalRefMut<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
self.inner.deref_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
struct GenerationalRefMutBorrowInfo {
|
||||||
|
borrowed_from: &'static MemoryLocationInner,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(debug_assertions, feature = "debug_borrows"))]
|
||||||
|
impl Drop for GenerationalRefMutBorrowInfo {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.borrowed_from.borrowed_mut_at.take();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Owner: Handles dropping generational boxes. The owner acts like a runtime lifetime guard. Any states that you create with an owner will be dropped when that owner is dropped.
|
/// Owner: Handles dropping generational boxes. The owner acts like a runtime lifetime guard. Any states that you create with an owner will be dropped when that owner is dropped.
|
||||||
|
|||||||
Reference in new issue
Block a user