aliyun OSS Rust sdk 之导出数据到自定义类型

178 阅读2分钟

前言:aliyun-oss-client 是我的第一个 rust 项目,随着版本的迭代,见证了笔者的 rust 水平的渐渐提高。这些版本里,从刚开始的,不会使用指针,导致产生了大量的copy,到后来逐渐的开始用指针,引用,智能指针等,节省了大量的内存开销,减少了大量的copy,笔者感觉有些是值得记录一下的。

今天想跟大家介绍的是将 aliyun 接口返回的数据,转化为任意的 rust 类型的通用方式,在做这个 lib 的之前的版本中,此 lib 只能将数据导入到 lib 内部的自有结构体中,随着笔者对 rust 了解的逐渐深入,发现了更加通用的的方式,将数据导出到其他开发者希望的类型,也是可行的。

因为 aliyun 接口返回的类型只能是 xml 格式,rust 在解析 xml 方面,并没有比较符合人体工程学的库,所以笔者在很早之前是自己手动解析 xml 的,oss-rs/traits.rs at master · tu6ge/oss-rs (github.com)

其实这块解析功能,完全可以开放出来,供大家使用,现在就将它的用法,介绍给大家:

use aliyun_oss_client::traits::{RefineObject, RefineObjectList};
use thiserror::Error;

struct MyFile {
    key: String,
    #[allow(dead_code)]
    other: String,
}
impl RefineObject for MyFile {
    type Error = MyError;

    fn set_key(&mut self, key: &str) -> Result<(), Self::Error> {
        self.key = key.to_string();
        Ok(())
    }
}

#[derive(Default)]
struct MyBucket {
    name: String,
    files: Vec<MyFile>,
}

impl RefineObjectList<MyFile> for MyBucket {
    type Error = MyError;

    fn set_name(&mut self, name: &str) -> Result<(), Self::Error> {
        self.name = name.to_string();
        Ok(())
    }
    fn set_list(&mut self, list: Vec<MyFile>) -> Result<(), Self::Error> {
        self.files = list;
        Ok(())
    }
}

#[derive(Debug, Error)]
enum MyError {
    #[error(transparent)]
    QuickXml(#[from] quick_xml::Error),
}

fn get_with_xml() -> Result<(), MyError> {
    // 这是阿里云接口返回的原始数据
    let xml = r#"<?xml version="1.0" encoding="UTF-8"?>
        <ListBucketResult>
          <Name>foo_bucket</Name>
          <Prefix></Prefix>
          <MaxKeys>100</MaxKeys>
          <Delimiter></Delimiter>
          <IsTruncated>false</IsTruncated>
          <NextContinuationToken>CiphcHBzL1RhdXJpIFB1Ymxpc2ggQXBwXzAuMS42X3g2NF9lbi1VUy5tc2kQAA--</NextContinuationToken>
          <Contents>
            <Key>9AB932LY.jpeg</Key>
            <LastModified>2022-06-26T09:53:21.000Z</LastModified>
            <ETag>"F75A15996D0857B16FA31A3B16624C26"</ETag>
            <Type>Normal</Type>
            <Size>18027</Size>
            <StorageClass>Standard</StorageClass>
          </Contents>
          <KeyCount>3</KeyCount>
        </ListBucketResult>"#;

    // 除了设置Default 外,还可以做更多设置
    let mut bucket = MyBucket::default();

    // 利用闭包对 MyFile 做一下初始化设置
    let init_file = || MyFile {
        key: String::default(),
        other: "abc".to_string(),
    };

    bucket.from_xml(xml, init_file)?;

    assert!(bucket.name == "foo_bucket");
    assert!(bucket.files[0].key == "9AB932LY.jpeg");

    Ok(())
}

let res = get_with_xml();

if let Err(err) = res {
    eprintln!("{}", err);
}