Unconstrained generic type

I'm trying to make a generic background iterator. It should take a real iterator, I and run it in another thread, while in the main thread, there'll be an iterator that receives items from channel.

The problem is with error type, E: compiler gives me Error 207: error[E0207]: the type parameter E is not constrained by the impl trait, self type, or predicates.

I thouugh I put a constraint by writing where E: Error + Send but compiler thinks otherwise.

How can I fix this?

pub struct BgIterator<T, E> {
	pub receiver: Receiver<T>,
	pub jh: JoinHandle<Result<(), E>>,
}

impl<I, T, E> BgIterator<I, T>
           ^ unconstrained type parameter

where I: Iterator<Item = T>,
E: Error + Send {
	pub fn new(bgitr: I, n: i32) -> BgIterator<I, T> {
		let (snd, rec):(Sender<T>, Receiver<T>) = bounded(n);
		let iter_handle = spawn(move || -> Result<(), E> {
			for obj in bgitr {
				snd.send(obj)?
			}
			drop(snd);
			Ok(())
		});
		BgIterator { jh: iter_handle, receiver: rec }
	}
}


impl<I, T, E> Iterator for BgIterator<I, T>
           ^ unconstrained type parameter

where E: Error + Send {
	type Item = Result<T, E>;
	fn next(&mut self) -> Option<<Self as Iterator>::Item> {
		match self.receiver.recv() {
			Ok(Some(v)) => Some(Ok(v)),
			Ok(None) => None,
			Err(e) => {
				self.jh.join();
				Some(Err(e))
			}
		}
	}
}

Unconstrained here means that, if you know what the Self type is, then you must be able to uniquely determine all generic parameters. So e.g. if Self = BgIterator<MyIterType, MyItemType>, then we know that I = MyIterType and T = MyItemType, but we cannot conclude what E should be from this information alone.

3 Likes

It has to be part of BgIterator. But are you just getting your generic parameters mixed up?

pub struct BgIterator<T, E> {
    pub receiver: Receiver<T>,
    pub jh: JoinHandle<Result<(), E>>,
}

impl<I, T, E> BgIterator<I, T>
// Why not <T, E>       ^^^^^^
// ...
let iter_handle = spawn(move || -> Result<(), E> {
//                                            ^
// Shouldn't this be T, the second param of BgIterator?
3 Likes

No, it's the result that the handle returns when it quits, and I don't need anything there. T is instead sent over the channel.

I didn't get the E right yet. I thought of sending Result<T, E> over the channel, to indicate an error inside the real iterator. But it seemed that an error in the bg thread function should be handled as well.

Made it compile this way. Boy, it looks so prickly.


pub enum BgIterError<T> {
	SendError(SendError<Option<T>>),
	RecvError(RecvError)
}

impl<T> From<SendError<Option<T>>> for BgIterError<T> { fn from(err: SendError<Option<T>>) -> Self { BgIterError::SendError(err) } }
impl<T> From<RecvError> for BgIterError<T> { fn from(err: RecvError) -> Self { BgIterError::RecvError(err) } }


pub struct BgIterator<T>
where T: Send {
	pub receiver: Receiver<Option<T>>,
	pub jh: Option<JoinHandle<Result<(), BgIterError<T>>>>,
}

impl<T: 'static> BgIterator<T>
where T: Send {
	pub fn new<I: 'static>(bgitr: I, q_len: usize) -> BgIterator<T>
	where I: Iterator<Item = Option<T>> + Send {
		let (snd, rec):(Sender<Option<T>>, Receiver<Option<T>>) = bounded(q_len);
		let iter_handle = spawn(move || -> Result<(), BgIterError<T>> {
			for obj in bgitr {
				snd.send(obj)?
			}
			drop(snd);
			Ok(())
		});
		BgIterator { jh: Some(iter_handle), receiver: rec }
	}
}


impl<T: 'static> Iterator for BgIterator<T>
where T: Send {

	// error in iterator should be returned as Err(E) hence this Result wrapper
	type Item = Result<T, BgIterError<T>>;
	fn next(&mut self) -> Option<<Self as Iterator>::Item> {
		match self.receiver.recv() {
			Ok(Some(v)) => Some(Ok(v)),
			Ok(None) => None,
			Err(e) => {
				self.jh.take().map(|jh| jh.join());
				Some(Err(BgIterError::from(e)))
			}
		}
	}
}

I would encourage you to put that through rustfmt. The idiomatic way to format where clauses is like this:

impl<T: 'static> BgIterator<T>
where
    T: Send,
{
    pub fn new<I: 'static>(bgitr: I, q_len: usize) -> BgIterator<T>
    where
        I: Iterator<Item = Option<T>> + Send,
    {
2 Likes

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.