synca 0.5.0

Write asynchronous code, and synca will create a synchronous version.
Documentation
# About

SyncA is a framework for creating crates with both synchronous and asynchronous versions.

# Docs

[SyncA Book](https://synca.sgr-team.dev)

# Motivation

When we write a library, we cannot control the environment in which our code will be used.

Often this leads to the fact that there is only a synchronous version, or two different crates.
If the problems of the first solution are obvious, then the second leads to a violation of the 
[DRY principle](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself).

SyncA solves this problem by hiding the asynchronous implementation behind a feature.

# Concept

One macro for everything.

The macro synca::synca generates 2 versions of code: async with attribute #[cfg(feature)] and 
sync with attribute #[cfg(not(feature))].

# Full example

```rust
/// # synca
/// 
/// The macro will create 2 versions of the my_mod
/// With the asynchrony feature enabled - asynchronous version, 
/// without it - synchronous.
#[synca::synca(feature = "async")]
mod my_mod { }

/// # Functions
/// 
/// The macro turns asynchronous functions into synchronous 
/// implementations - removing all the .await calls
#[synca::synca(feature = "async")]
impl MyStruct {
  pub async fn first_name(&mut self) -> String {
    let row = self.client.query_one("SQL", &[]).await.unwrap();

    row.get("name")
  }
}

/// # Types
/// 
/// synca supports type substitution 
/// The synchronous version will use type postgres::Client
#[synca::synca(
  feature = "async",
  tokio_postgres::Client => postgres::Client
)]
struct MyStruct {
  client: tokio_postgres::Client
} 

/// # Tests
/// 
/// synca support attributes substitution too.
/// This allows you to test not only the asynchronous version, but also the synchronous one
#[synca::synca(
  feature = "async",
  tokio_postgres::Client => postgres::Client,
  #[tokio::test] => #[test]
)]
mod tests {
  #[tokio::test]
  pub async fn my_test() {

  }
}

/// # Traits
///
/// synca also knows how to work with traits
#[synca::synca(
  feature = "async",
  tokio_postgres::Client => postgres::Client,
)]
pub trait MyTrait { 
  async fn get_name(client: &mut tokio_postgres::Client);
}

/// # Docs
/// 
/// synca also contains a documentation processor that allows to generate 
/// different documentation for the synchronous and asynchronous versions
/// 
/// [synca::sync]
/// It's sync doc
/// [/synca::sync]
/// [synca::async]
/// It's async doc
/// [/synca::async]
/// 
/// # Match
/// 
/// You can also use "synca::match" to replace part of a string.
/// 
/// Arguments 
/// - [synca::match]tokio_postgres|postgres[/synca::match]::Client - postgres client
#[synca::synca(
  feature = "async",
  tokio_postgres::Client => postgres::Client,
)]
pub async fn my_fn(client: &mut tokio_postgres::Client) { }

/// # Virtual attributes
/// 
/// - synca::ignore - ignore in code fold
/// - synca::sync_only - the code will only be available in the synchronous version
/// - synca::async_only - the code will only be available in the asynchronous version
#[synca::synca(
  feature = "async",
  tokio_postgres::Client => postgres::Client,
  #[tokio::test] => #[test],
)]
mod my_mod {
  #[tokio::test]
  async fn my_test() { 
    #[synca::ignore]
    assert_eq!(format!(".aw{}", "ait"), ".await");
  }

  #[test]
  #[synca::sync_only]
  fn sync_test() { 
  }

  #[test]
  #[synca::async_only]
  fn async_test() { 
  }
}
```