clay_core/process/
program.rs1use 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
20pub 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}