esp-rs / embedded-svc

Rust APIs and abstractions for various embedded services (WiFi, Network, Httpd, Logging, etc.)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ipv4.rs: Potentially incomplete implementation of Result in `impl TryFrom<Ipv4Addr> for Mask {}`

turgu1 opened this issue · comments

Hello,

I am implementing an instantiation of Wifi using specific IP address, subnet mask and gateway. The following code is close to be complete but I can't retrieve the error result from the try_from call, I can only use the unwrap() call (see line with // <======= comment):

pub struct Wireless {
    running: bool,
    wifi: Box<EspWifi>,
}

impl Wireless {
    pub fn new(cfg: Config) -> Result<Wireless, anyhow::Error> {
      let netif_stack = Arc::new(EspNetifStack::new()?);
      let sys_loop_stack = Arc::new(EspSysLoopStack::new()?);
      let default_nvs = Arc::new(EspDefaultNvs::new()?);

      let ssid = cfg.ssid.clone();
      let psw = cfg.wifi_password.clone();

      let mut wireless = Wireless {
        running: false,
        wifi: Box::new(EspWifi::new(netif_stack, sys_loop_stack, default_nvs)?),
      };

      let ap_infos = wireless.wifi.scan()?;

      let ours = ap_infos.into_iter().find(|a| a.ssid == ssid);

      let channel = if let Some(ours) = ours {
        info!(
          "Found configured access point {} on channel {}",
          ssid, ours.channel
        );
        Some(ours.channel)
      } else {
        info!(
          "Configured access point {} not found during scanning, will go with unknown channel",
          ssid
        );
        None
      };

      wireless
        .wifi
        .set_configuration(&Configuration::Client(ClientConfiguration {
          ssid: ssid.clone(),
          password: psw.clone(),
          ip_conf: Some(
            if cfg.ip.is_empty() { ipv4::ClientConfiguration::DHCP(Default::default()) }
            else { ipv4::ClientConfiguration::Fixed(ipv4::ClientSettings {
              ip: cfg.ip.parse::<Ipv4Addr>()?,
              subnet: ipv4::Subnet {
                gateway: cfg.gateway.parse::<Ipv4Addr>()?,
                mask: ipv4::Mask::try_from(cfg.subnet_mask.parse::<Ipv4Addr>()?).unwrap(),  // <==========
              },
              dns: Some(cfg.dns.parse::<Ipv4Addr>()?),
              ..Default::default()
            }) }
          ),
          ..Default::default()
        }))?;

I can't replace the .unwrap() call with ? as I receive the following message from the analyser:

[Result]()<[Mask](), ()>
Go to Result | Mask

error: the trait bound `(): StdError` is not satisfied
label: the trait `StdError` is not implemented for `()`

note: required because of the requirements on the impl of `From<()>` for `anyhow::Error`
label: the trait `StdError` is not implemented for `()`

note: required because of the requirements on the impl of `FromResidual<Result<Infallible, ()>>` for `Result<Wireless, anyhow::Error>`
label: the trait `StdError` is not implemented for `()`

the trait bound `(): StdError` is not satisfied
required because of the requirements on the impl of `From<()>` for `anyhow::Error`
required because of the requirements on the impl of `FromResidual<Result<Infallible, ()>>` for `Result<Wireless, anyhow::Error>`rustc[E0277](https://doc.rust-lang.org/error-index.html#E0277

Thanks for your help!!
Guy

That's because the implementation of TryFrom returns an error of type () which is not compatible with the STD Error trait, and as such the conversion of it to anyhow::Error(via ?) fails.

Now - I can implement a custom Error type which also implements the STD Error trait (if STD is enabled) and then use it in the TryFrom trait, but that's a lot of work and might be an overkill for a conversion - which if it fails - cannot return anything meaningful besides "I failed". :)

Regardless, and in the meantime - a quick remedy would be something like:

mask: ipv4::Mask::try_from(cfg.subnet_mask.parse::<Ipv4Addr>()?).map_err(|_| anyhow::anyhow!("Invalid mask"))?

Let me know if that works for you.

UPDATE: Or even

mask: ipv4::Mask::try_from(cfg.subnet_mask.parse::<Ipv4Addr>()?).map_err(|_| anyhow::anyhow!("Invalid mask {}", cfg.subnet_mask))?

Thanks a lot! I've learned something today!! It worked fine!

Cheers!
Guy

Closing for now, if more folks complain, I may implement a better compat with STD.