import sys
import os
import re
class SourceFile(object):
_one_indent_level = ' '
def __init__(self):
self._section = 0
self._lines = []
self._indents = []
def getsection(self):
return self._section
def section(self, section):
while len(self._lines) <= section:
self._lines.append([])
while len(self._indents) <= section:
self._indents.append(0)
self._section = section
def getindent(self):
return self._indents[self._section]
def setindent(self, indent):
self._indents[self._section] = indent;
def indent_block(self):
class Indenter(object):
def __init__(self, sf):
self.sf = sf
def __enter__(self):
self.sf.indent()
def __exit__(self, type, value, traceback):
self.sf.unindent()
return Indenter(self)
def indent(self):
self._indents[self._section] += 1
def unindent(self):
assert self.getindent() > 0, "negative indent"
self._indents[self._section] -= 1
def __call__(self, fmt, *args):
indent = SourceFile._one_indent_level * self._indents[self._section]
self._lines[self._section].append(indent + (fmt % args))
def writeout(self, path):
with open(path, 'w') as f:
for section in self._lines:
for line in section:
print(line.rstrip(), file=f)
_f = SourceFile()
_r = SourceFile()
def _rf(fmt, *args):
_f(fmt, *args)
_r(fmt, *args)
_ns = None
_ext_names = {}
finished_serializers = []
finished_sizeof = []
finished_switch = []
_types_uneligible_to_copy = []
current_handler = None
types_with_lifetime = [
"xcb_str_iterator_t", "xcb_xv_image_format_info_iterator_t" ]
link_exceptions = {
"bigreq": "xcb",
"xc_misc": "xcb"
}
_ffi_type_translation = {
'BOOL': 'u8'
}
_rs_type_translation = {
'BOOL': 'bool'
}
_rs_typedef_exceptions = [
'xproto::Setup'
]
def rs_open(module):
global _ns
_ns = module.namespace
linklib = "xcb"
if _ns.is_ext:
linklib = 'xcb-' + _ns.header
_ext_names[_ns.ext_name.lower()] = _ns.header
for (n, h) in module.direct_imports:
if h != 'xproto':
_ext_names[n.lower()] = h
if _ns.header in link_exceptions:
linklib = link_exceptions[_ns.header]
ext_id_name = _ffi_name(_ns.prefix + ('id',))
_r.section(0)
_f.section(0)
_rf('// Generated automatically from %s by rs_client.py version %s.',
_ns.file, os.getenv('CARGO_PKG_VERSION', 'undefined'))
_rf('// Do not edit!')
_rf('')
_f('')
_f('#![allow(improper_ctypes)]')
_f('')
_f('use ffi::base::*;')
if _ns.is_ext:
for (n, h) in module.imports:
_f('use ffi::%s::*;', _module_name(n))
_f('')
_f('use libc::{c_char, c_int, c_uint, c_void};')
_f('use std;')
_f('')
_f.section(1)
_f('')
_f('')
_f('#[link(name="%s")]', linklib)
_f('extern {')
_f.indent()
if _ns.is_ext:
_f('')
_f('pub static mut %s: xcb_extension_t;', ext_id_name)
_r('#![allow(unused_unsafe)]')
_r('')
_r('use base;')
if _ns.is_ext:
for (n, h) in module.imports:
_r('use %s;', _module_name(n))
_r('use ffi::base::*;')
_r('use ffi::%s::*;', _module_name(_ns.ext_name))
if _ns.is_ext:
for (n, h) in module.imports:
_r('use ffi::%s::*;', _module_name(n))
_r('use libc::{self, c_char, c_int, c_uint, c_void};')
_r('use std;')
_r('use std::iter::Iterator;')
_r('')
if _ns.is_ext:
_r('')
_r("pub fn id() -> &'static mut base::Extension {")
_r(' unsafe {')
_r(' &mut %s', ext_id_name)
_r(' }')
_r('}')
_r.section(1)
_r('')
_r('')
if _ns.is_ext:
_f.section(0)
_f('')
_f('pub const %s: u32 = %s;',
_ffi_const_name(('xcb', _ns.ext_name, 'major', 'version')),
_ns.major_version)
_f('pub const %s: u32 = %s;',
_ffi_const_name(('xcb', _ns.ext_name, 'minor', 'version')),
_ns.minor_version)
_r.section(0)
_r('')
_r('pub const MAJOR_VERSION: u32 = %s;', _ns.major_version)
_r('pub const MINOR_VERSION: u32 = %s;', _ns.minor_version)
EnumCodegen.build_collision_table(module)
def rs_close(module):
_f.section(1)
_f('')
_f.unindent()
_f('} // extern')
_f.writeout(os.path.join(module.rs_srcdir, "ffi", "%s.rs" % _module_name(_ns.ext_name)))
_r.writeout(os.path.join(module.rs_srcdir, "%s.rs" % _module_name(_ns.ext_name)))
_cname_re = re.compile('([A-Z0-9][a-z]+|[A-Z0-9]+(?![a-z])|[a-z]+)')
_rs_keywords = ['type', 'str', 'match', 'new']
def _tit_split(string):
split = _cname_re.finditer(string)
name_parts = [match.group(0) for match in split]
return '_'.join(name_parts)
def _tit_cap(string):
split = _cname_re.finditer(string)
name_parts = [match.group(0) for match in split]
name_parts = [i[0].upper() + i[1:].lower() for i in name_parts]
return ''.join(name_parts)
_extension_special_cases = ['XPrint', 'XCMisc', 'BigRequests']
def _module_name(name):
if len(name):
if name in _extension_special_cases:
return _tit_split(name).lower()
else:
return name.lower()
else:
return 'xproto'
def _symbol(string):
if string in _rs_keywords:
string += '_'
return string
def _upper_1st(string):
if len(string) == 0:
return ''
if len(string) == 1:
return string.upper()
return string[0].upper() + string[1:]
def _upper_name(nametup):
return '_'.join(tuple(_tit_split(name) for name in nametup)).upper()
def _cap_name(nametup):
return ''.join(tuple(_upper_1st(name) for name in nametup))
def _lower_name(nametup):
return '_'.join(tuple(_tit_split(name) for name in nametup)).lower()
def _ext_nametup(nametup):
if len(nametup) > 2 and nametup[1].lower() in _ext_names:
nametup = tuple(_module_name(name) if i == 1 else name
for (i, name) in enumerate(nametup))
return nametup
def _ffi_type_name(nametup):
if len(nametup) == 1:
if nametup[0] in _ffi_type_translation:
return _ffi_type_translation[nametup[0]]
return nametup[0]
return _ffi_name(nametup + ('t',))
def _ffi_name(nametup):
secondIsExt = (len(nametup) > 2 and nametup[1].lower() in _ext_names)
nametup = _ext_nametup(nametup)
if secondIsExt:
return '_'.join(tuple(name if i==1 else _tit_split(name)
for (i, name) in enumerate(nametup))).lower()
else:
return '_'.join(tuple(_tit_split(name) for name in nametup)).lower()
def _ffi_const_name(nametup):
return _ffi_name(_ext_nametup(nametup)).upper()
def _rs_extract_module(nametup):
if len(nametup) == 1:
return ("", nametup[0])
if nametup[0].lower() == 'xcb':
nametup = nametup[1:]
module = ''
if nametup[0].lower() in _ext_names:
ext = _ext_names[nametup[0].lower()]
if (not _ns.is_ext or
ext != _ns.header):
module = ext + '::'
nametup = nametup[1:]
else:
if _ns.is_ext:
module = 'xproto::'
return (module, nametup)
def _rs_type_name(nametup):
if len(nametup) == 1:
if nametup[0] in _rs_type_translation:
return _rs_type_translation[nametup[0]]
return nametup[0]
(module, nametup) = _rs_extract_module(nametup)
return module + ''.join([_tit_cap(n) for n in nametup])
def _rs_name(nametup):
(module, nametup) = _rs_extract_module(nametup)
return module + '_'.join([_tit_split(n) for n in nametup]).lower()
def _rs_const_name(nametup):
return _upper_name(_rs_extract_module(nametup)[1])
def _rs_field_name(string):
res = ''
for c in string:
if c.isupper():
res = res + '_' + c.lower()
else:
res = res + c
return res
def _set_type_lifetime(typeobj, has_lifetime):
typeobj.has_lifetime = has_lifetime
def ensure_in(val):
if not val in types_with_lifetime:
types_with_lifetime.append(val)
def ensure_out(val):
while val in types_with_lifetime:
types_with_lifetime.remove(val)
if has_lifetime:
ensure_in(typeobj.ffi_iterator_type)
ensure_in(typeobj.rs_type)
ensure_in(typeobj.rs_iterator_type)
else:
ensure_out(typeobj.ffi_iterator_type)
ensure_out(typeobj.rs_type)
ensure_out(typeobj.rs_iterator_type)
def _ffi_type_setup(typeobj, nametup, suffix=()):
typeobj.ffi_type = _ffi_type_name(nametup + suffix)
typeobj.ffi_iterator_type = _ffi_type_name(nametup + ('iterator',))
typeobj.ffi_next_fn = _ffi_name(nametup + ('next',))
typeobj.ffi_end_fn = _ffi_name(nametup + ('end',))
typeobj.ffi_request_fn = _ffi_name(nametup)
typeobj.ffi_checked_fn = _ffi_name(nametup + ('checked',))
typeobj.ffi_unchecked_fn = _ffi_name(nametup + ('unchecked',))
typeobj.ffi_reply_fn = _ffi_name(nametup + ('reply',))
typeobj.ffi_reply_type = _ffi_type_name(nametup + ('reply',))
typeobj.ffi_cookie_type = _ffi_type_name(nametup + ('cookie',))
typeobj.ffi_reply_fds_fn = _ffi_name(nametup + ('reply_fds',))
typeobj.ffi_need_aux = False
typeobj.ffi_need_serialize = False
typeobj.ffi_need_sizeof = False
typeobj.ffi_aux_fn = _ffi_name(nametup + ('aux',))
typeobj.ffi_aux_checked_fn = _ffi_name(nametup + ('aux', 'checked'))
typeobj.ffi_aux_unchecked_fn = _ffi_name(nametup + ('aux', 'unchecked'))
typeobj.ffi_serialize_fn = _ffi_name(nametup + ('serialize',))
typeobj.ffi_unserialize_fn = _ffi_name(nametup + ('unserialize',))
typeobj.ffi_unpack_fn = _ffi_name(nametup + ('unpack',))
typeobj.ffi_sizeof_fn = _ffi_name(nametup + ('sizeof',))
typeobj.ffi_var_followed_by_fixed_fields = False
if not typeobj.fixed_size():
if not typeobj in _types_uneligible_to_copy:
_types_uneligible_to_copy.append(typeobj)
if hasattr(typeobj, 'parents'):
for p in typeobj.parents:
_types_uneligible_to_copy.append(p)
if typeobj.is_container:
prev_varsized_field = None
prev_varsized_offset = 0
first_field_after_varsized = None
for field in typeobj.fields:
_ffi_type_setup(field.type, field.field_type, ())
if field.type.is_list:
_ffi_type_setup(field.type.member, field.field_type, ())
if (field.type.nmemb is None):
typeobj.ffi_need_sizeof = True
field.ffi_field_type = _ffi_type_name(field.field_type)
field.ffi_field_name = _symbol(field.field_name)
field.has_subscript = (field.type.nmemb and
field.type.nmemb > 1)
field.ffi_need_const = (field.type.nmemb != 1)
field.ffi_need_pointer = (field.type.nmemb != 1)
if not field.type.fixed_size():
field.ffi_need_pointer = True
if field.type.is_list and not field.type.member.fixed_size():
field.ffi_need_pointer = True
if field.type.is_switch:
field.ffi_need_const = True
field.ffi_need_pointer = True
field.ffi_need_aux = True
elif not field.type.fixed_size() and not field.type.is_bitcase:
typeobj.ffi_need_sizeof = True
field.ffi_iterator_type = _ffi_type_name(
field.field_type + ('iterator',))
field.ffi_iterator_fn = _ffi_name(
nametup + (field.field_name, 'iterator'))
field.ffi_accessor_fn = _ffi_name(
nametup + (field.field_name,))
field.ffi_length_fn = _ffi_name(
nametup + (field.field_name, 'length'))
field.ffi_end_fn = _ffi_name(
nametup + (field.field_name, 'end'))
field.prev_varsized_field = prev_varsized_field
field.prev_varsized_offset = prev_varsized_offset
if prev_varsized_offset == 0:
first_field_after_varsized = field
field.first_field_after_varsized = first_field_after_varsized
if field.type.fixed_size():
prev_varsized_offset += field.type.size
if (prev_varsized_field is not None and
not field.type.is_pad and field.wire):
if not typeobj.is_union:
typeobj.ffi_need_serialize = True
typeobj.ffi_var_followed_by_fixed_fields = True
else:
typeobj.last_varsized_field = field
prev_varsized_field = field
prev_varsized_offset = 0
if typeobj.ffi_var_followed_by_fixed_fields:
if field.type.fixed_size():
field.prev_varsized_field = None
if typeobj.ffi_need_serialize:
typeobj.ffi_need_sizeof = True
if not typeobj.is_bitcase:
if typeobj.ffi_need_serialize:
if typeobj.ffi_serialize_fn not in finished_serializers:
finished_serializers.append(typeobj.ffi_serialize_fn)
if (typeobj.is_switch or
typeobj.ffi_var_followed_by_fixed_fields):
pass
if typeobj.ffi_need_sizeof:
if typeobj.ffi_sizeof_fn not in finished_sizeof:
if not _ns.is_ext or typeobj.name[:2] == _ns.prefix:
finished_sizeof.append(typeobj.ffi_sizeof_fn)
def _ffi_bitcase_name(switch, bitcase):
assert switch.is_switch and bitcase.type.has_name
switch_name = _lower_name(_ext_nametup(switch.name))
return '_%s__%s' % (switch_name, bitcase.ffi_field_name)
def _ffi_struct(typeobj, must_pack=False):
struct_fields = []
for field in typeobj.fields:
if (not field.type.fixed_size()
and not typeobj.is_switch
and not typeobj.is_union):
continue
if field.wire:
struct_fields.append(field)
_f.section(0)
_f('')
_write_doc_brief_desc(_f, typeobj.doc)
_f('#[repr(C%s)]', ', packed' if must_pack else '')
_f('pub struct %s {', typeobj.ffi_type)
_f.indent()
maxfieldlen = 0
if not typeobj.is_switch:
for field in typeobj.fields:
maxfieldlen = max(maxfieldlen, len(field.ffi_field_name))
else:
for b in typeobj.bitcases:
if b.type.has_name:
maxfieldlen = max(maxfieldlen, len(b.ffi_field_name))
else:
for field in b.type.fields:
maxfieldlen = max(maxfieldlen, len(field.ffi_field_name))
def _ffi_struct_field(field):
ftype = field.ffi_field_type
space = ' '* (maxfieldlen - len(field.ffi_field_name))
if (field.type.fixed_size() or typeobj.is_union or
(typeobj.is_switch and field.type.is_switch)):
if field.has_subscript:
ftype = '[%s; %d]' % (ftype, field.type.nmemb)
_f('pub %s: %s%s,', field.ffi_field_name, space, ftype)
else:
assert not field.has_subscript
_f('pub %s: %s*mut %s,', field.ffi_field_name, space, ftype)
named_bitcases = []
if not typeobj.is_switch:
for field in struct_fields:
for d in typeobj.doc.fields[field.field_name]:
_f('/// %s', d)
_ffi_struct_field(field)
else:
for b in typeobj.bitcases:
if b.type.has_name:
named_bitcases.append(b)
space = ' ' * (maxfieldlen - len(b.ffi_field_name))
_f('pub %s: %s%s,', b.ffi_field_name, space,
_ffi_bitcase_name(typeobj, b))
else:
for field in b.type.fields:
_ffi_struct_field(field)
_f.unindent()
_f('}')
if not typeobj in _types_uneligible_to_copy:
_f('')
_f('impl Copy for %s {}', typeobj.ffi_type)
_f('impl Clone for %s {', typeobj.ffi_type)
_f(' fn clone(&self) -> %s { *self }', typeobj.ffi_type)
_f('}')
for b in named_bitcases:
_f('')
_f('#[repr(C)]')
_f('pub struct %s {', _ffi_bitcase_name(typeobj, b))
_f.indent()
maxfieldlen = 0
for field in b.type.fields:
maxfieldlen = max(maxfieldlen, len(field.ffi_field_name))
for field in b.type.fields:
_ffi_struct_field(field)
_f.unindent()
_f('}')
def _ffi_accessors_list(typeobj, field):
list = field.type
ffi_type = typeobj.ffi_type
switch_obj = typeobj if typeobj.is_switch else None
if typeobj.is_bitcase:
switch_obj = typeobj.parents[-1]
if switch_obj is not None:
ffi_type = switch_obj.ffi_type
params = []
parents = typeobj.parents if hasattr(typeobj, 'parents') else [typeobj]
params.append(('R: *const %s' % parents[0].ffi_type, parents[0]))
R_obj = parents[0]
if switch_obj is not None:
toplevel_switch = parents[1]
params.append(('S: *const %s' % toplevel_switch.ffi_type,
toplevel_switch))
S_obj = parents[1]
_f.section(1)
if list.member.fixed_size():
idx = 1 if switch_obj is not None else 0
_f('')
_f('pub fn %s (%s)', field.ffi_accessor_fn, params[idx][0])
_f(' -> *mut %s;', field.ffi_field_type)
def _may_switch_fn(fn_name, return_type):
_f('')
has_lifetime = return_type in types_with_lifetime
lifetime = "<'a>" if has_lifetime else ""
if switch_obj is not None:
fn_start = 'pub fn %s%s (' % (fn_name, lifetime)
spacing = ' '*len(fn_start)
_f('%sR: *const %s,', fn_start, R_obj.ffi_type)
_f('%sS: *const %s)', spacing, S_obj.ffi_type)
_f(' -> %s%s;', return_type, lifetime)
else:
_f('pub fn %s%s (R: *const %s)', fn_name, lifetime, ffi_type)
_f(' -> %s%s;', return_type, lifetime)
_may_switch_fn(field.ffi_length_fn, 'c_int')
if field.type.member.is_simple:
_may_switch_fn(field.ffi_end_fn, 'xcb_generic_iterator_t')
else:
_may_switch_fn(field.ffi_iterator_fn, field.ffi_iterator_type)
def _ffi_accessors_field(typeobj, field):
ffi_type = typeobj.ffi_type
switch_obj = typeobj if typeobj.is_switch else None
if typeobj.is_bitcase:
switch_obj = typeobj.parents[-1]
if switch_obj is not None:
ffi_type = switch_obj.ffi_type
_f.section(1)
if field.type.is_simple:
_f('')
_f('pub fn %s (R: *const %s)', field.ffi_accessor_fn, ffi_type)
_f(' -> %s;', field.ffi_field_type)
else:
if field.type.is_switch and switch_obj is None:
return_type = '*mut c_void'
else:
return_type = '*mut %s' % field.ffi_field_type
_f('')
_f('pub fn %s (R: *const %s)', field.ffi_accessor_fn, ffi_type)
_f(' -> %s;', return_type)
def _ffi_accessors(typeobj, nametup):
for field in typeobj.fields:
if not field.type.is_pad:
if field.type.is_list and not field.type.fixed_size():
_ffi_accessors_list(typeobj, field)
elif (field.prev_varsized_field is not None
or not field.type.fixed_size()):
_ffi_accessors_field(typeobj, field)
def _ffi_iterator(typeobj, nametup):
has_lifetime = typeobj.ffi_iterator_type in types_with_lifetime
lifetime = "<'a>" if has_lifetime else ""
_f.section(0)
_f('')
_f('#[repr(C)]')
_f("pub struct %s%s {", typeobj.ffi_iterator_type, lifetime)
_f(' pub data: *mut %s,', typeobj.ffi_type)
_f(' pub rem: c_int,')
_f(' pub index: c_int,')
if has_lifetime:
_f(" _phantom: std::marker::PhantomData<&'a %s>,", typeobj.ffi_type)
_f('}')
_f.section(1)
_f('')
_f('pub fn %s (i: *mut %s);', typeobj.ffi_next_fn,
typeobj.ffi_iterator_type)
_f('')
_f('pub fn %s (i: *mut %s)', typeobj.ffi_end_fn,
typeobj.ffi_iterator_type)
_f(' -> xcb_generic_iterator_t;')
def _ffi_reply(request):
_f.section(1)
_f('')
_f('/// the returned value must be freed by the caller using ' +
'libc::free().')
fn_start = 'pub fn %s (' % request.ffi_reply_fn
spacing = ' ' * len(fn_start)
_f('%sc: *mut xcb_connection_t,', fn_start)
_f('%scookie: %s,', spacing, request.ffi_cookie_type)
_f('%serror: *mut *mut xcb_generic_error_t)', spacing)
_f(' -> *mut %s;', request.ffi_reply_type)
def _ffi_reply_has_fds(self):
for field in self.fields:
if field.isfd:
return True
return False
def _ffi_reply_fds(request, name):
_f.section(1)
_f('')
_f('/// the returned value must be freed by the caller using ' +
'libc::free().')
fn_start = 'pub fn %s (' % request.ffi_reply_fds_fn
spacing = ' ' * len(fn_start)
_f('%sc: *mut xcb_connection_t,', fn_start)
_f('%sreply: *mut %s)', spacing, request.ffi_reply_type)
_f(' -> *mut c_int;')
def _rs_type_setup(typeobj, nametup, suffix=()):
typeobj.rs_type = _rs_type_name(nametup + suffix)
if len(nametup) == 1:
typeobj.rs_qualified_type = typeobj.rs_type
else:
module = _ns.ext_name.lower() if _ns.is_ext else 'xproto'
typeobj.rs_qualified_type = '%s::%s' % (module, typeobj.rs_type)
typeobj.rs_iterator_type = _rs_type_name(nametup+('iterator',))
typeobj.rs_request_fn = _rs_name(nametup)
typeobj.rs_checked_fn = _rs_name(nametup+('checked',))
typeobj.rs_unchecked_fn = _rs_name(nametup+('unchecked',))
typeobj.rs_aux_fn = _rs_name(nametup+('aux',))
typeobj.rs_aux_checked_fn = _rs_name(nametup+('aux', 'checked'))
typeobj.rs_aux_unchecked_fn = _rs_name(nametup+('aux', 'unchecked'))
typeobj.rs_reply_type = _rs_type_name(nametup + ('reply',))
typeobj.rs_cookie_type = _rs_type_name(nametup + ('cookie',))
typeobj.rs_is_pod = False
if typeobj.is_container:
has_complex = False
for field in typeobj.fields:
_rs_type_setup(field.type, field.field_type)
if field.type.is_list:
_rs_type_setup(field.type.member, field.field_type)
field.rs_field_name = _symbol(_rs_field_name(field.field_name))
field.rs_field_type = _rs_type_name(field.field_type)
field.rs_iterator_type = _rs_type_name(
field.field_type + ('iterator',))
if not field.type.is_simple and not field.type.rs_is_pod \
and not field.type.is_pad:
has_complex = True
typeobj.rs_only_has_simple = not has_complex
typeobj.rs_is_pod = (
(not has_complex) and
(not typeobj.rs_qualified_type in _rs_typedef_exceptions) and
(not typeobj.is_reply and not typeobj.is_union) and
(not typeobj.is_switch))
if typeobj.rs_is_pod:
_set_type_lifetime(typeobj, False)
def _rs_struct(typeobj):
_r.section(1)
_r('')
_write_doc_brief_desc(_r, typeobj.doc)
if typeobj.rs_is_pod:
_r('#[derive(Copy, Clone)]')
_r('pub struct %s {', typeobj.rs_type)
_r(' pub base: %s,', typeobj.ffi_type)
_r('}')
else:
has_lifetime = typeobj.rs_type in types_with_lifetime
lifetime1 = "<'a>" if has_lifetime else ""
lifetime2 = "'a, " if has_lifetime else ""
_r("pub type %s%s = base::StructPtr<%s%s>;", typeobj.rs_type, lifetime1,
lifetime2, typeobj.ffi_type)
def _rs_accessors(typeobj):
has_lifetime = typeobj.rs_type in types_with_lifetime
lifetime = "<'a>" if has_lifetime else ""
_r.section(1)
_r('')
_r('impl%s %s%s {', lifetime, typeobj.rs_type, lifetime)
with _r.indent_block():
if typeobj.rs_is_pod:
fnstart = 'pub fn new('
fnspace = ' '*len(fnstart)
argfields = []
for f in typeobj.fields:
if not f.type.is_pad:
argfields.append(f)
maxfieldlen = 0
for f in typeobj.fields:
maxfieldlen = max(maxfieldlen, len(f.rs_field_name))
if len(argfields):
eol = ',' if len(argfields) > 1 else ')'
f1 = argfields[0]
space1 = ' '*(maxfieldlen - len(f1.rs_field_name))
_r('#[allow(unused_unsafe)]')
_r('%s%s: %s%s%s', fnstart, f1.rs_field_name, space1, f1.rs_field_type, eol)
for (i, f) in enumerate(argfields[1:]):
argspace = ' '*(maxfieldlen-len(f.rs_field_name))
eol = ',' if i < len(argfields)-2 else ')'
_r('%s%s: %s%s%s', fnspace, f.rs_field_name, argspace, f.rs_field_type, eol)
_r(' -> %s {', typeobj.rs_type)
else:
_r('#[allow(unused_unsafe)]')
_r('%s) -> %s {', fnstart, typeobj.rs_type)
with _r.indent_block():
_r('unsafe {')
with _r.indent_block():
_r('%s {', typeobj.rs_type)
with _r.indent_block():
_r('base: %s {', typeobj.ffi_type)
with _r.indent_block():
for f in typeobj.fields:
space = ' '*(maxfieldlen-len(f.rs_field_name))
if f.type.rs_is_pod:
_r('%s: %sstd::mem::transmute(%s),', f.rs_field_name, space, f.rs_field_name)
elif f.type.is_pad:
fval = '0'
if f.has_subscript:
fval = '[0; %d]' % f.type.nmemb
_r('%s: %s%s,', f.rs_field_name, space, fval)
else:
assignment = f.rs_field_name
if f.rs_field_type == 'bool':
assignment = 'if %s { 1 } else { 0 }' % f.rs_field_name
_r('%s: %s%s,', f.ffi_field_name, space, assignment)
_r('}')
_r('}')
_r('}')
_r('}')
for (i, field) in enumerate(typeobj.fields):
if field.visible and not field.type.is_switch:
for d in typeobj.doc.fields[field.field_name]:
_r('/// %s', d)
if typeobj.is_union:
_rs_union_accessor(typeobj, field)
else:
_rs_accessor(typeobj, field)
_r('}')
def _rs_reply_accessors(reply):
has_lifetime = reply.rs_type in types_with_lifetime
lifetime = "<'a>" if has_lifetime else ""
fd_field = None
nfd_field = None
for f in reply.fields:
if f.rs_field_name == 'nfd':
nfd_field = f
if f.isfd:
fd_field = f
reply_fields = []
for f in reply.fields:
if f.rs_field_name == 'nfd':
if not fd_field or not nfd_field:
reply_fields.append(f)
elif not f.isfd:
reply_fields.append(f)
_r.section(1)
_r('')
_r('impl%s %s%s {', lifetime, reply.rs_type, lifetime)
with _r.indent_block():
for field in reply_fields:
if field.visible and not field.type.is_switch:
_rs_accessor(reply, field)
if nfd_field and fd_field:
getter = reply.request.ffi_reply_fds_fn
fname = fd_field.rs_field_name
if not fname.endswith('s'):
fname += 's'
_r('pub fn %s(&self, c: &base::Connection) -> &[i32] {', fname)
with _r.indent_block():
_r('unsafe {')
with _r.indent_block():
_r('let nfd = (*self.ptr).nfd as usize;')
_r('let ptr = %s(c.get_raw_conn(), self.ptr);', getter)
_r('')
_r('std::slice::from_raw_parts(ptr, nfd)')
_r('}')
_r('}')
_r('}')
def _rs_union_accessor(typeobj, field):
if field.type.is_simple or field.type.rs_is_pod:
_r('pub fn %s(&self) -> %s {', field.rs_field_name, field.rs_field_type)
with _r.indent_block():
_r('unsafe {')
with _r.indent_block():
convert = ''
if field.rs_field_type == 'bool':
convert = ' != 0'
_r('let _ptr = self.data.as_ptr() as *const %s;', field.rs_field_type)
_r('*_ptr%s', convert)
_r('}')
_r('}')
_r('pub fn from_%s(%s: %s) -> %s {', field.rs_field_name,
field.rs_field_name, field.rs_field_type, typeobj.rs_type)
with _r.indent_block():
_r('unsafe {')
with _r.indent_block():
if field.rs_field_type == 'bool':
_r('let %s: %s = %s != 0;', field.rs_field_name,
field.ffi_field_type, field.rs_field_name)
_r('let mut res = %s { data: [0; %d] };', typeobj.rs_type,
typeobj.union_num_bytes)
_r('let res_ptr = res.data.as_mut_ptr() as *mut %s;', field.rs_field_type)
_r('*res_ptr = %s;', field.rs_field_name)
_r('res')
_r('}')
_r('}')
elif field.type.is_list and field.type.fixed_size():
assert (typeobj.union_num_bytes % field.type.size) == 0
_r('pub fn %s(&self) -> &[%s] {',
field.rs_field_name, field.rs_field_type)
with _r.indent_block():
_r('unsafe {')
with _r.indent_block():
_r('let ptr = self.data.as_ptr() as *const %s;', field.rs_field_type)
_r('std::slice::from_raw_parts(ptr, %d)',
typeobj.union_num_bytes / field.type.size)
_r('}')
_r('}')
_r('pub fn from_%s(%s: [%s; %d]) -> %s {', field.rs_field_name,
field.rs_field_name, field.rs_field_type,
typeobj.union_num_bytes / field.type.size,
typeobj.rs_type)
with _r.indent_block():
_r('unsafe {')
with _r.indent_block():
_r('%s { data: std::mem::transmute(%s) }', typeobj.rs_type,
field.rs_field_name)
_r('}')
_r('}')
elif field.type.is_container:
if not field.type.rs_is_pod:
_r('pub fn %s<\'a>(&\'a self) -> %s<\'a> {',
field.rs_field_name, field.rs_field_type)
else:
_r('pub fn %s(&self) -> %s {', field.rs_field_name, field.rs_field_type)
with _r.indent_block():
_r('unsafe {')
with _r.indent_block():
if not field.type.rs_is_pod:
_r('std::mem::transmute(self)')
else:
_r('let _ptr = self.data.as_ptr() as *const %s;', field.rs_field_type)
_r('*_ptr')
_r('}')
_r('}')
def _rs_accessor(typeobj, field, disable_pod_acc=False):
if field.type.is_simple or field.type.rs_is_pod:
_r('pub fn %s(&self) -> %s {', field.rs_field_name,
field.rs_field_type)
acc = '(*self.ptr)'
if typeobj.rs_is_pod and not disable_pod_acc:
acc = 'self.base'
with _r.indent_block():
convert = ''
if field.rs_field_type == 'bool':
convert = ' != 0'
_r('unsafe {')
with _r.indent_block():
if field.type.rs_is_pod:
_r('std::mem::transmute(%s.%s)', acc, field.ffi_field_name)
else:
_r('%s.%s%s', acc, field.ffi_field_name, convert)
_r('}')
_r('}')
elif field.type.is_union:
has_lifetime = typeobj.rs_type in types_with_lifetime
lifetime = "<'a>" if not has_lifetime else ""
_r("pub fn %s%s(&'a self) -> &'a %s {", field.rs_field_name, lifetime,
field.rs_field_type)
with _r.indent_block():
_r('unsafe {')
with _r.indent_block():
_r('&(*self.ptr).%s', field.ffi_field_name)
_r('}')
_r('}')
elif field.type.is_list and not field.type.fixed_size():
if field.type.member.rs_type == 'bool':
_r('pub fn %s(&self) -> Vec<bool> {', field.rs_field_name)
with _r.indent_block():
_r('unsafe {')
with _r.indent_block():
_r('let field = self.ptr;')
_r('let len = %s(field);', field.ffi_length_fn)
_r('let data = %s(field);', field.ffi_accessor_fn)
_r('let slice = std::slice::from_raw_parts(data, len as usize);')
_r('slice.iter().map(|el| if *el == 0 {false} else{true}).collect()')
_r('}')
_r('}')
elif field.type.member.is_simple:
field_type = field.type.member.rs_type
is_template = False
if field_type == 'c_char':
return_type = '&str'
elif field_type == 'c_void':
is_template = True
return_type = '&[T]'
else:
return_type = '&[%s]' % field_type
_r('pub fn %s%s(&self) -> %s {', field.rs_field_name,
'<T>' if is_template else '', return_type)
with _r.indent_block():
_r('unsafe {')
with _r.indent_block():
_r('let field = self.ptr;')
_r('let len = %s(field) as usize;', field.ffi_length_fn)
_r('let data = %s(field);', field.ffi_accessor_fn)
if field_type == 'c_char':
_r('let slice = ' +
'std::slice::from_raw_parts(' +
'data as *const u8, len);')
_r('// should we check what comes from X?')
_r('std::str::from_utf8_unchecked(&slice)')
elif is_template:
_r('debug_assert_eq!(len %% std::mem::size_of::<T>(), 0);')
_r('std::slice::from_raw_parts(data as *const T, ' +
'len / std::mem::size_of::<T>())')
else:
_r('std::slice::from_raw_parts(data, len)')
_r('}')
_r('}')
else:
lifetime = ""
if field.rs_iterator_type in types_with_lifetime and \
typeobj.rs_type in types_with_lifetime:
lifetime = "<'a>"
_r('pub fn %s(&self) -> %s%s {',
field.rs_field_name, field.rs_iterator_type, lifetime)
with _r.indent_block():
_r('unsafe {')
with _r.indent_block():
_r('%s(self.ptr)', field.ffi_iterator_fn)
_r('}')
_r('}')
pass
elif field.type.is_list:
_r('pub fn %s(&self) -> &[%s] {',
field.rs_field_name, field.rs_field_type)
with _r.indent_block():
_r('unsafe {')
with _r.indent_block():
_r('&(*self.ptr).%s', field.ffi_field_name)
_r('}')
_r('}')
elif field.type.is_container:
_r('pub fn %s(&self) -> %s {',
field.rs_field_name, field.rs_field_type)
with _r.indent_block():
_r('unsafe {')
with _r.indent_block():
_r('std::mem::transmute(&(*self.ptr).%s)',
field.ffi_field_name)
_r('}')
_r('}')
elif not field.type.is_pad:
raise Exception('did not treat accessor %s.%s'
% (typeobj.ffi_type, field.ffi_field_name))
def _rs_iterator(typeobj):
has_lifetime = typeobj.rs_iterator_type in types_with_lifetime
lifetime1 = "<'a>" if has_lifetime else ""
lifetime2 = "'a, " if has_lifetime else ""
return_expr = '*data'
if typeobj.rs_is_pod:
return_expr = 'std::mem::transmute(*data)'
elif typeobj.is_container and not typeobj.is_union:
return_expr = 'std::mem::transmute(data)'
_r.section(1)
_r('')
_r("pub type %s%s = %s%s;",
typeobj.rs_iterator_type, lifetime1, typeobj.ffi_iterator_type, lifetime1)
_r('')
_r("impl%s Iterator for %s%s {", lifetime1, typeobj.rs_iterator_type, lifetime1)
_r(" type Item = %s%s;", typeobj.rs_type, lifetime1)
_r(" fn next(&mut self) -> std::option::Option<%s%s> {",
typeobj.rs_type, lifetime1)
_r(' if self.rem == 0 { None }')
_r(' else {')
_r(' unsafe {')
_r(' let iter = self as *mut %s;',
typeobj.ffi_iterator_type)
_r(' let data = (*iter).data;')
_r(' %s(iter);', typeobj.ffi_next_fn)
_r(' Some(%s)', return_expr)
_r(' }')
_r(' }')
_r(' }')
_r('}')
def _rs_reply(request):
_r.section(1)
_r('')
_r('pub type %s = base::Reply<%s>;', request.rs_reply_type, request.ffi_reply_type);
def _prepare_doc(typeobj):
def rework_phrase(phrase):
return phrase
if hasattr(typeobj, "doc_prepared"):
assert typeobj.doc_prepared == True
return
if hasattr(typeobj, "doc") and typeobj.doc:
if typeobj.doc.brief:
typeobj.doc.brief = [rework_phrase(p) for p in typeobj.doc.brief.split('\n')]
else:
typeobj.doc.brief = []
if typeobj.doc.description:
typeobj.doc.description = [rework_phrase(p) for p in typeobj.doc.description.split('\n')]
else:
typeobj.doc.description = []
if hasattr(typeobj, "fields"):
if not hasattr(typeobj.doc, "fields"):
typeobj.doc.fields = {}
for f in typeobj.fields:
if f.field_name in typeobj.doc.fields:
typeobj.doc.fields[f.field_name] = \
[rework_phrase(p) for p in typeobj.doc.fields[f.field_name].split('\n')]
else:
typeobj.doc.fields[f.field_name] = []
else:
class Doc(object): pass
typeobj.doc = Doc()
typeobj.doc.brief = []
typeobj.doc.description = []
typeobj.doc.fields = {}
if hasattr(typeobj, "fields"):
for f in typeobj.fields:
typeobj.doc.fields[f.field_name] = []
typeobj.doc_prepared = True
def _write_docs(sf, doclist):
for s in doclist:
sf('/// %s', s)
def _write_doc_brief_desc(sf, doc):
_write_docs(sf, doc.brief)
if len(doc.brief) and len(doc.description):
sf('///')
_write_docs(sf, doc.description)
class EnumCodegen(object):
namecount = {}
def build_collision_table(module):
for v in module.types.values():
key = _ffi_type_name(v[0])
EnumCodegen.namecount[key] = (
(EnumCodegen.namecount.get(key) or 0) + 1
)
def __init__(self, nametup, doc):
self._nametup = nametup
self._doc = doc
self.done_vals = {}
self.unique_discriminants = []
self.conflicts = []
self.all_discriminants = []
key = _ffi_type_name(nametup)
if EnumCodegen.namecount[key] > 1:
nametup = nametup + ('enum',)
self.ffi_name = _ffi_type_name(nametup)
self.rs_name = _rs_type_name(nametup)
def add_discriminant(self, name, val):
class Discriminant: pass
d = Discriminant()
d.rs_name = _rs_const_name(self._nametup+(name,))
d.ffi_name = _ffi_const_name(self._nametup+(name,))
d.valstr = '0x%02x' % val
d.val = val
d.doc = None
if self._doc and name in self._doc.fields:
d.doc = self._doc.fields[name]
self.all_discriminants.append(d)
if val in self.done_vals:
self.conflicts.append(d)
else:
self.done_vals[val] = d
self.unique_discriminants.append(d)
def maxlen(self, name_field):
maxnamelen = 0
maxvallen = 0
for d in self.unique_discriminants:
maxvallen = max(maxvallen, len(d.valstr))
maxnamelen = max(maxnamelen, len(getattr(d, name_field)))
return (maxnamelen, maxvallen)
def write_ffi(self):
(maxnamelen, maxvallen) = self.maxlen('ffi_name')
type_name = self.ffi_name
_f.section(0)
_f('')
_write_doc_brief_desc(_f, self._doc)
_f('pub type %s = u32;', type_name)
for d in self.all_discriminants:
d_name = d.ffi_name
namespace = ' ' * (maxnamelen-len(d_name))
valspace = ' ' * (maxvallen-len(d.valstr))
if d.doc:
ddocs = d.doc.split('\n')
for dd in ddocs:
_f('/// %s', dd)
_f('pub const %s%s: %s =%s %s;', d_name, namespace, type_name,
valspace, d.valstr)
def write_rs(self):
(maxnamelen, maxvallen) = self.maxlen("rs_name")
_r.section(0)
_r('')
_write_doc_brief_desc(_r, self._doc)
_r('pub type %s = u32;', self.rs_name)
for d in self.all_discriminants:
namespace = ' ' * (maxnamelen-len(d.rs_name))
valspace = ' ' * (maxvallen-len(d.valstr))
if d.doc:
ddocs = d.doc.split('\n')
for dd in ddocs:
_r('/// %s', dd)
_r('pub const %s%s: %s =%s %s;', d.rs_name, namespace, self.rs_name,
valspace, d.valstr)
class RequestCodegen(object):
def __init__(self, request):
self.request = request
self.void = False if self.request.reply else True
self.ffi_cookie_type = ('xcb_void_cookie_t' if self.void
else self.request.ffi_cookie_type)
self.rs_cookie_type = ('base::VoidCookie' if self.void
else self.request.rs_cookie_type)
self.visible_fields = []
for field in self.request.fields:
if field.visible:
self.visible_fields.append(field)
self.ffi_params = []
for field in self.visible_fields:
self.ffi_params.append(field)
rs_num_template = 0
template_letters = ['T', 'U', 'V', 'W']
self.rs_send_event = False
if _ns.header == "xproto" and \
self.request.rs_request_fn.startswith("send_event"):
self.rs_send_event = True
for f in self.visible_fields:
f.rs_is_slice = False
f.rs_template_let = ''
f.rs_lenfield = None
f.rs_is_mask_slice = False
f.rs_maskfield = None
f.rs_skip = False
for (ffi_index, field) in enumerate(self.visible_fields):
field.ffi_index = ffi_index
if self.rs_send_event and field.rs_field_name == "event":
field.rs_template_let = template_letters[rs_num_template]
rs_num_template += 1
elif field.type.is_list:
if field.type.expr.bitfield:
field.rs_is_mask_slice = True
else:
field.rs_is_slice = True
if field.type.member.rs_type == 'c_void':
field.rs_template_let = template_letters[rs_num_template]
rs_num_template += 1
field.rs_lenfield = field.type.expr.lenfield
if not field.rs_lenfield:
len_name = field.type.expr.lenfield_name
for f in self.visible_fields:
if f.field_name == len_name:
field.rs_lenfield = f
if field.rs_is_mask_slice:
assert field.rs_lenfield
if field.rs_lenfield:
field.rs_lenfield.rs_skip = True
self.rs_params = []
for field in self.visible_fields:
if not field.rs_skip:
self.rs_params.append(field)
self.rs_template = "<'a>"
if rs_num_template:
self.rs_template = "<'a"
for i in range(rs_num_template):
self.rs_template += ', ' + template_letters[i]
self.rs_template += '>'
def ffi_func_name(self, regular, aux):
checked = self.void and not regular
unchecked = not self.void and not regular
if checked:
func_name = (self.request.ffi_checked_fn if not aux else
self.request.ffi_aux_checked_fn)
elif unchecked:
func_name = (self.request.ffi_unchecked_fn if not aux else
self.request.ffi_aux_unchecked_fn)
else:
func_name = (self.request.ffi_request_fn if not aux else
self.request.ffi_aux_fn)
return func_name
def rs_func_name(self, regular, aux):
checked = self.void and not regular
unchecked = not self.void and not regular
if checked:
func_name = (self.request.rs_checked_fn if not aux else
self.request.rs_aux_checked_fn)
elif unchecked:
func_name = (self.request.rs_unchecked_fn if not aux else
self.request.rs_aux_unchecked_fn)
else:
func_name = (self.request.rs_request_fn if not aux else
self.request.rs_aux_fn)
return func_name
def ffi_rq_type(self, field, aux):
ffi_rq_type = field.ffi_field_type
if field.ffi_need_pointer:
pointer = '*const ' if field.ffi_need_const else '*mut '
ffi_rq_type = pointer + ffi_rq_type
if field.type.ffi_need_serialize and not aux:
ffi_rq_type = '*const c_void'
return ffi_rq_type
def write_ffi_rs(self, regular, aux=False):
self.write_ffi(regular, aux)
self.write_rs(regular, aux)
def write_ffi(self, regular, aux=False):
ffi_func_name = self.ffi_func_name(regular, aux)
maxnamelen = 1
for p in self.ffi_params:
maxnamelen = max(maxnamelen, len(p.ffi_field_name))
_f.section(1)
_f("")
_write_doc_brief_desc(_f, self.request.doc)
fn_start = "pub fn %s (" % ffi_func_name
func_spacing = ' ' * len(fn_start)
spacing = " " * (maxnamelen-len('c'))
eol = ',' if len(self.ffi_params) else ')'
_f("%sc: %s*mut xcb_connection_t%s", fn_start, spacing, eol)
for (i, p) in enumerate(self.ffi_params):
ffi_rq_type = self.ffi_rq_type(p, aux)
spacing = ' '*(maxnamelen-len(p.ffi_field_name))
eol = ')' if i == (len(self.ffi_params)-1) else ','
_f('%s%s: %s%s%s', func_spacing, p.ffi_field_name, spacing,
ffi_rq_type, eol)
_f(" -> %s;", self.ffi_cookie_type)
def write_rs(self, regular, aux=False):
checked = (self.void and not regular) \
or ((not self.void) and regular)
rs_func_name = self.rs_func_name(regular, aux)
ffi_func_name = self.ffi_func_name(regular, aux)
maxnamelen = len('c')
for p in self.rs_params:
maxnamelen = max(maxnamelen, len(p.rs_field_name))
let_lines = []
call_params = []
_r.section(1)
_r('')
_write_doc_brief_desc(_r, self.request.doc)
doc_params = False
for f in self.rs_params:
if len(self.request.doc.fields[f.field_name]):
doc_params = True
break
if doc_params:
_r('///')
_r('/// parameters:')
_r('///')
_r('/// - __c__:')
_r('/// The connection object to the server')
for f in self.rs_params:
_r('///')
_r('/// - __%s__:', f.field_name)
for fd in self.request.doc.fields[f.field_name]:
_r('/// %s', fd)
fn_start = "pub fn %s%s(" % (rs_func_name, self.rs_template)
func_spacing = ' ' * len(fn_start)
eol = ',' if len(self.rs_params) else ')'
spacing = ' ' * (maxnamelen-len('c'))
_r("%sc%s: &'a base::Connection%s", fn_start, spacing, eol)
for (i, p) in enumerate(self.rs_params):
ffi_rq_type = self.ffi_rq_type(p, aux)
rs_typestr = p.rs_field_type
if self.rs_send_event and p.rs_field_name == "event":
rs_typestr = "&base::Event<%s>" % p.rs_template_let
let_lines.append("let event_ptr = " +
"std::mem::transmute(event.ptr);")
call_params.append((p.ffi_index, "event_ptr"))
pass
elif p.rs_is_mask_slice:
maskfield = p.rs_lenfield
rs_typestr = '&[(%s, %s)]' % (maskfield.rs_field_type,
p.rs_field_type)
let_lines.append('let mut %s_copy = %s.to_vec();' %
(p.rs_field_name, p.rs_field_name))
let_lines.append(('let (%s_mask, %s_vec) = ' +
'base::pack_bitfield(&mut %s_copy);') %
(p.rs_field_name, p.rs_field_name, p.rs_field_name))
let_lines.append("let %s_ptr = %s_vec.as_ptr();" %
(p.rs_field_name, p.rs_field_name))
if not next((cp for cp in call_params
if cp[0] == maskfield.ffi_index), None):
call_params.append((maskfield.ffi_index, "%s_mask as %s" %
(p.rs_field_name, maskfield.ffi_field_type)))
call_params.append((p.ffi_index, '%s_ptr as %s' %
(p.rs_field_name, ffi_rq_type)))
elif p.rs_is_slice:
if p.type.member.rs_type == 'c_char':
rs_typestr = '&str'
let_lines.append('let %s = %s.as_bytes();' %
(p.rs_field_name, p.rs_field_name))
elif p.type.member.rs_type == 'c_void':
rs_typestr = '&[%s]' % p.rs_template_let
else:
rs_typestr = '&[%s]' % rs_typestr
if p.rs_lenfield:
lenfield = p.rs_lenfield
if not next((cp for cp in call_params
if cp[0] == lenfield.ffi_index), None):
let_lines.append('let %s_len = %s.len();' %
(p.rs_field_name, p.rs_field_name))
call_params.append((lenfield.ffi_index,
"%s_len as %s" %
(p.rs_field_name, lenfield.ffi_field_type)))
let_lines.append('let %s_ptr = %s.as_ptr();' %
(p.rs_field_name, p.rs_field_name))
call_params.append((p.ffi_index, '%s_ptr as %s' %
(p.rs_field_name, ffi_rq_type)))
elif p.type.is_container and p.ffi_need_pointer:
rs_typestr = 'std::option::Option<%s>' % rs_typestr
let_lines.append('let %s_ptr = match %s {' % (p.rs_field_name,
p.rs_field_name))
let_lines.append(' Some(p) => p.ptr as %s,' %
ffi_rq_type)
let_lines.append(' None => std::ptr::null()')
let_lines.append('};')
call_params.append((p.ffi_index, '%s_ptr' % p.rs_field_name))
elif p.type.is_container and not p.type.rs_is_pod:
call_params.append((p.ffi_index, '*(%s.ptr)' %
p.rs_field_name))
elif p.type.rs_is_pod:
call_params.append((p.ffi_index, '%s.base' %
p.rs_field_name))
else:
call_params.append((p.ffi_index,
'%s as %s' % (p.rs_field_name, ffi_rq_type)))
spacing = ' ' * (maxnamelen-len(p.rs_field_name))
eol = ',' if i < (len(self.rs_params)-1) else ')'
_r('%s%s%s: %s%s', func_spacing, p.rs_field_name,
spacing, rs_typestr, eol)
_r(" -> %s<'a> {", self.rs_cookie_type)
with _r.indent_block():
_r('unsafe {')
with _r.indent_block():
for l in let_lines:
_r(l)
call_start = 'let cookie = %s(' % ffi_func_name
eol = ',' if len(call_params) else ');'
spacing = ' ' * len(call_start)
_r('%sc.get_raw_conn()%s', call_start, eol)
call_params.sort(key=lambda x: x[0])
for (i, (ffi_ind, p)) in enumerate(call_params):
eol = ',' if i < (len(call_params)-1) else ');'
_r('%s%s%s // %d', spacing, p, eol, ffi_ind)
_r("%s {", self.rs_cookie_type)
_r(" cookie: cookie,")
_r(" conn: c,")
_r(" checked: %s", 'true' if checked else 'false')
_r("}")
_r('}')
_r('}')
def _opcode(nametup, opcode):
optype = 'u8' if int(opcode) >= 0 else 'i8'
ffi_name = _ffi_const_name(nametup)
_f.section(0)
_f('')
_f('pub const %s: %s = %s;', ffi_name, optype, opcode)
rs_name = _rs_const_name(nametup)
_r.section(1)
_r('')
_r('pub const %s: %s = %s;', rs_name, optype, opcode)
def _cookie(request):
_f.section(0)
_f('')
_f('#[derive(Copy, Clone)]')
_f('#[repr(C)]')
_f('pub struct %s {', request.ffi_cookie_type)
_f(' sequence: c_uint')
_f('}')
_r.section(1)
_r("")
_r("pub type %s<'a> = base::Cookie<'a, %s>;",
request.rs_cookie_type, request.ffi_cookie_type)
cookie = request.rs_cookie_type
reply = request.rs_reply_type
func = request.ffi_reply_fn
_r.section(1)
_r('')
_r("impl<'a> %s<'a> {", cookie)
with _r.indent_block():
_r("pub fn get_reply(&self) -> Result<%s, base::GenericError> {", reply)
with _r.indent_block():
_r('unsafe {')
with _r.indent_block():
_r("if self.checked {")
_r(" let mut err: *mut xcb_generic_error_t = "
+ "std::ptr::null_mut();")
_r(" let reply = %s {", reply)
_r(" ptr: %s (self.conn.get_raw_conn(), self.cookie, &mut err)", func)
_r(" };")
_r(" if err.is_null() { Ok (reply) }")
_r(" else { Err(base::GenericError { ptr: err }) }")
_r("} else {")
_r(" Ok( %s {", reply)
_r(" ptr: %s (self.conn.get_raw_conn(), self.cookie, ", func)
_r(" std::ptr::null_mut())")
_r(" })")
_r("}")
_r('}')
_r('}')
_r('}')
def _must_pack_event(event, nametup):
must_pack = False
if (hasattr(event, 'is_ge_event')
and event.is_ge_event
and event.name == nametup):
event_size = 0
for field in event.fields:
if field.type.size != None and field.type.nmemb != None:
event_size += field.type.size * field.type.nmemb
if event_size == 32:
full_sequence = Field(tcard32,
tcard32.name, 'full_sequence',
False, True, True)
idx = event.fields.index(field)
event.fields.insert(idx + 1, full_sequence)
must_pack = any(f.type.size == 8 and f.type.is_simple
for f in event.fields[(idx+1):])
break
return must_pack
def _handle_switch(typeobj, nametup):
if typeobj.is_switch and typeobj.ffi_type not in finished_switch:
finished_switch.append(typeobj.ffi_type)
for bitcase in typeobj.bitcases:
fname = _symbol(bitcase.field_name)
bitcase.ffi_field_name = fname
bitcase.rs_field_name = fname
bitcase.nametup = (bitcase.field_type if bitcase.type.has_name
else nametup)
_ffi_type_setup(bitcase.type, bitcase.nametup, ())
_rs_type_setup(bitcase.type, bitcase.nametup, ())
_set_type_lifetime(typeobj, True)
_ffi_struct(typeobj)
_rs_struct(typeobj)
for bitcase in typeobj.bitcases:
_ffi_accessors(bitcase.type, bitcase.nametup)
if typeobj.is_container:
for f in typeobj.fields:
_prepare_doc(f.type)
_handle_switch(f.type, f.field_type)
def rs_simple(simple, nametup):
global current_handler
current_handler = ('simple: ', nametup)
_prepare_doc(simple)
simple.has_lifetime = False
_ffi_type_setup(simple, nametup)
_f.section(0)
assert len(simple.name) == 1
_f('')
_write_doc_brief_desc(_f, simple.doc)
_f('pub type %s = %s;', simple.ffi_type, simple.name[0])
_ffi_iterator(simple, nametup)
_rs_type_setup(simple, nametup)
_r.section(0)
_r('')
_write_doc_brief_desc(_r, simple.doc)
_r('pub type %s = %s;', simple.rs_type, simple.ffi_type)
def rs_enum(typeobj, nametup):
global current_handler
current_handler = ('enum: ', nametup)
_prepare_doc(typeobj)
ecg = EnumCodegen(nametup, typeobj.doc)
val = -1
for (enam, eval) in typeobj.values:
val = int(eval) if eval != '' else val+1
ecg.add_discriminant(enam, val)
ecg.write_ffi()
ecg.write_rs()
def rs_struct(struct, nametup):
global current_handler
current_handler = ('struct: ', nametup)
_prepare_doc(struct)
struct.has_lifetime = True
_ffi_type_setup(struct, nametup)
_rs_type_setup(struct, nametup)
_handle_switch(struct, nametup)
_set_type_lifetime(struct, struct.has_lifetime)
_ffi_struct(struct)
_ffi_accessors(struct, nametup)
_ffi_iterator(struct, nametup)
_rs_struct(struct)
_rs_accessors(struct)
_rs_iterator(struct)
def rs_union(union, nametup):
global current_handler
current_handler = ('union: ', nametup)
_prepare_doc(union)
union.has_lifetime = False
_ffi_type_setup(union, nametup)
_rs_type_setup(union, nametup)
biggest = 1
most_aligned = 1
ptr_size = 8 if sys.maxsize > 2**32 else 4
for field in union.fields:
fs = ptr_size
fa = ptr_size
if field.type.size:
fs = field.type.size
fa = field.type.size
if field.type.nmemb:
fs = fa * field.type.nmemb
biggest = max(biggest, fs)
most_aligned = max(most_aligned, fa)
assert biggest >= most_aligned
num_aligned = int(biggest / most_aligned)
if biggest % most_aligned:
num_aligned += 1
num_bytes = num_aligned * most_aligned
union.union_num_bytes = num_bytes
_f.section(0)
_f('')
_write_doc_brief_desc(_f, union.doc)
_f('// union')
_f('#[repr(C)]')
_f('pub struct %s {', union.ffi_type)
_f(' pub data: [u8; %d]', num_bytes)
_f('}')
_f('')
_f('impl Copy for %s {}', union.ffi_type)
_f('impl Clone for %s {', union.ffi_type)
_f(' fn clone(&self) -> %s { *self }', union.ffi_type)
_f('}')
_ffi_iterator(union, nametup)
_r.section(1)
_r('')
_r('pub type %s = %s;', union.rs_type, union.ffi_type)
_rs_accessors(union)
_rs_iterator(union)
def rs_request(request, nametup):
global current_handler
current_handler = ('request: ', nametup)
_prepare_doc(request)
request.has_lifetime = False
_ffi_type_setup(request, nametup, ('request',))
_rs_type_setup(request, nametup, ('request',))
_handle_switch(request, nametup)
_set_type_lifetime(request, request.has_lifetime)
rcg = RequestCodegen(request)
_opcode(nametup, request.opcode)
_ffi_struct(request)
if request.reply:
_prepare_doc(request.reply)
request.reply.request = request
request.reply.has_lifetime = False
_cookie(request)
_ffi_type_setup(request.reply, nametup, ('reply',))
_rs_type_setup(request.reply, nametup, ('reply',))
_handle_switch(request.reply, nametup)
_set_type_lifetime(request.reply, request.reply.has_lifetime)
_ffi_struct(request.reply)
_ffi_accessors(request.reply, nametup + ('reply',))
_ffi_reply(request)
if _ffi_reply_has_fds(request.reply):
_ffi_reply_fds(request, nametup)
_rs_reply(request)
_rs_reply_accessors(request.reply)
rcg.write_ffi_rs(True, False)
rcg.write_ffi_rs(False, False)
if request.ffi_need_aux:
rcg.write_ffi_rs(True, True)
rcg.write_ffi_rs(False, True)
def rs_event(event, nametup):
global current_handler
current_handler = ('event: ', nametup)
must_pack = _must_pack_event(event, nametup)
_prepare_doc(event)
if must_pack:
print('event ', nametup, ' is packed')
event.has_lifetime = False
_ffi_type_setup(event, nametup, ('event',))
_rs_type_setup(event, nametup, ('event',))
_set_type_lifetime(event, event.has_lifetime)
_opcode(nametup, event.opcodes[nametup])
_r.section(1)
_r('')
_write_doc_brief_desc(_r, event.doc)
_r('pub type %s = base::Event<%s>;', event.rs_type, event.ffi_type)
if event.name == nametup:
_ffi_struct(event, must_pack)
accessor_fields = []
for f in event.fields:
if not f.visible: continue
accessor_fields.append(f)
if f.type.is_list or f.type.is_switch or f.type.is_bitcase:
try:
accessor_fields.remove(f.type.expr.lenfield)
except:
pass
new_params = []
if len(event.opcodes) > 1:
new_params.append('response_type: u8')
_r.section(1)
_r('')
_r('impl %s {', event.rs_type)
with _r.indent_block():
for f in accessor_fields:
for fd in event.doc.fields[f.field_name]:
_r('/// %s', fd)
_rs_accessor(event, f, True)
rs_ftype = f.rs_field_type
if f.has_subscript:
rs_ftype = "[%s; %d]" % (rs_ftype, f.type.nmemb)
new_params.append("%s: %s" % (f.rs_field_name, rs_ftype))
_r('/// Constructs a new %s', event.rs_type)
if len(event.opcodes) > 1:
_r('/// `response_type` must be set to one of:')
for opname in event.opcodes:
_r('/// - `%s`', _rs_const_name(opname))
else:
_r('/// `response_type` will be set automatically to %s',
_rs_const_name(nametup))
fn_start = "pub fn new("
fn_space = ' ' * len(fn_start)
p = new_params[0] if len(new_params) else ''
eol = ',' if len(new_params)>1 else ')'
_r('%s%s%s', fn_start, p, eol)
for (i, p) in enumerate(new_params[1:]):
eol = ',' if i != len(new_params)-2 else ')'
_r("%s%s%s", fn_space, p, eol)
_r(' -> %s {', event.rs_type)
with _r.indent_block():
_r('unsafe {')
with _r.indent_block():
_r('let raw = libc::malloc(32 as usize) as *mut %s;',
event.ffi_type)
if len(event.opcodes) > 1:
orlist = ' ||\n '.join(
[('response_type == %s' % _rs_const_name(opname))
for opname in event.opcodes])
_r('assert!(%s,', orlist)
_r(' "wrong response_type supplied to %s::new");',
event.rs_type)
_r('(*raw).response_type = response_type;')
else:
_r('(*raw).response_type = %s;', _rs_const_name(nametup))
for f in event.fields:
if not f.visible: continue
if f.type.is_container and not f.type.is_union \
and not f.type.rs_is_pod:
_r('(*raw).%s = *%s.ptr;',
f.ffi_field_name, f.rs_field_name)
elif f.type.rs_is_pod:
_r('(*raw).%s = %s.base;', f.ffi_field_name,
f.rs_field_name)
else:
assignment = f.rs_field_name
if f.rs_field_type == 'bool':
assignment = ('if %s { 1 } else { 0 }' %
f.rs_field_name)
_r('(*raw).%s = %s;', f.ffi_field_name, assignment)
_r('%s {', event.rs_type)
_r(' ptr: raw')
_r('}')
_r('}')
_r('}')
_r('}')
else:
_f.section(0)
_f('')
_f('pub type %s = %s;', _ffi_type_name(nametup+('event',)),
_ffi_type_name(event.name+('event',)))
def rs_error(error, nametup):
global current_handler
current_handler = ('error: ', nametup)
_prepare_doc(error)
_ffi_type_setup(error, nametup, ('error',))
_opcode(nametup, error.opcodes[nametup])
if error.name == nametup:
_ffi_struct(error)
else:
_f.section(0)
_f('')
_f('pub type %s = %s;', _ffi_type_name(nametup+('error',)),
_ffi_type_name(error.name+('error',)))
_rs_type_setup(error, nametup, ('error',))
_r.section(0)
_r('')
_r('pub struct %s {', error.rs_type)
_r(' pub base: base::Error<%s>', error.ffi_type)
_r('}')
def usage(program):
print('Usage: {} -o SRCDIR file.xml', program, file=sys.stderr)
if __name__ == '__main__':
from optparse import OptionParser
parser = OptionParser(usage="Usage: %prog -o SRCDIR file.xml")
parser.add_option('-o', '--output', dest='srcdir', metavar='SRCDIR',
help='specifies rust src dir where to generate files')
(options, args) = parser.parse_args(sys.argv)
if options.srcdir == None:
parser.error('-o SRCDIR is mandatory')
if not os.path.isdir(options.srcdir):
parser.error('-o SRCDIR must be a directory')
if len(args) < 2:
parser.error('input XML file must be supplied')
output = { 'open' : rs_open,
'close' : rs_close,
'simple' : rs_simple,
'enum' : rs_enum,
'struct' : rs_struct,
'union' : rs_union,
'request' : rs_request,
'event' : rs_event,
'error' : rs_error }
try:
from xcbgen.state import Module
from xcbgen.xtypes import *
except ImportError:
print('failed to load xcbgen', file=sys.stderr)
raise
module = Module(args[1], output)
module.rs_srcdir = options.srcdir
module.register()
module.resolve()
try:
module.generate()
except:
print('error occured in handler: ', current_handler, file=sys.stderr)
raise