What's the name of this pattern?

I wonder if this approach has a name in Rust community or literature. To myself I called this "payload pattern".

Let's say I have a list of points with a lot of attributes, and want to split it by points that are in a list.

#[derive(Copy, Hash, Eq, Debug)]
struct PointId(u32);

#[derive(Clone, Debug)]
struct Point {
	id: PointId,
	attribute1: u32,
	attribute2: String,
	attribute3: Category,  // an enum
	// etc.
}

fn slice_points(pts: Vec<Point>, split_ids: HashSet<PointId>) -> Vec<Vec<Point>> {
	let result: Vec<Vec<Point>> = vec![];
	let mut prev = 0;
	for i in 0..pts.len() {
		if i == pts.len() - 1 || split_ids.contains(&pts[i]) {
			result.push(pts[prev..i].into());
			prev = i;
		}
	}
	result
}

To write tests for slice_points, I only care whether point ID is correctly checked against the hashset, and whether the slices are correct. But the struct Point requires some fields, and generating dummies of these would be quite tedious.

I solve it this way: make a permanent struct or one in the params, with key attribute (id) as one field, and the rest as a generic that can be reduced to ():

// I for Id, P for Payload
fn slice_points<I, P>(pts: Vec<(I, P)>, split_ids: HashSet<I>) -> Vec<Vec<(I, P)>>
where I: Copy + Eq + Hash, P: Clone
{
	let result: Vec<Vec<P>> = vec![];
	let mut prev = 0;
	for i in 0..pts.len() {
		if i == pts.len() - 1 || split_ids.contains(&pts[i].0) {
			result.push(pts[prev..i].into());
			prev = i;
		}
	}
	result
}

#[cfg(test)]
mod test_slices {
	use super::slice_points;
	fn make_dummy(ids: &[u32]) -> Vec<(u32, ())> {
		ids.into_iter().map(|i| (i, ())).collect()
	}

	#[test]
	fn test_slice() {
		let dum1 = make_dummy(&[1u32, 2, 3, 4, 5]);
		let slice_pts: HashSet<u32> = &[3].collect();
		assert_eq!(slice_points(dum1, spice_pts), vec![vec![1, 2, 3], vec![3, 4, 5]]);
	}
}

An alternative approach would be to make a trait and demand to impl it for every structure that I want to store, which I found more troublesome: the main function code gets even more complex with all the trait bounds (IdTrait<Id = I>), and there's more to implement in the Point struct.

// NOT THE SOLUTION
trait IdTrait {
    type Id: Hash + Eq + Copy;
    fn id(&self) -> Self::Id;
}

impl IdTrait for Point {
    type Id = PointId;
    fn id(&self) -> PointId {
        self.id
    }
}

fn slice_points<P: IdTrait<Id = I>, I>(pts: Vec<P>, split_ids: HashSet<I>) -> Vec<Vec<(I, P)>>
where I: Copy + Eq + Hash, P: Clone
{
	let result: Vec<Vec<P>> = vec![];
	let mut prev = 0;
	for i in 0..pts.len() {
		if i == pts.len() - 1 || split_ids.contains(&pts[i].0) {
			result.push(pts[prev..i].into());
			prev = i;
		}
	}
	result
}

I though of an approach similar to ...by_key, where you provide a function that extracts the Id property from the payload struct, ...but I'm not sure it will work if I have a super-structure, like graph.

I probably would create a macro to make a points with dummy

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.