1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crate::{
    list_devices_by_type, list_platforms, ClContext, ClDeviceID, ClPlatformID, DeviceType, Error,
    Output,
};

#[derive(Debug, Fail, PartialEq, Eq, Clone)]
pub enum ContextBuilderError {
    #[fail(display = "For context building devices and device type cannot both be specified")]
    CannotSpecifyDevicesAndDeviceType,

    #[fail(display = "For context building devices and platforms cannot both be specified")]
    CannotSpecifyDevicesAndPlatforms,
}

const DEVICES_AND_DEVICE_TYPE_ERROR: Error =
    Error::ContextBuilderError(ContextBuilderError::CannotSpecifyDevicesAndDeviceType);
const DEVICES_AND_PLATFORMS_ERROR: Error =
    Error::ContextBuilderError(ContextBuilderError::CannotSpecifyDevicesAndPlatforms);

pub struct ClContextBuilder<'a> {
    pub platforms: Option<&'a [ClPlatformID]>,
    pub device_type: Option<DeviceType>,
    pub devices: Option<&'a [ClDeviceID]>,
}

impl<'a> ClContextBuilder<'a> {
    pub fn new() -> ClContextBuilder<'a> {
        ClContextBuilder {
            platforms: None,
            device_type: None,
            devices: None,
        }
    }

    pub fn with_platforms(mut self, platforms: &'a [ClPlatformID]) -> ClContextBuilder<'a> {
        self.platforms = Some(platforms);
        self
    }

    pub fn with_device_type(mut self, device_type: DeviceType) -> ClContextBuilder<'a> {
        self.device_type = Some(device_type);
        self
    }

    pub fn with_devices(mut self, devices: &'a [ClDeviceID]) -> ClContextBuilder<'a> {
        self.devices = Some(devices);
        self
    }

    pub unsafe fn build(self) -> Output<BuiltClContext> {
        use ClContextBuilder as B;
        match self {
            B {
                device_type: Some(device_type),
                devices: None,
                platforms: None,
            } => ClContextBuilder::build_from_device_type(device_type),
            B {
                devices: Some(devices),
                device_type: None,
                platforms: None,
            } => ClContextBuilder::build_from_devices(devices),
            B {
                platforms: Some(platforms),
                device_type: None,
                devices: None,
            } => ClContextBuilder::build_from_platforms(platforms),
            B {
                platforms: Some(platforms),
                device_type: Some(device_type),
                devices: None,
            } => ClContextBuilder::build_from_platforms_with_device_type(platforms, device_type),
            B {
                platforms: None,
                device_type: None,
                devices: None,
            } => ClContextBuilder::build_with_defaults(),
            B {
                device_type: Some(_),
                devices: Some(_),
                ..
            } => Err(DEVICES_AND_DEVICE_TYPE_ERROR),
            B {
                devices: Some(_),
                platforms: Some(_),
                ..
            } => Err(DEVICES_AND_PLATFORMS_ERROR),
        }
    }

    pub unsafe fn build_with_defaults() -> Output<BuiltClContext> {
        let platforms = list_platforms()?;
        ClContextBuilder::build_from_platforms(&platforms[..])
    }

    pub unsafe fn build_from_platforms(platforms: &[ClPlatformID]) -> Output<BuiltClContext> {
        ClContextBuilder::build_from_platforms_with_device_type(platforms, DeviceType::ALL)
    }

    pub unsafe fn build_from_platforms_with_device_type(
        platforms: &[ClPlatformID],
        device_type: DeviceType,
    ) -> Output<BuiltClContext> {
        let mut devices = Vec::new();
        for p in platforms.iter() {
            let p_devices = list_devices_by_type(p, device_type)?;
            devices.extend(p_devices);
        }
        let context = ClContext::create(&devices[..])?;
        Ok(BuiltClContext::ContextWithDevices(context, devices))
    }

    pub unsafe fn build_from_devices(devices: &[ClDeviceID]) -> Output<BuiltClContext> {
        let context = ClContext::create(&devices[..])?;
        Ok(BuiltClContext::Context(context))
    }

    pub unsafe fn build_from_device_type(device_type: DeviceType) -> Output<BuiltClContext> {
        let platforms = list_platforms()?;
        ClContextBuilder::build_from_platforms_with_device_type(&platforms[..], device_type)
    }
}

pub enum BuiltClContext {
    Context(ClContext),
    ContextWithDevices(ClContext, Vec<ClDeviceID>),
}