0

I'm trying to Rust's cpal crate to enumerate a system's default host audio devices with the following code:

use cpal::traits::{HostTrait, DeviceTrait};
use cpal::{Device, Host};

fn main(){
    let default_host:Host = cpal::default_host();
    for device in default_host.devices().into_iter(){
        println!("> {}", device.name())
    }
}

When I run the code it becomes apparent that the objects I'm iterating through aren't Device objects but Devices objects, returning the following error:

error[E0599]: no method named `name` found for struct `Devices` in the current scope

   |
16 |         println!("> {}", device.name())
   |                                 ^^^^ method not found in `Devices`

Not sure where to go from here, I've read the relevant cpal and rust documentation repeatedly but I think I'm missing something very fundamental. Any idea what that might be?

Jmb
  • 18,893
  • 2
  • 28
  • 55
  • 1
    Note that `into_iter()` is redundant, `for` does that automatically. – Chayim Friedman Mar 16 '23 at 15:24
  • Please don't include the solution in the question. Instead you can [answer your own question](https://stackoverflow.com/help/self-answer). – Jmb Mar 17 '23 at 09:24

2 Answers2

2

Not sure where to go from here, I've read the relevant cpal and rust documentation repeatedly but I think I'm missing something very fundamental. Any idea what that might be?

HostTrait::Devices can apparently fail so it returns a

Result<Self::Devices, DevicesError>

Results, like options, are iterable, when iterated they behave as a sequence of 0 (Err) or 1 (Ok) items. That is what your into_iter() invokes, it iterates the result, rather than the devices inside the result.

Masklinn
  • 34,759
  • 3
  • 38
  • 57
0

Solution:

As @Masklinn noted, default_host.devices() actually returns a Result object, not a Devices object. I handled the Result using pattern matching and had each arm of the match call a different function. One panics in case of error, and one progresses the flow of logic if it returns successfully:

use cpal::traits::{HostTrait, DeviceTrait};
use cpal::{Device, Host};

fn main() {
    let default_host:Host = cpal::default_host();
    match default_host.devices() {
        Ok(devices) => print_devices(devices),
        Err(_error) => panic!("Error retrieving devices"),
    }; }

fn print_devices(default_host_devices: cpal::Devices) {
    for device in default_host_devices {
        println!("> {}", device.name().unwrap())
    } }

In the future I'll write a more robust version that doesn't panic upon failing to enumerate the host devices but for now this is fine. @Chayim Friedman also correctly noted that for loops call .to_iter() on objects automatically, so I removed the explicit .to_iter() from my print_devices function.