<p align="center">
<h1 align="center">yaLanTingLibs</h1>
<h6 align="center">C++20基础工具库集合，包括struct_pack, struct_json, struct_xml, struct_pb, easylog, coro_rpc, coro_http 和 async_simple </h6>
</p>
<p align="center">
<img alt="license" src="https://img.shields.io/github/license/alibaba/async_simple?style=flat-square">
<img alt="language" src="https://img.shields.io/github/languages/top/alibaba/yalantinglibs?style=flat-square">
<img alt="last commit" src="https://img.shields.io/github/last-commit/alibaba/async_simple?style=flat-square">
</p>

[English Version](../../en/guide/what_is_yalantinglibs.md)

yaLanTingLibs 是一个现代C++基础工具库的集合, 现在它包括 struct_pack, struct_json, struct_xml, struct_yaml, struct_pb, easylog, coro_rpc, coro_io, coro_http 和 async_simple, 目前我们正在开发并添加更多的新功能。

yaLanTingLibs 的目标: 为C++开发者提供高性能，极度易用的现代C++基础工具库, 帮助用户构建高性能的现代C++应用。

| 测试平台 (编译器版本)                            | 状态                                                                                                   |
|------------------------------------------------|----------------------------------------------------------------------------------------------------------|
| Ubuntu 22.04 (clang 14.0.0)                    | ![ubuntu-clang](https://github.com/alibaba/yalantinglibs/actions/workflows/ubuntu_clang.yml/badge.svg?branch=main) |
| Ubuntu 22.04 (gcc 11.2.0)                      | ![ubuntu-gcc](https://github.com/alibaba/yalantinglibs/actions/workflows/ubuntu_gcc.yml/badge.svg?branch=main)   |
| macOS Monterey 12 (AppleClang 14.0.0.14000029) | ![macos-clang](https://github.com/alibaba/yalantinglibs/actions/workflows/mac.yml/badge.svg?branch=main)         |
| Windows Server 2022 (MSVC 19.33.31630.0)       | ![win-msvc](https://github.com/alibaba/yalantinglibs/actions/workflows/windows.yml/badge.svg?branch=main)     |

# 快速开始

## 编译器要求

如果你的编译器只支持C++17，yalantinglibs 只会编译序列化库。(struct_*系列)

确保你的编译器版本不低于:
- clang6++ (libstdc++-8 以上)。
- g++9 或更高版本。
- msvc 14.20 或更高版本。



如果你的编译器支持C++20，yalantinglibs会编译全部库。

确保你的编译器版本不低于:
- clang11++ (libstdc++-8 以上)。
- g++10 或更高版本。
- msvc 14.29 或更高版本。

你也可以手动指定Cmake选项`-DENABLE_CPP_20=ON` 或 `-DENABLE_CPP_20=OFF`来控制。

## 安装&编译

Yalantinglibs 是一个head-only的库，这意味着你可以简单粗暴的直接将`./include/ylt`拷贝走。但是更推荐的做法还是用Cmake安装。

- 克隆仓库

```shell
git clone https://github.com/alibaba/yalantinglibs.git
```

- 构建，测试并安装

- 我们建议，最好在安装之前编译样例/压测程序并执行测试：

```shell
cmake ..
cmake --build . --config debug # 可以在末尾加上`-j 选项, 通过并行编译加速
ctest . # 执行测试
```

测试/样例/压测的可执行文件存储在路径`./build/output/`下。

- 你也可以跳过编译:

```shell
# 可以通过这些选项来跳过编译样例/压测/测试程序
cmake .. -DBUILD_EXAMPLES=OFF -DBUILD_BENCHMARK=OFF -DBUILD_UNIT_TESTS=OFF
cmake --build .
```

3. 安装

默认情况下会安装到系统默认的include路径，你也可以通过选项来自定义安装路径。

```shell
cmake --install . # --prefix ./user_defined_install_path 
```

4. 开始编程

- 使用CMAKE:

安装完成后，你可以直接拷贝并打开文件夹`src/*/examples`，然后执行以下命令：

```shell
mkdir build
cd build
cmake ..
cmake --build .
```

- 手动编译:

1. 将 `include/`加入到头文件包含路径中(如果已安装到系统默认路径，可跳过该步骤)
2. 将 `include/ylt/thirdparty` 加入到头文件包含路径中(如果已通过Cmake 选项 -DINSTALL_INDEPENDENT_THIRDPARTY=ON 安装了第三方依赖，可跳过该步骤)
3. 如果你使用了 `coro_` 开头的任何头文件, 在linux系统下需要添加选项 `-pthread` . 使用`g++`编译器时需要添加选项 `-fcoroutines`。
4. 全部搞定. 更多细节请参考 `example/cmakelist.txt`.

- 更多细节:
如需查看更多细节, 除了`example/cmakelist.txt`，你还可以参考 [here](https://github.com/alibaba/yalantinglibs/tree/main/CmakeLists.txt) and [there](https://github.com/alibaba/yalantinglibs/tree/main/cmake).

# 简介

## coro_rpc

coro是一个高度易用, head-only，基于协程的C++20高性能rpc框架库。在pipeline echo模式下单机每核心qps可达40万+。

你可以在几分钟之内就构建一个高性能的rpc服务端和客户端！

[简介](https://alibaba.github.io/yalantinglibs/zh/coro_rpc/coro_rpc_introduction.html)  

[API](https://alibaba.github.io/yalantinglibs/cn/html/group__coro__rpc.html)

[Purecpp 演讲稿](https://alibaba.github.io/yalantinglibs/resource/coro_rpc_introduction_purecpp_talk.pdf).

[Purecpp 会议视频](https://live.csdn.net/room/csdnlive1/bKFbKP7T)，从04:55:08开始。

### 快速开始

1. 定义一个普通函数作为rpc函数。

```cpp
// rpc_service.hpp
inline std::string_view echo(std::string_view str) { return str; }
```

2. 注册rpc函数并启动服务器

```cpp
#include "rpc_service.hpp"
#include <ylt/coro_rpc/coro_rpc_server.hpp>

int main() {
  coro_rpc_server server(/*thread_num =*/10, /*port =*/9000);
  server.register_handler<echo>(); // register function echo
  server.start(); // start the server & block
}
```

3. rpc客户端连接服务器并调用rpc函数

```cpp
#include "rpc_service.hpp"
#include <ylt/coro_rpc/coro_rpc_client.hpp>

Lazy<void> test_client() {
  coro_rpc_client client;
  co_await client.connect("localhost", /*port =*/"9000"); // connect to the server

  auto r = co_await client.call<echo>("hello coro_rpc"); // call remote function echo
  std::cout << r.result.value() << "\n"; //will print "hello coro_rpc"
}

int main() {
  syncAwait(test_client());
}
```
更多示例[请见](https://github.com/alibaba/yalantinglibs/tree/main/src/coro_rpc/examples).

## struct_pack

struct_pack是一个基于编译期反射，易用且高性能的序列化库，head-only。一行代码即可完成序列化/反序列化。性能远超protobuf等传统序列化库。

[简介与设计文档](https://alibaba.github.io/yalantinglibs/zh/struct_pack/struct_pack_intro.html)

[API文档](https://alibaba.github.io/yalantinglibs/doxygen_cn/html/group__struct__pack.html)

[(Slides) A Faster Serialization Library Based on Compile-time Reflection and C++20](https://alibaba.github.io/yalantinglibs/resource/A%20Faster%20Serialization%20Library%20Based%20on%20Compile-time%20Reflection%20and%20C++%2020.pdf) CppCon2022 的演讲稿。

[(Video)  A Faster Serialization Library Based on Compile-time Reflection and C++20](https://www.youtube.com/watch?v=myhB8ZlwOlE) CppCon2022 的演讲视频。

[(Slides) 基于编译期反射和模板元编程的序列化库：struct_pack简介](https://alibaba.github.io/yalantinglibs/resource/struct_pack_introduce_CN.pdf) Purecpp的演讲稿。

[(Video) 基于编译期反射和模板元编程的序列化库：struct_pack简介](https://live.csdn.net/room/csdnlive1/bKFbKP7T) Purecpp的演讲视频, 从 01:32:20 开始

### 快速开始
```cpp
// 定义一个C++结构体
struct person {
  int64_t id;
  std::string name;
  int age;
  double salary;
};
// 初始化对象
person person1{.id = 1, .name = "hello struct pack", .age = 20, .salary = 1024.42};

// 一行代码序列化
std::vector<char> buffer = struct_pack::serialize(person1);

// 一行代码反序列化
auto person2 = deserialize<person>(buffer);
```
更多示例[请见](https://alibaba.github.io/yalantinglibs/zh/struct_pack/struct_pack_intro.html#%E5%BA%8F%E5%88%97%E5%8C%96).

## struct_json
基于反射的json库，轻松实现结构体和json之间的映射。

### 快速开始
```cpp
#include "ylt/struct_json/json_reader.h"
#include "ylt/struct_json/json_writer.h"

struct person {
  std::string name;
  int age;
};
REFLECTION(person, name, age);

int main() {
  person p{.name = "tom", .age = 20};
  std::string str;
  struct_json::to_json(p, str); // {"name":"tom","age":20}

  person p1;
  struct_json::from_json(p1, str);
}
```

## struct_xml
基于反射的xml库，轻松实现结构体和xml之间的映射。

### quick example
```cpp
#include "struct_xml/xml_reader.h"
#include "struct_xml/xml_writer.h"

struct person {
  std::string name;
  int age;
};
REFLECTION(person, name, age);

void basic_usage() {
  std::string xml = R"(
<person>
    <name>tom</name>
    <age>20</age>
</person>
)";

  person p;
  bool r = struct_xml::from_xml(p, xml.data());
  assert(r);
  assert(p.name == "tom" && p.age == 20);

  std::string str;
  r = struct_xml::to_xml_pretty(p, str);
  assert(r);
  std::cout << str;
}
```

## coro_http

coro_http 是一个 C++20 的协程http(https)客户端, 支持: get/post, websocket, multipart file , chunked 和 ranges 请求。

### get/post
```cpp
#include "ylt/coro_http/coro_http_client.hpp"
using namespace ylt;

async_simple::coro::Lazy<void> get_post(coro_http_client &client) {
  std::string uri = "http://www.example.com";
  auto result = co_await client.async_get(uri);
  std::cout << result.status << "\n";
  
  result = co_await client.async_post(uri, "hello", req_content_type::string);
  std::cout << result.status << "\n";
}

int main() {
  coro_http_client client{};
  async_simple::coro::syncAwait(get_post(client));
}
```

### websocket
```cpp
async_simple::coro::Lazy<void> websocket(coro_http_client &client) {
  client.on_ws_close([](std::string_view reason) {
    std::cout << "web socket close " << reason << std::endl;
  });
  
  client.on_ws_msg([](resp_data data) {
    std::cout << data.resp_body << std::endl;
  });

  // connect to your websocket server.
  bool r = co_await client.async_connect("ws://example.com/ws");
  if (!r) {
    co_return;
  }

  co_await client.async_send_ws("hello websocket");
  co_await client.async_send_ws("test again", /*need_mask = */ false);
  co_await client.async_send_ws_close("ws close reason");
}
```

### 上传/下载
```cpp
async_simple::coro::Lazy<void> upload_files(coro_http_client &client) {
  std::string uri = "http://example.com";
  
  client.add_str_part("hello", "world");
  client.add_str_part("key", "value");
  client.add_file_part("test", "test.jpg");
  auto result = co_await client.async_upload(uri);
  std::cout << result.status << "\n";
  
  result = co_await client.async_upload(uri, "test", "test.jpg");
}

async_simple::coro::Lazy<void> download_files(coro_http_client &client) {
  // chunked download
  auto result = co_await client.async_download("http://example.com/test.jpg",
                                               "myfile.jpg");
  std::cout << result.status << "\n";
  
  // ranges download
  result = co_await client.async_download("http://example.com/test.txt",
                                               "myfile.txt", "1-10,11-16");
  std::cout << result.status << "\n";
}
```

## async_simple

async_simple是一个C++20协程库，提供各种轻量且易用的组件，帮助用户编写异步代码。
请见[async_simple](https://github.com/alibaba/async_simple)

# 其他

## CMAKE 选项

以下这些Cmake选项只适用于yalantinglibs自身的开发和安装。他们不会对你的项目造成影响，因为yalantinglibs是head-only的。

### 安装选项

|选项|默认值|
|----------|------------|
|INSTALL_THIRDPARTY|ON|
|INSTALL_INDEPENDENT_THIRDPARTY|OFF|

### ylt 开发选项

|选项|默认值|
|----------|------------|
|BUILD_EXAMPLES|ON|
|BUILD_BENCHMARK|ON|
|BUILD_UNIT_TESTS|ON|
|BUILD_*(BUILD_CORO_RPC, BUILD_STRUCT_PACK 等)|ON|
|COVERAGE_TEST|OFF|
|GENERATE_BENCHMARK_DATA|ON|
|CORO_RPC_USE_OTHER_RPC|ON|

### ylt 配置项

你可能也想在你的工程里启用这些配置项。你可以参考这些[cmake 代码](https://github.com/alibaba/yalantinglibs/tree/main/cmake/config.cmake)。

|选项|默认值|
|----------|------------|
|ENABLE_SSL|OFF|
|ENABLE_PMR|OFF|
|ENABLE_IO_URING|OFF|
|ENABLE_FILE_IO_URING|OFF|
|ENABLE_STRUCT_PACK_UNPORTABLE_TYPE|OFF|
|ENABLE_STRUCT_PACK_OPTIMIZE|OFF|

## 第三方依赖

默认情况下，ylt会把第三方依赖安装到`ylt/thirdparty`目录下，你需要将它添加到头文件包含路径中。

如果你不想让ylt安装第三方依赖，你可以使用选项：`-DINSTALL_THIRDPARTY=OFF`。

如果你想让ylt将第三方依赖直接独立安装到系统默认的包含路径中，你可以开启选项：`-DINSTALL_INDEPENDENT_THIRDPARTY=ON`。

以下是我们使用的第三方依赖（async_simple虽然也是ylt的一部分，但其首先开源，故计为一个独立的第三方依赖）

### coro_io

- [asio](https://think-async.com/Asio)
- [async_simple](https://github.com/alibaba/async_simple)
- [openssl](https://www.openssl.org/) (optional)

### coro_rpc

- [asio](https://think-async.com/Asio)
- [async_simple](https://github.com/alibaba/async_simple)
- [openssl](https://www.openssl.org/) (optional)

### coro_http

- [asio](https://think-async.com/Asio)
- [async_simple](https://github.com/alibaba/async_simple)
- [cinatra](https://github.com/qicosmos/cinatra)

### easylog

无依赖。

### struct_pack

无依赖。

### struct_json

- [iguana](https://github.com/qicosmos/iguana)

### struct_pb (optional)

- [protobuf](https://protobuf.dev/)

### struct_xml

- [iguana](https://github.com/qicosmos/iguana)

### struct_yaml

- [iguana](https://github.com/qicosmos/iguana)

## Benchmark

### coro_rpc

选项:

```bash
./benchmark_client # [线程数（默认为硬件线程数）] [每线程客户端数（默认为20）] [pipeline大小(默认为1，当设为1时相当于ping-pong模式)] [主机地址（默认为127.0.0.1）] [端口号（默认为9000）] [测试数据文件夹地址（默认为"./test_data/echo_test"] [测试秒数（默认为30）] [热身秒数（默认为5）]
```

## 如何生成文档

请见[生成网站](https://github.com/alibaba/yalantinglibs/blob/main/website/README.md)

## 如何贡献代码
1. 根据issue模板提交一个issue。
2. 在本地修改代码，通过测试并使用 `git-clang-format HEAD^` 格式化代码。
3. 创建一个Pull Request，填写模板中的内容。
4. 提交Pull Request，并选择审核者: (如： qicosmos, poor-circle, PikachuHyA).
5. 通过github的全平台测试，审核者完成审核，代码合入主线。

# 讨论组

钉钉群

<center>
<img src="../../public/img/yalantinglibs_ding_talk_group.png" alt="dingtalk" width="200" height="200" align="bottom" />
</center>

## 许可证

yaLanTingLibs 基于 Apache License (Version 2.0) 开发。
本产品包含了许多基于其他开源许可证的第三方组件。
你可以查看[NOTICE文件](https://github.com/alibaba/yalantinglibs/blob/main/NOTICE)来了解更多信息。