]>
git.proxmox.com Git - wasi-libc.git/blob - tools/wasi-headers/src/c_header.rs
43c66f78ef9c93b435977d5c36049a9ed7d52221
1 use heck
::ShoutySnakeCase
;
4 const PROLOGUE
: &str = r
#"/**
5 * THIS FILE IS AUTO-GENERATED!
8 * This file describes the WASI interface, consisting of functions, types,
9 * and defined values (macros).
11 * The interface described here is greatly inspired by [CloudABI]'s clean,
12 * thoughtfully-designed, cabability-oriented, POSIX-style API.
14 * [CloudABI]: https://github.com/NuxiNL/cloudlibc
21 #error <wasi/api.h> is only supported on WASI platforms.
27 _Static_assert(_Alignof(int8_t) == 1, "non-wasi data layout");
28 _Static_assert(_Alignof(uint8_t) == 1, "non-wasi data layout");
29 _Static_assert(_Alignof(int16_t) == 2, "non-wasi data layout");
30 _Static_assert(_Alignof(uint16_t) == 2, "non-wasi data layout");
31 _Static_assert(_Alignof(int32_t) == 4, "non-wasi data layout");
32 _Static_assert(_Alignof(uint32_t) == 4, "non-wasi data layout");
33 _Static_assert(_Alignof(int64_t) == 8, "non-wasi data layout");
34 _Static_assert(_Alignof(uint64_t) == 8, "non-wasi data layout");
40 // TODO: Encoding this in witx.
41 #define __WASI_DIRCOOKIE_START (UINT64_C(0))
44 const EPILOGUE
: &str = r
#"#ifdef __cplusplus
50 pub fn to_c_header(doc
: &Document
) -> String
{
51 let mut ret
= String
::new();
53 ret
.push_str(PROLOGUE
);
55 for d
in doc
.datatypes() {
56 print_datatype(&mut ret
, &*d
);
59 for m
in doc
.modules() {
60 print_module(&mut ret
, doc
, &m
);
63 ret
.push_str(EPILOGUE
);
68 fn print_datatype(ret
: &mut String
, d
: &Datatype
) {
69 if !d
.docs
.is_empty() {
70 ret
.push_str("/**\n");
71 for line
in d
.docs
.lines() {
72 ret
.push_str(&format
!(" * {}\n", line
));
74 ret
.push_str(" */\n");
78 DatatypeVariant
::Alias(a
) => print_alias(ret
, a
),
79 DatatypeVariant
::Enum(e
) => print_enum(ret
, e
),
80 DatatypeVariant
::Flags(f
) => print_flags(ret
, f
),
81 DatatypeVariant
::Struct(s
) => print_struct(ret
, s
),
82 DatatypeVariant
::Union(u
) => print_union(ret
, u
),
83 DatatypeVariant
::Handle(h
) => print_handle(ret
, h
),
87 fn print_alias(ret
: &mut String
, a
: &AliasDatatype
) {
89 DatatypeIdent
::Array(_
) => {
90 // Don't emit arrays as top-level types; instead we special-case
91 // them in places like parameter lists so that we can pass them
92 // as pointer and length pairs.
95 if a
.name
.as_str() == "size" {
96 // Special-case "size" as "__SIZE_TYPE__" -- TODO: Encode this in witx.
97 ret
.push_str(&format
!(
98 "typedef __SIZE_TYPE__ __wasi_{}_t;\n",
102 ret
.push_str(&format
!(
103 "typedef {} __wasi_{}_t;\n",
104 datatype_ident_name(&a
.to
),
113 fn print_enum(ret
: &mut String
, e
: &EnumDatatype
) {
114 ret
.push_str(&format
!(
115 "typedef {} __wasi_{}_t;\n",
116 intrepr_name(e
.repr
),
121 for (index
, variant
) in e
.variants
.iter().enumerate() {
122 if !variant
.docs
.is_empty() {
123 ret
.push_str("/**\n");
124 for line
in variant
.docs
.lines() {
125 ret
.push_str(&format
!(" * {}\n", line
));
127 ret
.push_str(" */\n");
129 ret
.push_str(&format
!(
130 "#define __WASI_{}_{} ((__wasi_{}_t){})\n",
131 ident_name(&e
.name
).to_shouty_snake_case(),
132 ident_name(&variant
.name
).to_shouty_snake_case(),
140 fn print_flags(ret
: &mut String
, f
: &FlagsDatatype
) {
141 ret
.push_str(&format
!(
142 "typedef {} __wasi_{}_t;\n",
143 intrepr_name(f
.repr
),
148 for (index
, flag
) in f
.flags
.iter().enumerate() {
149 if !flag
.docs
.is_empty() {
150 ret
.push_str("/**\n");
151 for line
in flag
.docs
.lines() {
152 ret
.push_str(&format
!(" * {}\n", line
));
154 ret
.push_str(" */\n");
156 ret
.push_str(&format
!(
157 "#define __WASI_{}_{} ((__wasi_{}_t){})\n",
158 ident_name(&f
.name
).to_shouty_snake_case(),
159 ident_name(&flag
.name
).to_shouty_snake_case(),
167 fn print_struct(ret
: &mut String
, s
: &StructDatatype
) {
168 ret
.push_str(&format
!(
169 "typedef struct __wasi_{}_t {{\n",
173 for member
in &s
.members
{
174 if !member
.docs
.is_empty() {
175 ret
.push_str(" /**\n");
176 for line
in member
.docs
.lines() {
177 ret
.push_str(&format
!(" * {}\n", line
));
179 ret
.push_str(" */\n");
181 ret
.push_str(&format
!(
183 datatype_ident_name(&member
.type_
),
184 ident_name(&member
.name
)
189 ret
.push_str(&format
!("}} __wasi_{}_t;\n", ident_name(&s
.name
)));
193 fn print_union(ret
: &mut String
, u
: &UnionDatatype
) {
194 ret
.push_str(&format
!(
195 "typedef union __wasi_{}_t {{\n",
199 for variant
in &u
.variants
{
200 if !variant
.docs
.is_empty() {
201 ret
.push_str(" /**\n");
202 for line
in variant
.docs
.lines() {
203 ret
.push_str(&format
!(" * {}\n", line
));
205 ret
.push_str(" */\n");
207 ret
.push_str(&format
!(
209 datatype_ident_name(&variant
.type_
),
210 ident_name(&variant
.name
)
215 ret
.push_str(&format
!("}} __wasi_{}_t;\n", ident_name(&u
.name
)));
219 fn print_handle(ret
: &mut String
, h
: &HandleDatatype
) {
220 ret
.push_str(&format
!("typedef int __wasi_{}_t;", ident_name(&h
.name
)));
223 fn print_module(ret
: &mut String
, doc
: &Document
, m
: &Module
) {
224 ret
.push_str("/**\n");
225 ret
.push_str(&format
!(" * @defgroup {}\n", ident_name(&m
.name
),));
226 for line
in m
.docs
.lines() {
227 ret
.push_str(&format
!(" * {}\n", line
));
229 ret
.push_str(" * @{\n");
230 ret
.push_str(" */\n");
233 for func
in m
.funcs() {
234 print_func(ret
, doc
, &func
, &m
.name
);
237 ret
.push_str("/** @} */\n");
241 fn print_func(ret
: &mut String
, doc
: &Document
, func
: &InterfaceFunc
, module_name
: &Id
) {
242 if !func
.docs
.is_empty() {
243 ret
.push_str("/**\n");
244 for line
in func
.docs
.lines() {
245 ret
.push_str(&format
!(" * {}\n", line
));
247 if !func
.results
.is_empty() {
248 let first_result
= &func
.results
[0];
249 if !first_result
.docs
.is_empty() {
250 ret
.push_str(" * @return\n");
251 for line
in first_result
.docs
.lines() {
252 ret
.push_str(&format
!(" * {}", line
));
256 ret
.push_str(" */\n");
258 if func
.results
.is_empty() {
259 // Special-case "proc_exit" as _Noreturn -- TODO: Encode this in witx.
260 if func
.name
.as_str() == "proc_exit" {
261 ret
.push_str("_Noreturn ");
263 ret
.push_str("void ");
265 let first_result
= &func
.results
[0];
266 ret
.push_str(&format
!("{} ", datatype_ident_name(&first_result
.type_
)));
269 ret
.push_str(&format
!("__wasi_{}(\n", ident_name(&func
.name
)));
271 if func
.params
.is_empty() && func
.results
.len() <= 1 {
272 ret
.push_str(" void\n");
274 for (index
, param
) in func
.params
.iter().enumerate() {
275 if !param
.docs
.is_empty() {
276 ret
.push_str(" /**\n");
277 for line
in param
.docs
.lines() {
278 ret
.push_str(&format
!(" * {}\n", line
));
280 ret
.push_str(" */\n");
282 add_params(ret
, doc
, &ident_name(¶m
.name
), ¶m
.type_
);
283 ret
.push_str(&format
!(
285 if index
+ 1 < func
.params
.len() || func
.results
.len() > 1 {
293 for (index
, result
) in func
.results
.iter().enumerate() {
295 // The first result is returned by value above.
298 if !result
.docs
.is_empty() {
299 ret
.push_str(" /**\n");
300 for line
in result
.docs
.lines() {
301 ret
.push_str(&format
!(" * {}\n", line
));
303 ret
.push_str(" */\n");
305 ret
.push_str(&format
!(
307 datatype_ident_name(&result
.type_
),
308 ident_name(&result
.name
),
309 if index
+ 1 < func
.results
.len() {
317 ret
.push_str(") __attribute__((\n");
318 ret
.push_str(&format
!(
319 " __import_module__(\"{}\"),\n",
320 ident_name(module_name
)
322 ret
.push_str(&format
!(
323 " __import_name__(\"{}\")",
324 ident_name(&func
.name
)
326 if !func
.results
.is_empty() {
327 ret
.push_str(",\n __warn_unused_result__\n");
329 ret
.push_str("));\n");
333 fn add_params(ret
: &mut String
, doc
: &Document
, name
: &str, type_
: &DatatypeIdent
) {
335 DatatypeIdent
::Ident(i
) => match &doc
.datatype(&i
.name
).unwrap().as_ref().variant
{
336 DatatypeVariant
::Alias(a
) => add_resolved_params(ret
, name
, &a
.to
),
337 _
=> add_resolved_params(ret
, name
, type_
),
339 _
=> add_resolved_params(ret
, name
, type_
),
343 fn add_resolved_params(ret
: &mut String
, name
: &str, type_
: &DatatypeIdent
) {
345 DatatypeIdent
::Builtin(BuiltinType
::String
) => {
346 ret
.push_str(&format
!(" const char *{},\n", name
));
348 ret
.push_str(" /**\n");
349 ret
.push_str(&format
!(
350 " * The length of the buffer pointed to by `{}`.\n",
353 ret
.push_str(" */\n");
354 ret
.push_str(&format
!(" size_t {}_len", name
));
356 DatatypeIdent
::Array(element
) => {
357 ret
.push_str(&format
!(
359 datatype_ident_name(&element
),
363 ret
.push_str(" /**\n");
364 ret
.push_str(&format
!(
365 " * The length of the array pointed to by `{}`.\n",
368 ret
.push_str(" */\n");
369 ret
.push_str(&format
!(" size_t {}_len", name
));
372 ret
.push_str(&format
!(" {} {}", datatype_ident_name(&type_
), name
));
377 fn ident_name(i
: &Id
) -> String
{
378 i
.as_str().to_string()
381 fn builtin_type_name(b
: BuiltinType
) -> &'
static str {
383 BuiltinType
::String
=> "string",
384 BuiltinType
::U8
=> "uint8_t",
385 BuiltinType
::U16
=> "uint16_t",
386 BuiltinType
::U32
=> "uint32_t",
387 BuiltinType
::U64
=> "uint64_t",
388 BuiltinType
::S8
=> "int8_t",
389 BuiltinType
::S16
=> "int16_t",
390 BuiltinType
::S32
=> "int32_t",
391 BuiltinType
::S64
=> "int64_t",
392 BuiltinType
::F32
=> "float",
393 BuiltinType
::F64
=> "double",
397 fn datatype_ident_name(data_ty
: &DatatypeIdent
) -> String
{
399 DatatypeIdent
::Builtin(b
) => builtin_type_name(*b
).to_string(),
400 DatatypeIdent
::Array(_
) => unreachable
!("arrays should be special-cased"),
401 DatatypeIdent
::Pointer(p
) => format
!("{} *", datatype_ident_name(&*p
)),
402 DatatypeIdent
::ConstPointer(p
) => format
!("const {} *", datatype_ident_name(&*p
)),
403 DatatypeIdent
::Ident(i
) => format
!("__wasi_{}_t", i
.name
.as_str()),
407 fn intrepr_name(i
: IntRepr
) -> &'
static str {
409 IntRepr
::U8
=> "uint8_t",
410 IntRepr
::U16
=> "uint16_t",
411 IntRepr
::U32
=> "uint32_t",
412 IntRepr
::U64
=> "uint64_t",