clay_core/process/
program.rs

1use std::{
2    path::Path,
3};
4use regex::{Regex, RegexBuilder, Captures};
5use ocl::{
6    self,
7    enums::{ProgramBuildInfo as Pbi, ProgramBuildInfoResult as Pbir},
8};
9use ocl_include::{self, Hook};
10use lazy_static::lazy_static;
11use crate::{Context};
12
13
14lazy_static!{
15    static ref LOCATION: Regex = RegexBuilder::new(
16        r#"^([^:\r\n]*):(\d*):(\d*):"#
17    ).multi_line(true).build().unwrap();
18}
19
20/// Handler for source code of the device OpenCL program.
21///
22/// It is responsible for building the program and showing errors and warnings it they're exist.
23pub struct Program {
24    source: String,
25    index: ocl_include::Index,
26}
27
28impl Program {
29    pub fn new<H: Hook>(hook: &H, main: &Path) -> crate::Result<Self> {
30        let node = ocl_include::build(hook, main)?;
31        let (source, index) = node.collect();
32
33        Ok(Self { source, index })
34    }
35
36    pub fn source(&self) -> String {
37        self.source.clone()
38    }
39
40    fn replace_index(&self, message: &str) -> String {
41        LOCATION.replace_all(&message, |caps: &Captures| -> String {
42            caps[2].parse::<usize>().map_err(|_| ())
43            .and_then(|line| {
44                self.index.search(line - 1).ok_or(())
45            })
46            .and_then(|(path, local_line)| {
47                Ok(format!(
48                    "{}:{}:{}:",
49                    path.to_string_lossy(),
50                    local_line + 1,
51                    &caps[3],
52                ))
53            })
54            .unwrap_or(caps[0].to_string())
55        }).into_owned()
56    }
57
58    pub fn build(&self, context: &Context) -> crate::Result<(ocl::Program, String)> {
59        ocl::Program::builder()
60        .devices(context.device())
61        .source(self.source.clone())
62        .build(context.context())
63        .and_then(|p| {
64            p.build_info(context.device().clone(), Pbi::BuildLog)
65            .map(|pbi| match pbi {
66                Pbir::BuildLog(s) => s,
67                _ => unreachable!(),
68            })
69            .map(|log| {
70                if log.len() > 0 {
71                    println!("Build log: {}", log);
72                }
73                (p, self.replace_index(&log))
74            })
75            .map_err(|e| e.into())
76        })
77        .map_err(|e| {
78            let message = self.replace_index(&e.to_string());
79            ocl::Error::from(ocl::core::Error::from(message))
80        })
81        .map_err(|e| e.into())
82    }
83}