Mercurial > lbo > hg > async-google-apis
changeset 2:c7e2e5de7401
Make struct generation work
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Sat, 17 Oct 2020 10:36:44 +0200 |
parents | d967aac4e997 |
children | 09ee80214be1 |
files | .hgignore generate/drivev3.json generate/generate.py manual_demo/src/main.rs manual_demo/tokencache.json |
diffstat | 5 files changed, 186 insertions(+), 42 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Fri Oct 16 22:31:04 2020 +0200 +++ b/.hgignore Sat Oct 17 10:36:44 2020 +0200 @@ -1,2 +1,3 @@ .txt +.json target/
--- a/generate/drivev3.json Fri Oct 16 22:31:04 2020 +0200 +++ b/generate/drivev3.json Sat Oct 17 10:36:44 2020 +0200 @@ -2299,6 +2299,7 @@ }, "teamDriveThemes": { "description": "Deprecated - use driveThemes instead.", + // [ { backgroundImageLink: ..., colorRgb: ..., ...} ] "items": { "properties": { "backgroundImageLink": {
--- a/generate/generate.py Fri Oct 16 22:31:04 2020 +0200 +++ b/generate/generate.py Sat Oct 17 10:36:44 2020 +0200 @@ -5,54 +5,109 @@ import json import requests +from os import path + ResourceStructTmpl = ''' -pub struct {name} {{ - {{#fields}} - {{name}}: {{typ}}, - {{/fields}} -}} +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct {{name}} { +{{#fields}} + {{#comment}} + // {{comment}} + {{/comment}} + {{{attr}}} + {{name}}: {{{typ}}}, +{{/fields}} +} ''' -def json_type_to_rust_field(prop): - if prop is None: - return '' - print(prop) - if 'type' in prop: - jt = prop['type'] - else: - jt = 'object' +def capitalize_first(name): + return name[0].upper() + name[1:] + +def snake_case(name): + def r(c): + if c.islower(): + return c + return '_'+c.lower() + return ''.join([r(c) for c in name]) - if jt == 'string': - if 'format' in prop: - if prop['format'] in ['int64', 'int32']: - return 'i64' - if prop['format'] == 'date-time': - return 'Time' - if prop['format'] in ['float', 'double']: - return 'float64' - if prop['format'] == 'byte': - return 'Vec<u8>' - return 'String' - if jt == 'boolean': - return 'bool' - if jt == 'array': - inner = prop['items'] - inner_type = json_type_to_rust_field(inner) - return 'Vec<' + inner_type + '>' - if jt == 'object': - if 'additionalProperties' in prop: - inner = prop.get('additionalProperties', None) - inner_type = json_type_to_rust_field(inner) - return 'HashMap<String,'+inner_type+'>' - else: - for subpropname, subprop in prop.items(): - pass +def type_of_property(name, prop): + typ = '' + comment = '' + structs = [] + try: + if '$ref' in prop: + return prop['$ref'], structs + if 'type' in prop and prop['type'] == 'object': + if 'properties' in prop: + typ = name + struct = {'name': name, 'fields': []} + for pn, pp in prop['properties'].items(): + subtyp, substructs = type_of_property(name+capitalize_first(pn), pp) + if type(subtyp) is tuple: + subtyp, comment = subtyp + else: + comment = None + struct['fields'].append({'name': snake_case(pn), 'attr': '#[serde(rename = "{}")]'.format(pn), + 'typ': subtyp, 'comment': comment}) + structs.extend(substructs) + structs.append(struct) + return typ, structs + if 'additionalProperties' in prop: + field, substructs = type_of_property(name, prop['additionalProperties']) + structs.extend(substructs) + if type(field) is tuple: + typ = field[0] + else: + typ = field + print(typ) + return 'HashMap<String,' + typ + '>', structs + if prop['type'] == 'array': + typ, substructs = type_of_property(name, prop['items']) + if type(typ) is tuple: + typ = typ[0] + return 'Vec<' + typ + '>', structs+substructs + if prop['type'] == 'string': + if 'format' in prop: + if prop['format'] == 'int64': + return ('String', 'i64'), structs + if prop['format'] == 'int32': + return ('String', 'i32'), structs + if prop['format'] == 'double': + return ('String', 'f64'), structs + if prop['format'] == 'float': + return ('String', 'f32'), structs + if prop['format'] == 'date-time': + return 'Time', structs + return 'String', structs + if prop['type'] == 'boolean': + return 'bool', structs + if prop['type'] in ('number', 'integer'): + if prop['format'] == 'float': + return 'f32', structs + if prop['format'] == 'double': + return 'f64', structs + if prop['format'] == 'int32': + return 'i32', structs + if prop['format'] == 'int64': + return 'i64', structs + raise Exception('unimplemented!', name, prop) + except KeyError as e: + print(name, prop) + print(e) + raise e def generate_structs(discdoc): schemas = discdoc['schemas'] + structs = [] for name, desc in schemas.items(): - for propname, prop in desc['properties'].items(): - print(propname, '=>', json_type_to_rust_field(prop)) + typ, substructs = type_of_property(name, desc) + structs.extend(substructs) + + modname = (discdoc['id']+'_types').replace(':', '_') + with open(path.join('gen', modname+'.rs'), 'w') as f: + f.write('use serde::{Deserialize, Serialize};') + for s in structs: + f.write(chevron.render(ResourceStructTmpl, s)) def fetch_discovery_base(url, apis):
--- a/manual_demo/src/main.rs Fri Oct 16 22:31:04 2020 +0200 +++ b/manual_demo/src/main.rs Sat Oct 17 10:36:44 2020 +0200 @@ -4,10 +4,97 @@ use std::string::String; use std::str::FromStr; +use std::collections::HashMap; + use hyper::Uri; use hyper_rustls::HttpsConnector; use serde_json::Value; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct AboutDriveThemes { + #[serde(rename = "backgroundImageLink")] + background_image_link: String, + #[serde(rename = "colorRgb")] + color_rgb: String, + #[serde(rename = "id")] + id: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct AboutStorageQuota { + // i64 + #[serde(rename = "limit")] + limit: String, + // i64 + #[serde(rename = "usage")] + usage: String, + // i64 + #[serde(rename = "usageInDrive")] + usage_in_drive: String, + // i64 + #[serde(rename = "usageInDriveTrash")] + usage_in_drive_trash: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct AboutTeamDriveThemes { + #[serde(rename = "backgroundImageLink")] + background_image_link: String, + #[serde(rename = "colorRgb")] + color_rgb: String, + #[serde(rename = "id")] + id: String, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct About { + #[serde(rename = "appInstalled")] + app_installed: bool, + #[serde(rename = "canCreateDrives")] + can_create_drives: bool, + #[serde(rename = "canCreateTeamDrives")] + can_create_team_drives: bool, + #[serde(rename = "driveThemes")] + drive_themes: Vec<AboutDriveThemes>, + #[serde(rename = "exportFormats")] + export_formats: HashMap<String,Vec<String>>, + #[serde(rename = "folderColorPalette")] + folder_color_palette: Vec<String>, + #[serde(rename = "importFormats")] + import_formats: HashMap<String,Vec<String>>, + #[serde(rename = "kind")] + kind: String, + #[serde(rename = "maxImportSizes")] + max_import_sizes: HashMap<String,String>, + // i64 + #[serde(rename = "maxUploadSize")] + max_upload_size: String, + #[serde(rename = "storageQuota")] + storage_quota: AboutStorageQuota, + #[serde(rename = "teamDriveThemes")] + team_drive_themes: Vec<AboutTeamDriveThemes>, + #[serde(rename = "user")] + user: User, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct User { + #[serde(rename = "displayName")] + display_name: String, + #[serde(rename = "emailAddress")] + email_address: String, + #[serde(rename = "kind")] + kind: String, + #[serde(rename = "me")] + me: bool, + #[serde(rename = "permissionId")] + permission_id: String, + #[serde(rename = "photoLink")] + photo_link: String, +} + type TlsConnr = HttpsConnector<hyper::client::HttpConnector>; type TlsClient = hyper::Client<TlsConnr, hyper::Body>; @@ -27,7 +114,8 @@ let body = resp.into_body(); let body = hyper::body::to_bytes(body).await.unwrap(); let dec = String::from_utf8(body.to_vec()).unwrap(); - println!("{}", dec); + let about: About = serde_json::from_str(&dec).unwrap(); + println!("{:?}", about); } #[tokio::main]
--- a/manual_demo/tokencache.json Fri Oct 16 22:31:04 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -[{"scopes":["https://www.googleapis.com/auth/drive.file"],"token":{"access_token":"ya29.a0AfH6SMDxs3RY-1v6wPg8nTDYse51fTM6MjP1dxflS4fTH_HCfMdhm1V59wAvcPeC8xnPjPkTqyNg_r3rSodWu1fYlv2oby_v2cZZ1euk1-GFZ6lnwpLgjRxVF-WxW8aKs-vx3vuMao8gd-FvD8U0Io-QdVTsKL2eaIQ","refresh_token":"1//094GIedhCtiYACgYIARAAGAkSNwF-L9IrAsqDDGTQUboZfDDpJFcEPcwHedLVwpAnSapXphwVutQIFOPFrOc0fE43DJ-6qJ1hL0c","expires_at":"2020-10-16T20:05:45.667484422Z"}}] \ No newline at end of file