Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InputPin with mutable self #546

Closed
usbalbin opened this issue Dec 13, 2023 · 1 comment · Fixed by #547
Closed

InputPin with mutable self #546

usbalbin opened this issue Dec 13, 2023 · 1 comment · Fixed by #547

Comments

@usbalbin
Copy link
Contributor

usbalbin commented Dec 13, 2023

Sorry if this has been asked earlier, I could not find an answer.

I was trying to implement a new type FilteredInputPin. Which wraps an ordinary generic InputPin but with some basic filtering added.

My plan was to implement InputPin for FilteredInputPin, every call to is_low/is_high would update its history and return the filters result. However that does not work since is_low and is_high both take shared references. Thus there is no way for me to update the filters history data.

Is this a use case that embedded-hal does not intend to support or is this an oversight? :)

Semi pseudo code:

struct FilteredInputPin<P> {
    pin: P,
    history: History,
}

impl<P: InputPin> InputPin for FilteredInputPin {
    type Error = P::Error;
    fn is_high(&self) -> Result<bool, Self::Error> {
        let new_value = self.pin.is_high()?;
        let result = self.history.update(new_value); // <--- Needs mutable access
        Ok(result)
    }
    ...
}
@usbalbin
Copy link
Contributor Author

@GrantM11235 's comment

Yes I think a Cell would probably be completely fine. Have actually never used gotten around to using a Cell, but that does indeed seem to be a sufficient solution here since my History type would probably just be something like a

#[derive(Copy, Clone)]
struct History {
    bits: u32
}

impl History {
    fn update(self, new_value: bool) -> (Self, bool) {
        let new_history = (self.bits << 1 | u32::from(new_value));
        let result = foo(new_history.count_ones());
        (new_history, result)
    }
}

so updating the example above:

struct FilteredInputPin<P> {
    pin: P,
    history: Cell<History>,
}

impl<P: InputPin> InputPin for FilteredInputPin {
    type Error = P::Error;
    fn is_high(&self) -> Result<bool, Self::Error> {
        let new_value = self.pin.is_high()?;
        let history = self.history.get(); // <-- Cell::get makes a copy of the history, assuming History: Copy
        let (new_history, result) = history.update(new_value); // <--- creates a new History object plus the result
        self.history.set(new_history); // <-- Overwrite cells contents with new history
        Ok(result)
    }
    ...
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant