use std::str::FromStr; use pyo3::{ exceptions::{PyException, PyValueError}, prelude::*, }; use snafu::{ResultExt, Snafu}; use strum::EnumString; #[derive(Debug, Clone, EnumString, strum::Display)] #[strum(serialize_all = "snake_case")] pub enum LightState { On, Off, } #[derive(Debug, Snafu)] pub enum ExtractLightStateError { /// couldn't extract the object as a string ExtractStringError { source: PyErr }, /// couldn't parse the string as a [`LightState`] ParseError { source: ::Err, }, } impl From for PyErr { fn from(error: ExtractLightStateError) -> Self { match &error { ExtractLightStateError::ExtractStringError { .. } => { PyException::new_err(error.to_string()) } ExtractLightStateError::ParseError { .. } => PyValueError::new_err(error.to_string()), } } } // TODO: replace with a derive(PyFromStr) (analogous to serde_with::DeserializeFromStr) once I make one impl<'a, 'py> FromPyObject<'a, 'py> for LightState { type Error = ExtractLightStateError; fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result { let s = ob.extract::<&str>().context(ExtractStringSnafu)?; let state = LightState::from_str(&s).context(ParseSnafu)?; Ok(state) } } impl From for protocol::light::State { fn from(light_state: LightState) -> Self { match light_state { LightState::On => protocol::light::State::On, LightState::Off => protocol::light::State::Off, } } } impl From for LightState { fn from(state: protocol::light::State) -> Self { match state { protocol::light::State::On => LightState::On, protocol::light::State::Off => LightState::Off, } } }