Hello,
I am wondering whether there is a better way to determine whether a shared vector contains an object and if it does not exist, push the new object into the vector. The first section of code, below, works as expected. The second set of code, which is commented out, deadlocks at the push().
I'd appreciate your suggestions for writing the best version of this code. It will be used in a Rust microservice using Tokio, etc., when things are correct.
The full project can be found at: abitofhelp.shared / rwlocking · GitLab
pub struct DatabaseConnection<T> {
pub database: T,
}
pub type InMemoryDatabase = RwLock<Vec<ProjectEntity>>;
pub type InMemoryDatabaseConnection = Arc<DatabaseConnection<InMemoryDatabase>>;
pub fn new() -> InMemoryDatabaseConnection {
let mut inmemory_database = RwLock::new(vec![
ProjectEntity::new(None, "abc".to_string(), 123, "America_Phoenix".to_string()).unwrap(),
ProjectEntity::new(None, "xyz".to_string(), 321, "America_Chicago".to_string()).unwrap(),
]);
InMemoryDatabaseConnection::from(DatabaseConnection {
database: inmemory_database,
})
}
fn main() -> std::io::Result<()> {
let database_connection = inmemory_database_connection::new();
let project = Project::from("zzz", 010, "UTC");
create_project(database_connection.clone(), project).map_err(|e| panic!("{e}"))
}
fn create_project(conn: InMemoryDatabaseConnection, project: Project) -> Result<(), ApiError> {
let project_name = project.name.clone();
{
println!(
"Searching for an existing project named '{}'",
&project.name
);
{
let read_binding = conn.database.read();
let exists = read_binding.iter().find(|p| p.name == project_name);
if exists.is_some() {
return Err(ApiError::NotFound {
message: format!("a project named '{}' already exists", &project_name),
err: None,
});
}
}
{
println!("A project named '{}' does not exist", &project_name);
let project_entity = ProjectEntityMapper::to_entity(project);
println!(
"Attempting to create() the project named '{}'",
&project_name
);
let mut write_binding = conn.database.write();
let result = write_binding.push(project_entity);
println!("Created the project named '{}'", &project_name);
Ok(result)
}
}
}
// IS IT POSSIBLE TO CHAIN THE READ AND WRITE? BASED ON MY READING AND EXPERIMENTING, IT LOOKS LIKE THE FOLLOWING IS NOT FEASIBLE.
//
// conn.database
// .read().iter()
// .find(|p| p.name == project.name)
// .map_or_else(
// || {
// println!(
// "A project named '{}' does not exist -- proceeding with create()",
// &project.name
// );
// let project_entity = ProjectEntityMapper::to_entity(project);
// println!("Attempting to create() the project");
// conn.database.write().push(project_entity);
//
// Ok(())
// },
// |pe| {
// Err(ApiError::NotFound {
// message: format!("a project named '{}' already exists", pe.name),
// err: None,
// })
// },
// )
// }