Skip to content

Commit fa9f07a

Browse files
Add Vec::replace and MutRef::replace
1 parent 587fedd commit fa9f07a

File tree

4 files changed

+84
-3
lines changed

4 files changed

+84
-3
lines changed

rustfmt.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
disable_all_formatting = true

soa-derive-internal/src/refs.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use proc_macro2::TokenStream;
1+
use proc_macro2::{Ident, Span, TokenStream};
22
use quote::quote;
33

44
use crate::input::Input;
@@ -26,6 +26,11 @@ pub fn derive(input: &Input) -> TokenStream {
2626
.map(|field| field.ident.clone().unwrap())
2727
.collect::<Vec<_>>();
2828

29+
let fields_names_hygienic = input.fields.iter()
30+
.enumerate()
31+
.map(|(i, _)| Ident::new(&format!("___soa_derive_private_{}", i), Span::call_site()))
32+
.collect::<Vec<_>>();
33+
2934
let ref_fields_types = input.map_fields_nested_or(
3035
|_, field_type| {
3136
let field_ptr_type = names::ref_name(field_type);
@@ -57,6 +62,11 @@ pub fn derive(input: &Input) -> TokenStream {
5762
|ident, _| quote! { self.#ident.clone() },
5863
).collect::<Vec<_>>();
5964

65+
let ref_replace = input.map_fields_nested_or(
66+
|ident, _| quote! { self.#ident.replace(field) },
67+
|ident, _| quote! { ::std::mem::replace(&mut *self.#ident, field) },
68+
).collect::<Vec<_>>();
69+
6070
quote! {
6171
/// A reference to a
6272
#[doc = #doc_url]
@@ -146,6 +156,19 @@ pub fn derive(input: &Input) -> TokenStream {
146156
#( #fields_names: #to_owned, )*
147157
}
148158
}
159+
160+
/// Similar to [`std::mem::replace()`](https://doc.rust-lang.org/std/mem/fn.replace.html).
161+
pub fn replace(&mut self, val: #name) -> #name {
162+
#(
163+
let field = unsafe { ::std::ptr::read(&val.#fields_names) };
164+
let #fields_names_hygienic = #ref_replace;
165+
)*
166+
// if val implements Drop, we don't want to run it here, only
167+
// when the vec itself will be dropped
168+
::std::mem::forget(val);
169+
170+
#name{#(#fields_names: #fields_names_hygienic),*}
171+
}
149172
}
150173
}
151174
}

soa-derive-internal/src/vec.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
use proc_macro2::{Ident, Span};
2-
use proc_macro2::{TokenStream};
1+
use proc_macro2::{Ident, Span, TokenStream};
32
use quote::TokenStreamExt;
43
use quote::quote;
54

@@ -68,6 +67,11 @@ pub fn derive(input: &Input) -> TokenStream {
6867
|ident, _| quote! { Vec::from_raw_parts(data.#ident, len, capacity) },
6968
).collect::<Vec<_>>();
7069

70+
let vec_replace = input.map_fields_nested_or(
71+
|ident, _| quote! { self.#ident.replace(index, field) },
72+
|ident, _| quote! { ::std::mem::replace(&mut self.#ident[index], field) },
73+
).collect::<Vec<_>>();
74+
7175
let mut generated = quote! {
7276
/// An analog to `
7377
#[doc = #vec_name_str]
@@ -210,6 +214,25 @@ pub fn derive(input: &Input) -> TokenStream {
210214
::std::mem::forget(element);
211215
}
212216

217+
/// Similar to [`std::mem::replace()`](https://doc.rust-lang.org/std/mem/fn.replace.html).
218+
pub fn replace(&mut self, index: usize, element: #name) -> #name {
219+
if index > self.len() {
220+
panic!("index out of bounds: the len is {} but the index is {}", self.len(), index);
221+
}
222+
223+
// similar to push, we can not use move and have to rely on ptr
224+
// read/write
225+
#(
226+
let field = unsafe { ::std::ptr::read(&element.#fields_names) };
227+
let #fields_names_hygienic = #vec_replace;
228+
)*
229+
// if value implements Drop, we don't want to run it here, only
230+
// when the vec itself will be dropped.
231+
::std::mem::forget(element);
232+
233+
#name{#(#fields_names: #fields_names_hygienic),*}
234+
}
235+
213236
/// Similar to [`
214237
#[doc = #vec_name_str]
215238
/// ::remove()`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.remove).

tests/replace.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#![allow(clippy::float_cmp)]
2+
3+
mod particles;
4+
use self::particles::{Particle, ParticleVec};
5+
6+
#[test]
7+
fn replace_element() {
8+
let mut soa = ParticleVec::new();
9+
soa.push(Particle::new(String::from("Na"), 22.990));
10+
soa.push(Particle::new(String::from("Zn"), 65.380));
11+
soa.push(Particle::new(String::from("Cl"), 35.453));
12+
13+
let particle = soa.replace(1, Particle::new(String::from("Br"), 79.904));
14+
assert_eq!(particle.name, "Zn");
15+
assert_eq!(particle.mass, 65.380);
16+
17+
assert_eq!(soa.name[1], "Br");
18+
assert_eq!(soa.mass[1], 79.904);
19+
}
20+
21+
#[test]
22+
fn replace_mutable_reference() {
23+
let mut soa = ParticleVec::new();
24+
soa.push(Particle::new(String::from("Na"), 22.990));
25+
soa.push(Particle::new(String::from("Zn"), 65.380));
26+
soa.push(Particle::new(String::from("Cl"), 35.453));
27+
28+
let particle = soa.index_mut(1).replace(Particle::new(String::from("Br"), 79.904));
29+
assert_eq!(particle.name, "Zn");
30+
assert_eq!(particle.mass, 65.380);
31+
32+
assert_eq!(soa.name[1], "Br");
33+
assert_eq!(soa.mass[1], 79.904);
34+
}

0 commit comments

Comments
 (0)