wirespec_backend_c/
lib.rs1pub mod checksum_binding;
6pub mod expr;
7pub mod header;
8pub mod names;
9pub mod parse_emit;
10pub mod serialize_emit;
11pub mod source;
12pub mod type_map;
13
14use wirespec_backend_api::*;
15use wirespec_codec::CodecModule;
16
17pub const TARGET_C: wirespec_backend_api::TargetId = wirespec_backend_api::TargetId("c");
18
19pub struct CBackend;
20
21impl Backend for CBackend {
22 type LoweredModule = CLoweredModule;
23
24 fn id(&self) -> TargetId {
25 TARGET_C
26 }
27
28 fn lower(
29 &self,
30 module: &CodecModule,
31 ctx: &BackendContext,
32 ) -> Result<Self::LoweredModule, BackendError> {
33 let opts = ctx
34 .target_options
35 .downcast_ref::<CBackendOptions>()
36 .ok_or_else(|| BackendError::UnsupportedOption {
37 target: TARGET_C,
38 option: "target_options".into(),
39 reason: "expected CBackendOptions".into(),
40 })?;
41 let emit_fuzz = opts.emit_fuzz_harness;
42
43 let header_content = header::emit_header(module, &ctx.module_prefix);
44 let source_content = source::emit_source(module, &ctx.module_prefix);
45 let fuzz_content = if emit_fuzz {
46 source::emit_fuzz_source(module, &ctx.module_prefix)
47 } else {
48 None
49 };
50
51 Ok(CLoweredModule {
52 header_content,
53 source_content,
54 fuzz_content,
55 prefix: ctx.module_prefix.clone(),
56 emit_fuzz,
57 })
58 }
59
60 fn emit(
61 &self,
62 lowered: &Self::LoweredModule,
63 sink: &mut dyn ArtifactSink,
64 ) -> Result<BackendOutput, BackendError> {
65 let mut artifacts = Vec::new();
66
67 sink.write(Artifact {
69 target: TARGET_C,
70 kind: ArtifactKind::C_HEADER,
71 module_name: lowered.prefix.clone(),
72 module_prefix: lowered.prefix.clone(),
73 relative_path: format!("{}.h", lowered.prefix).into(),
74 contents: lowered.header_content.as_bytes().to_vec(),
75 })?;
76 artifacts.push(ArtifactMeta {
77 kind: ArtifactKind::C_HEADER,
78 relative_path: format!("{}.h", lowered.prefix).into(),
79 byte_len: lowered.header_content.len(),
80 });
81
82 sink.write(Artifact {
84 target: TARGET_C,
85 kind: ArtifactKind::C_SOURCE,
86 module_name: lowered.prefix.clone(),
87 module_prefix: lowered.prefix.clone(),
88 relative_path: format!("{}.c", lowered.prefix).into(),
89 contents: lowered.source_content.as_bytes().to_vec(),
90 })?;
91 artifacts.push(ArtifactMeta {
92 kind: ArtifactKind::C_SOURCE,
93 relative_path: format!("{}.c", lowered.prefix).into(),
94 byte_len: lowered.source_content.len(),
95 });
96
97 if let Some(ref fuzz) = lowered.fuzz_content {
99 sink.write(Artifact {
100 target: TARGET_C,
101 kind: ArtifactKind::C_FUZZ_SOURCE,
102 module_name: lowered.prefix.clone(),
103 module_prefix: lowered.prefix.clone(),
104 relative_path: format!("{}_fuzz.c", lowered.prefix).into(),
105 contents: fuzz.as_bytes().to_vec(),
106 })?;
107 artifacts.push(ArtifactMeta {
108 kind: ArtifactKind::C_FUZZ_SOURCE,
109 relative_path: format!("{}_fuzz.c", lowered.prefix).into(),
110 byte_len: fuzz.len(),
111 });
112 }
113
114 Ok(BackendOutput {
115 target: TARGET_C,
116 artifacts,
117 })
118 }
119}
120
121pub struct CLoweredModule {
122 pub header_content: String,
123 pub source_content: String,
124 pub fuzz_content: Option<String>,
125 pub prefix: String,
126 pub emit_fuzz: bool,
127}
128
129impl BackendDyn for CBackend {
130 fn id(&self) -> TargetId {
131 TARGET_C
132 }
133
134 fn lower_and_emit(
135 &self,
136 module: &CodecModule,
137 ctx: &BackendContext,
138 sink: &mut dyn ArtifactSink,
139 ) -> Result<BackendOutput, BackendError> {
140 let lowered = Backend::lower(self, module, ctx)?;
141 Backend::emit(self, &lowered, sink)
142 }
143}