wrend/programs/
program_link.rs

1use crate::{
2    Id, ProgramLinkBuilderJsInner, ProgramLinkJs, ProgramLinkJsBuilder, ProgramLinkJsInner,
3};
4use std::fmt::Debug;
5use std::hash::Hash;
6use thiserror::Error;
7use wasm_bindgen::JsValue;
8
9/// This contains an id for a pair of shaders: one vertex shader and one fragment
10/// shader. These can be combined to link together a program.
11#[derive(Clone, Debug)]
12pub struct ProgramLink<ProgramId: Id, VertexShaderId: Id, FragmentShaderId: Id> {
13    program_id: ProgramId,
14    vertex_shader_id: VertexShaderId,
15    fragment_shader_id: FragmentShaderId,
16    transform_feedback_varyings: Vec<String>,
17}
18
19impl<ProgramId: Id, VertexShaderId: Id, FragmentShaderId: Id>
20    ProgramLink<ProgramId, VertexShaderId, FragmentShaderId>
21{
22    pub fn new(
23        program_id: ProgramId,
24        vertex_shader_id: VertexShaderId,
25        fragment_shader_id: FragmentShaderId,
26    ) -> Self {
27        Self {
28            program_id,
29            vertex_shader_id,
30            fragment_shader_id,
31            transform_feedback_varyings: Default::default(),
32        }
33    }
34
35    pub fn program_id(&self) -> &ProgramId {
36        &self.program_id
37    }
38
39    pub fn vertex_shader_id(&self) -> &VertexShaderId {
40        &self.vertex_shader_id
41    }
42
43    pub fn fragment_shader_id(&self) -> &FragmentShaderId {
44        &self.fragment_shader_id
45    }
46
47    pub fn transform_feedback_varyings(&self) -> &[String] {
48        &self.transform_feedback_varyings
49    }
50
51    pub fn builder() -> ProgramLinkBuilder<ProgramId, VertexShaderId, FragmentShaderId> {
52        ProgramLinkBuilder::default()
53    }
54}
55
56impl<ProgramId: Id, VertexShaderId: Id, FragmentShaderId: Id> Hash
57    for ProgramLink<ProgramId, VertexShaderId, FragmentShaderId>
58{
59    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
60        self.program_id.hash(state);
61        self.vertex_shader_id.hash(state);
62        self.fragment_shader_id.hash(state);
63    }
64}
65
66impl<ProgramId: Id, VertexShaderId: Id, FragmentShaderId: Id> PartialEq
67    for ProgramLink<ProgramId, VertexShaderId, FragmentShaderId>
68{
69    fn eq(&self, other: &Self) -> bool {
70        self.program_id == other.program_id
71            && self.vertex_shader_id == other.vertex_shader_id
72            && self.fragment_shader_id == other.fragment_shader_id
73    }
74}
75
76impl<ProgramId: Id, VertexShaderId: Id, FragmentShaderId: Id> Eq
77    for ProgramLink<ProgramId, VertexShaderId, FragmentShaderId>
78{
79}
80
81impl From<ProgramLink<String, String, String>> for JsValue {
82    fn from(program_link: ProgramLink<String, String, String>) -> Self {
83        let js_program_link: ProgramLinkJs = program_link.into();
84        js_program_link.into()
85    }
86}
87
88#[derive(Error, Debug)]
89pub enum ProgramLinkBuildError {
90    #[error("No VertexShaderId was supplied")]
91    NoVertexShaderId,
92    #[error("No FragmentShaderId was supplied")]
93    NoFragmentShaderId,
94    #[error("No ProgramId was supplied")]
95    NoProgramId,
96}
97
98#[derive(Clone)]
99pub struct ProgramLinkBuilder<ProgramId: Id, VertexShaderId: Id, FragmentShaderId: Id> {
100    program_id: Option<ProgramId>,
101    vertex_shader_id: Option<VertexShaderId>,
102    fragment_shader_id: Option<FragmentShaderId>,
103    transform_feedback_varyings: Vec<String>,
104}
105
106impl<ProgramId: Id, VertexShaderId: Id, FragmentShaderId: Id>
107    ProgramLinkBuilder<ProgramId, VertexShaderId, FragmentShaderId>
108{
109    pub fn new() -> Self {
110        Self::default()
111    }
112
113    pub fn set_program_id(&mut self, program_id: ProgramId) -> &mut Self {
114        self.program_id = Some(program_id);
115        self
116    }
117
118    pub fn set_vertex_shader_id(&mut self, vertex_shader_id: VertexShaderId) -> &mut Self {
119        self.vertex_shader_id = Some(vertex_shader_id);
120        self
121    }
122
123    pub fn set_fragment_shader_id(&mut self, fragment_shader_id: FragmentShaderId) -> &mut Self {
124        self.fragment_shader_id = Some(fragment_shader_id);
125        self
126    }
127
128    pub fn set_transform_feedback_varyings(
129        &mut self,
130        transform_feedback_varyings: impl Into<Vec<String>>,
131    ) -> &mut Self {
132        self.transform_feedback_varyings = transform_feedback_varyings.into();
133        self
134    }
135
136    pub fn build(
137        self,
138    ) -> Result<ProgramLink<ProgramId, VertexShaderId, FragmentShaderId>, ProgramLinkBuildError>
139    {
140        Ok(ProgramLink {
141            program_id: self.program_id.ok_or(ProgramLinkBuildError::NoProgramId)?,
142            vertex_shader_id: self
143                .vertex_shader_id
144                .ok_or(ProgramLinkBuildError::NoVertexShaderId)?,
145            fragment_shader_id: self
146                .fragment_shader_id
147                .ok_or(ProgramLinkBuildError::NoFragmentShaderId)?,
148            transform_feedback_varyings: self.transform_feedback_varyings,
149        })
150    }
151}
152
153impl<ProgramId: Id, VertexShaderId: Id, FragmentShaderId: Id> Default
154    for ProgramLinkBuilder<ProgramId, VertexShaderId, FragmentShaderId>
155{
156    fn default() -> Self {
157        Self {
158            program_id: Default::default(),
159            vertex_shader_id: Default::default(),
160            fragment_shader_id: Default::default(),
161            transform_feedback_varyings: Default::default(),
162        }
163    }
164}
165
166impl<ProgramId: Id, VertexShaderId: Id, FragmentShaderId: Id> Hash
167    for ProgramLinkBuilder<ProgramId, VertexShaderId, FragmentShaderId>
168{
169    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
170        self.program_id.hash(state);
171        self.vertex_shader_id.hash(state);
172        self.fragment_shader_id.hash(state);
173    }
174}
175
176impl<ProgramId: Id, VertexShaderId: Id, FragmentShaderId: Id> PartialEq
177    for ProgramLinkBuilder<ProgramId, VertexShaderId, FragmentShaderId>
178{
179    fn eq(&self, other: &Self) -> bool {
180        self.program_id == other.program_id
181            && self.vertex_shader_id == other.vertex_shader_id
182            && self.fragment_shader_id == other.fragment_shader_id
183    }
184}
185
186impl From<ProgramLinkBuilderJsInner> for JsValue {
187    fn from(program_link_builder: ProgramLinkBuilderJsInner) -> Self {
188        let js_program_link_builder: ProgramLinkJsBuilder = program_link_builder.into();
189        js_program_link_builder.into()
190    }
191}
192
193impl From<ProgramLinkJs> for ProgramLinkJsInner {
194    fn from(js_program_link: ProgramLinkJs) -> Self {
195        js_program_link.into_inner()
196    }
197}