Mercurial > lbo > hg > async-google-apis
changeset 5:e0856ff450bb
Improve rust struct generation: Also generate parameters
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Sat, 17 Oct 2020 12:04:51 +0200 |
parents | 95fca1b07ef5 |
children | 4b27e65aeccc |
files | generate/generate.py manual_demo/src/main.rs |
diffstat | 2 files changed, 63 insertions(+), 113 deletions(-) [+] |
line wrap: on
line diff
--- a/generate/generate.py Sat Oct 17 10:56:24 2020 +0200 +++ b/generate/generate.py Sat Oct 17 12:04:51 2020 +0200 @@ -8,7 +8,7 @@ from os import path ResourceStructTmpl = ''' -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Default)] pub struct {{name}} { {{#fields}} {{#comment}} @@ -20,6 +20,9 @@ } ''' +def optionalize(name, optional=True): + return 'Option<{}>'.format(name) if optional else name + def replace_keywords(name): return { 'type': ('typ', 'type'), @@ -37,7 +40,7 @@ return ''.join([r(c) for c in name]) -def type_of_property(name, prop): +def type_of_property(name, prop, optional=True): """Translate a JSON schema type into Rust types. Arguments: @@ -57,14 +60,14 @@ structs = [] try: if '$ref' in prop: - return prop['$ref'], structs + return optionalize(prop['$ref'], optional), 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) + name + capitalize_first(pn), pp, optional=True) if type(subtyp) is tuple: subtyp, comment = subtyp else: @@ -88,59 +91,67 @@ }) structs.extend(substructs) structs.append(struct) - return typ, structs + return (optionalize(typ, optional), prop.get('description', '')), structs if 'additionalProperties' in prop: field, substructs = type_of_property( - name, prop['additionalProperties']) + name, prop['additionalProperties'], optional=False) structs.extend(substructs) if type(field) is tuple: typ = field[0] else: typ = field - print(typ) - return 'HashMap<String,' + typ + '>', structs + return (optionalize('HashMap<String,'+typ+'>', optional), prop.get('description', '')), structs if prop['type'] == 'array': - typ, substructs = type_of_property(name, prop['items']) + typ, substructs = type_of_property(name, prop['items'], optional=False) if type(typ) is tuple: typ = typ[0] - return 'Vec<' + typ + '>', structs + substructs + return (optionalize('Vec<'+typ+'>', optional), prop.get('description', '')), structs + substructs if prop['type'] == 'string': if 'format' in prop: if prop['format'] == 'int64': - return ('String', 'i64'), structs + return (optionalize('String', optional), 'i64: ' + prop.get('description', '')), structs if prop['format'] == 'int32': - return ('String', 'i32'), structs + return (optionalize('String', optional), 'i32: ' + prop.get('description', '')), structs if prop['format'] == 'double': - return ('String', 'f64'), structs + return (optionalize('String', optional), 'f64: ' + prop.get('description', '')), structs if prop['format'] == 'float': - return ('String', 'f32'), structs + return (optionalize('String', optional), 'f32: ' + prop.get('description', '')), structs if prop['format'] == 'date-time': - return 'DateTime<Utc>', structs - return 'String', structs + return (optionalize('DateTime<Utc>', optional), prop.get('description', '')), structs + return (optionalize('String', optional), prop.get('description', '')), structs if prop['type'] == 'boolean': - return 'bool', structs + return (optionalize('bool', optional), prop.get('description', '')), structs if prop['type'] in ('number', 'integer'): if prop['format'] == 'float': - return 'f32', structs + return (optionalize('f32', optional), prop.get('description', '')), structs if prop['format'] == 'double': - return 'f64', structs + return (optionalize('f64', optional), prop.get('description', '')), structs if prop['format'] == 'int32': - return 'i32', structs + return (optionalize('i32', optional), prop.get('description', '')), structs if prop['format'] == 'int64': - return 'i64', structs + return (optionalize('i64', optional), prop.get('description', '')), structs raise Exception('unimplemented!', name, prop) except KeyError as e: print(name, prop) print(e) raise e - def generate_structs(discdoc): schemas = discdoc['schemas'] + resources = discdoc['resources'] structs = [] for name, desc in schemas.items(): typ, substructs = type_of_property(name, desc) structs.extend(substructs) + for name, res in resources.items(): + for methodname, method in res['methods'].items(): + if 'parameters' not in method: + structs.append({'name': '{}{}Params'.format(capitalize_first(name) , capitalize_first(methodname)), 'fields': []}) + else: + params = method['parameters'] + typ = {'type': 'object', 'properties': params} + typ, substructs = type_of_property('{}{}Params'.format(capitalize_first(name), capitalize_first(methodname)), typ) + structs.extend(substructs) modname = (discdoc['id'] + '_types').replace(':', '_') with open(path.join('gen', modname + '.rs'), 'w') as f: @@ -150,6 +161,9 @@ 'use std::collections::HashMap;\n' ]) for s in structs: + for field in s['fields']: + if field.get('comment', None): + field['comment'] = field['comment'].replace('\n', ' ') f.write(chevron.render(ResourceStructTmpl, s))
--- a/manual_demo/src/main.rs Sat Oct 17 10:56:24 2020 +0200 +++ b/manual_demo/src/main.rs Sat Oct 17 12:04:51 2020 +0200 @@ -7,100 +7,15 @@ use yup_oauth2::InstalledFlowAuthenticator; use std::string::String; use std::str::FromStr; - -use std::collections::HashMap; +use std::path::Path; +use std::fs; 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>; +type Authenticator = yup_oauth2::authenticator::Authenticator<TlsConnr>; fn https_client() -> TlsClient { let conn = hyper_rustls::HttpsConnector::new(); @@ -108,7 +23,27 @@ cl } -async fn get_about(cl: &mut TlsClient, auth: &mut yup_oauth2::authenticator::Authenticator<TlsConnr>) { +async fn upload_file(cl: &mut TlsClient, auth: &mut Authenticator, f: &Path) { + let posturl = "https://www.googleapis.com/upload/drive/v3/files?uploadType=media"; + let tok = auth.token(&["https://www.googleapis.com/auth/drive.file"]).await.unwrap(); + let authtok = format!("&oauth_token={}&fields=*", tok.as_str()); + + let file = fs::OpenOptions::new().read(true).open(f).unwrap(); + let len = file.metadata().unwrap().len(); + + let body = hyper::Body::from(fs::read(&f).unwrap()); + let req = hyper::Request::post(posturl.to_string()+&authtok).header("Content-Length", format!("{}", len)) + .body(body).unwrap(); + let resp = cl.request(req).await.unwrap(); + + let body = resp.into_body(); + let body = hyper::body::to_bytes(body).await.unwrap(); + let dec = String::from_utf8(body.to_vec()).unwrap(); + let about: drive::File = serde_json::from_str(&dec).unwrap(); + println!("{:?}", about); +} + +async fn get_about(cl: &mut TlsClient, auth: &mut Authenticator) { let baseurl = "https://www.googleapis.com/drive/v3/"; let path = "about"; let tok = auth.token(&["https://www.googleapis.com/auth/drive.file"]).await.unwrap(); @@ -118,7 +53,7 @@ let body = resp.into_body(); let body = hyper::body::to_bytes(body).await.unwrap(); let dec = String::from_utf8(body.to_vec()).unwrap(); - let about: About = serde_json::from_str(&dec).unwrap(); + let about: drive::About = serde_json::from_str(&dec).unwrap(); println!("{:?}", about); } @@ -138,7 +73,8 @@ let mut cl = https_client(); - get_about(&mut cl, &mut auth).await; + //get_about(&mut cl, &mut auth).await; + upload_file(&mut cl, &mut auth, Path::new("pp.jpg")).await; match auth.token(scopes).await { Ok(token) => println!("The token is {:?}", token),