#tokio #sync #async #sgr

synca

编写异步代码,synca将创建一个同步版本

9个版本 (4个破坏性更新)

0.5.3 2024年1月29日
0.5.2 2024年1月29日
0.4.1 2024年1月26日
0.3.0 2024年1月14日
0.1.0 2024年1月13日

#1438过程宏

每月22次 下载
pg_sgr_from_row 中使用

MIT/Apache

43KB
1K SLoC

SyncA

SyncA是一个用于创建同时具有同步和异步版本的crate的框架。

文档

动机

当我们编写一个库时,我们无法控制我们的代码将被使用的环境。

这通常导致只有同步版本,或者两个不同的crate。第一个解决方案的问题很明显,而第二个则违反了DRY原则

SyncA通过创建模块的副本来解决此问题。

概念

将synca宏属性应用于要复制的模块。作为参数,它接受基于模板应创建的模块。

在模块体中,可以描述代码修饰符。

代码修饰符

  • sync - 将模块代码转换为同步版本
  • replace - 替换类型和属性

示例

#[synca::synca(
  #[cfg(feature = "tokio")]
  pub mod tokio { },
  #[cfg(feature = "sync")]
  pub mod sync { 
    sync!();
    replace!(
      tokio_postgres::Client => postgres::Client,
      tokio_postgres::Error => postgres::Error,
      tokio_postgres::NoTls => postgres::NoTls,
      #[tokio::test] => #[test]
    );
  }
)] 
mod my_mod { 
  struct MyStruct {
    client: tokio_postgres::Client
  } 
  
  pub async fn get_name(client: &mut tokio_postgres::Client) -> String {
    let row = self.client.query_one("SQL", &[]).await.unwrap();

    row.get("name")
  }

  #[cfg(test)]
  mod tests {
    use super::get_name;

    #[tokio::test]
    pub async fn get_name_test() {
      assert_eq!(get_name(&mut client()).await, "My name");
    }

    fn client() -> tokio_postgres::Client { 
      #[synca::cfg(tokio)]
      let (client, connection) = tokio_postgres::connect("CONNECTION_STRING", tokio_postgres::NoTls).await?;
      #[synca::cfg(tokio)]
      tokio::spawn(async move {
        if let Err(e) = connection.await {
          eprintln!("connection error: {}", e);
        }
      });

      #[synca::cfg(sync)]
      let client = postgres::Client::connect(&conn_str, postgres::NoTls)?;

      client
    }
  }
}

生成的代码

#[cfg(feature = "tokio")]
pub mod tokio { 
  struct MyStruct {
    client: tokio_postgres::Client
  } 
  
  pub async fn get_name(client: &mut tokio_postgres::Client) -> String {
    let row = self.client.query_one("SQL", &[]).await.unwrap();

    row.get("name")
  }

  #[cfg(test)]
  mod tests {
    use super::get_name;

    #[tokio::test]
    pub async fn get_name_test() {
      assert_eq!(get_name(&mut client()).await, "My name");
    }

    fn client() -> tokio_postgres::Client { 
      let (client, connection) = tokio_postgres::connect("CONNECTION_STRING", tokio_postgres::NoTls).await?;
      tokio::spawn(async move {
        if let Err(e) = connection.await {
          eprintln!("connection error: {}", e);
        }
      });

      #[сfg(all(feature = "tokio", not(feature = "tokio")))]
      let client = postgres::Client::connect(&conn_str, postgres::NoTls)?;

      client
    }
  }
}

#[cfg(feature = "sync")]
mod sync { 
  struct MyStruct {
    client: postgres::Client
  } 
  
  pub fn get_name(client: &mut postgres::Client) -> String {
    let row = self.client.query_one("SQL", &[]).unwrap();

    row.get("name")
  }

  #[cfg(test)]
  mod tests {
    use super::get_name;

    #[test]
    pub async fn get_name_test() {
      assert_eq!(get_name(&mut client()), "My name");
    }

    fn client() -> postgres::Client {  
      #[сfg(all(feature = "tokio", not(feature = "tokio")))]
      let (client, connection) = tokio_postgres::connect("CONNECTION_STRING", tokio_postgres::NoTls).await?;
      #[сfg(all(feature = "tokio", not(feature = "tokio")))]
      tokio::spawn(async move {
        if let Err(e) = connection.await {
          eprintln!("connection error: {}", e);
        }
      });

      let client = postgres::Client::connect(&conn_str, postgres::NoTls)?;

      client
    }
  }
}

依赖关系

~260–700KB
~17K SLoC